Introduction
PlusWorkflow plugins can serve dynamic http pages built with the Freemarker library. This page will introduce the basics of creating such views.
Freemarker Editor
Unfortunately, the Eclipse environment does not have a built-in Freemarker editor.Such an editor can be installed separately along with JBoss Tools.
More at: http://freemarker.org/editors.html
Basics
Freemarker is an alternative to JSP, which cannot be integrated into a plug-in mechanism for a number of reasons. Freemarker templates are created dynamically and do not require compilation into Java classes.
Pages are created dynamically by inserting object values from the model straight into the template. The model is completed with, for example, request attributes (HttpServletRequest) quite like JSP.
Completion of the model is usually done in the controller:
@Controller public class HelloController { // The result of these 2 methods will be the same @RequestMapping("/hello") public String sayHello(Model model){ model.addAttribute( "username", "World" ); return "hello"; // /views/hello.ftl } @RequestMapping("/hello2") public String sayHello(HttpServletRequest request){ request.setAttribute( "username", "World" ); return "hello"; // /views/hello.ftl } }
Template
<h1>Hello ${username}</h1>
Result
<h1>Hello World</h1>
Freemarker supports loops, if..else expressions, html escape, date formatting etc. It is recommended to read the documentation http://freemarker.org/docs/index.html
PluginRequestContext object
KEach rendered .ftl view has access to an additional PluginRequestContext object that facilitates the retrieval of translations, paths, etc:
<!-- Downloading plugin context path: /{contextPath}/plugin/{id}/ --> ${pluginContext.pluginContextPath} <!-- Get the relative address to the plugin context: /{contextPath}/plugin/{id}/hello --> ${pluginContext.getPluginContextUrl('hello')} <!-- Get plugin resource path: /{contextPath}/plugin/{id}/resources/{timestamp} --> ${pluginContext.pluginResourcesPath} <!-- Get the path to the plugin resource: /{contextPath}/plugin/{id}/resources/{timestamp}/hello.js --> ${pluginContext.getPluginResourcesUrl('hello.js')} <!-- Get contextPath: e.g. /PlusWorkflow --> ${pluginContext.contextPath} <!-- Get contextPath: e.g. /PlusWorkflow/Admin.do --> ${pluginContext.getContextUrl('Admin.do')} <!-- Get key translation without parameters --> ${pluginContext.getMessage('messagekey')} <!-- Get translation with parameters --> ${pluginContext.getMessage('messagekey', ['somearg'])}
Macro plugin.ftl
In addition, the plugin can import a macro that simplifies operations on the PluginRequestContext object.
<!-- Importing a macro --> <#import "/plugin.ftl" as plugin/> <!-- Get the relative address to the plugin context: /{contextPath}/plugin/{id}/hello --> <@plugin.url 'hello'/> <!-- Get the path to the plugin resource: /{contextPath}/plugin/{id}/resources/{timestamp}/hello.js --> <@plugin.resourceUrl 'hello.js'/> <!-- Get contextPath: e.g. /PlusWorkflow/Admin.do --> <@plugin.systemUrl 'Admin.do'/> <!-- PGet key translation without parameters --> <@plugin.message 'messagekey'/>
Using JspTagLib
Freemarker allows calls to JspTagLib (e.g. displaytag, jstl).
Nowadays, there should be no need to use taglibs. A better alternative to them, for example, is to use dynamic JavaScript components or move the logic to a controller.
There is no guarantee that the TagLib used will work smoothly.
<!-- Assigning the tagline "JSTL" to the variable "c" --> <#assign c=JspTaglibs["http://java.sun.com/jsp/jstl/core"] /> <!-- <c:import...> --> <@c.import charEncoding="UTF-8" url=someUrl />
<!-- Assigning the tagline "displaytag" to the variable "display" --> <#assign display=JspTaglibs["http://displaytag.sf.net"] /> <@display.table id="table" name="records" pagesize=20 partialList=true requestURI="someUrl"> <@display.column title=pluginContext.getMessage("Lp") class="small">${table_rowNum}</@display.column> <!-- ... --> </@display.table>
View decorators
Freemarker views generated by the plugin are decorated by default to match the style of the PlusWorkflow system.
By default, all requests that:
- are not Ajax requests (do not contain the X-Requested-With: XMLHTTPREQUEST header)
- the request decorator parameter is not present or has a value other than none
The following decorators are available in the system (we use the name as the value of the decorator parameter):
Name | Description | Url |
---|---|---|
system | Default decorator - enters the contents of the template into the body area of the page. The header, system menu, footer will be automatically generated. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=system |
| Empty decorator - contains all scripts and css styles. It does not contain any structure such as header or footer. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=empty |
plain | Simple decorator - contains only standard JavaScript scripts | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=plain |
none | No decorator. Only the contents of the template will be displayed. | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=none |
notlogged | Login page decorator to display information about invalid login | http://<serwer>:<port>/<system>/plugin/<wtyczka>/view?decorator=notlogged |