FreeMarker with Stripes
This document is intended primarily to help those already familiar with FreeMarker integrate Stripes and FreeMarker for development of an application. It is not intended as an introduction to FreeMarker - FreeMarker has excellent documentation of it's own.
Setting up FreeMarker
The first step is to download FreeMarker. It is strongly recommended to use version 2.3.8 or above of FreeMarker. FreeMarker 2.3.8 includes several additions to the JSP tag support in order to support the full range of JSP 2.0 tag library APIs. Since some Stripes tags depend on JSP 2.0 APIs, they will not work with earlier version of FreeMarker.
Once FreeMarker is downloaded expand the distribution and copy lib/freemarker.jar
into your web application classpath, probably at WEB-INF/lib/freemarker.jar
.
Next you will need to configure the FreeMarker servlet. The following is a minimal configuration that can be added to your web.xml. You may wish to consult FreeMarker's documentation on using FreeMarker with servlets for more details and configuration options.
<servlet> <servlet-name>Freemarker</servlet-name> <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class> <init-param> <param-name>TemplatePath</param-name> <param-value>/</param-value> </init-param> <init-param> <param-name>template_update_delay</param-name> <param-value>0</param-value> <!-- 0 is for dev only! Use higher value otherwise. --> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Freemarker</servlet-name> <url-pattern>*.ftl</url-pattern> </servlet-mapping>
Of course it is entirely possible to map the FreeMarker servlet to other extensions or url patterns, but for now we'll use *.ftl
as the mapping. Similarly the TemplatePath
specified tells FreeMarker that it should find the template files by looking in the web application file structure, starting at the root.
The last step in configuring FreeMarker is to ensure that the Stripes Filter filters requests that are made directly to FreeMarker templates. This step is optional, but highly recommended. If you never (and I mean never) allow navigation directly to FreeMarker templates (i.e. navigation is always through ActionBeans first and you always forward, never redirect to views) then this is not necessary.
<filter-mapping> <filter-name>StripesFilter</filter-name> <servlet-name>Freemarker</servlet-name> <dispatcher>REQUEST</dispatcher> </filter-mapping>
Using FreeMarker and Stripes
Once FreeMarker is installed and configured you can begin using it right away. The main part of Stripes that interacts heavily with the view tier is the tag library. Stripes does not provide an alternate macro library for use with FreeMarker, but thanks to FreeMarker's embedded lightweight JSP tag container, you can use the Stripes tag library with FreeMarker. To do this you'll need to add a single assign
statement at the top of your FreeMarker templates:
[#assign s=JspTaglibs["http://stripes.sourceforge.net/stripes.tld"]]
Since Stripes exposes the ActionBean as a request attribute, and FreeMarker makes all request attributes available in the template model, you can also reference ActionBean properties using FreeMarker's built in expression language - just like any other model object. Stripes does not use it's own expression language (when used with JSPs Stripes uses the JSP EL), so access to ActionBeans behaves exactly as you would expect in FreeMarker.
The Quickstart Example in FreeMarker
The following is a reworking of the Quick Start Guide's JSP into a FreeMarker template. The ActionBean itself is identical except for the replacement of "index.jsp" with "index.ftl".
[#ftl] [#assign s=JspTaglibs["http://stripes.sourceforge.net/stripes.tld"]] <html> <head> <title>My First Stripe</title> <style type="text/css"> input.error { background-color: yellow; } </style> </head> <body> <h1>Stripes Calculator - FTL</h1> Hi, I'm the Stripes Calculator. I can only do addition. Maybe, some day, a nice programmer will come along and teach me how to do other things? [@s.form action="/examples/quickstart/Calculator.action"] [@s.errors/] <table> <tr> <td>Number 1:</td> <td>[@s.text name="numberOne"/]</td> </tr> <tr> <td>Number 2:</td> <td>[@s.text name="numberTwo"/]</td> </tr> <tr> <td colspan="2"> [@s.submit name="addition" value="Add"/] [@s.submit name="division" value="Divide"/] </td> </tr> <tr> <td>Result:</td> <td>${(actionBean.result)!}</td> </tr> </table> [/@] </body> </html>
The first and most obvious change is that instead of using JSP syntax, the template uses FreeMarker's (newer) square bracket syntax for tags. The next change to note is the removal of the JSP taglig imports, and their replacement with the FreeMarker assign statement on line 2.
Stripes tags in JSP took the form of <stripes:tagname attr="value"/>
. As you can see here, this has effectively been search-and-replaced to the form [@s.tagname attr="value"
. The change of prefix from 'stripes' to 's' is arbitrary (both prefixes are valid for both template systems) but the 's' feels more in keeping with FreeMarker's preference for terseness.
The last significant change is the following line:
<td>${(actionBean.result)!}</td>
The expression is wrapped in parenthesis and has the '!' applied to it. This is done because the first time the template renders the actionBean
is null, and FreeMarker would otherwise through an exception. The '!' operator informs FreeMarker to ignore null values in the preceeding expression.
Gotchas
The following is a short list of problems that I, as a user familiar with JSP and unfamiliar with Freemarker, encountered while converting a small application from JSP to FreeMarker. These are not problems with FreeMarker per se, but for anyone familiar with JSP they are traps which are easy to fall in to.
1. Some Stripes tags have hyphens in their names. FreeMarker does not support this unless the tag names are quoted. So for example, to use the layout-render
tag you have to write [@s["layout-render"]]. To close this tag you must use the shorthand [/@]
.
2. FreeMarker is less forgiving of null values than JSP is. Therefore for any bean value you access through an expression (e.g. actionBean.user.name
) if the value may be null you will need to protect against this using one of FreeMarker's built in operators. E.g. actionBean.user.name!
would render as the empty String if null, and actionBean.user.name!'New User'
would render as 'New User'.
3. In FreeMarker it is a) not necessary and b) incorrect to quote non-String values. For example, in JSP we might write <stripes:text name="foo" value="${actionBean.user.dateOfBirth}"/>
and the value supplied to the Stripes tag would the be the exact value of the property - probably a java.util.Date
. In FreeMarker writing [@s.text name="foo" value="${actionBean.user.dateOfBirth}"/]
would result in the String value of the property being supplied to the tag! The correct syntax in FreeMarker is more concise: [@s.text name="foo" value=actionBean.user.dateOfBirth/]
.