Velocity and FreeMarker are two templating languages that can both be used as view technologies within Spring MVC applications. The languages are quite similar and serve similar needs and so are considered together in this section. For semantic and syntactic differences between the two languages, see the FreeMarker web site.
Your web application will need to include velocity-1.x.x.jar
or freemarker-2.x.jar
in order to work with
Velocity or FreeMarker respectively and commons-collections.jar
needs also to be
available for Velocity. Typically they are included in the
WEB-INF/lib
folder where they are guaranteed to be
found by a Java EE server and added to the classpath for your application.
It is of course assumed that you already have the spring.jar
in your 'WEB-INF/lib'
directory too! The latest
stable Velocity, FreeMarker and Commons Collections jars are supplied
with the Spring framework and can be copied from the relevant /lib/
sub-directories. If you make use of
Spring's 'dateToolAttribute' or 'numberToolAttribute' in your Velocity
views, you will also need to include the velocity-tools-generic-1.x.jar
A suitable configuration is initialized by adding the relevant
configurer bean definition to your '*-servlet.xml'
as shown below:
<!-- This bean sets up the Velocity environment for us based on a root path for templates. Optionally, a properties file can be specified for more control over the Velocity environment, but the defaults are pretty sane for file based template loading. --> <bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="resourceLoaderPath" value="/WEB-INF/velocity/"/> </bean> <!-- View resolvers can also be configured with ResourceBundles or XML files. If you need different view resolving based on Locale, you have to use the resource bundle resolver. --> <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".vm"/> </bean>
<!-- freemarker config --> <bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/> </bean> <!-- View resolvers can also be configured with ResourceBundles or XML files. If you need different view resolving based on Locale, you have to use the resource bundle resolver. --> <bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".ftl"/> </bean>
Note | |
---|---|
For non web-apps add a
|
Your templates need to be stored in the directory specified by the
*Configurer
bean shown above. This document does not
cover details of creating templates for the two languages - please see
their relevant websites for information. If you use the view resolvers
highlighted, then the logical view names relate to the template file
names in similar fashion to
InternalResourceViewResolver
for JSP's. So if
your controller returns a ModelAndView object containing a view name of
"welcome" then the resolvers will look for the
/WEB-INF/freemarker/welcome.ftl
or
/WEB-INF/velocity/welcome.vm
template as
appropriate.
The basic configurations highlighted above will be suitable for most application requirements, however additional configuration options are available for when unusual or advanced requirements dictate.
This file is completely optional, but if specified, contains the
values that are passed to the Velocity runtime in order to configure
velocity itself. Only required for advanced configurations, if you
need this file, specify its location on the
VelocityConfigurer
bean definition above.
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="configLocation value="/WEB-INF/velocity.properties"/> </bean>
Alternatively, you can specify velocity properties directly in the bean definition for the Velocity config bean by replacing the "configLocation" property with the following inline properties.
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer"> <property name="velocityProperties"> <props> <prop key="resource.loader">file</prop> <prop key="file.resource.loader.class"> org.apache.velocity.runtime.resource.loader.FileResourceLoader </prop> <prop key="file.resource.loader.path">${webapp.root}/WEB-INF/velocity</prop> <prop key="file.resource.loader.cache">false</prop> </props> </property> </bean>
Refer to the API
documentation for Spring configuration of Velocity, or the
Velocity documentation for examples and definitions of the
'velocity.properties'
file itself.
FreeMarker 'Settings' and 'SharedVariables' can be passed
directly to the FreeMarker Configuration
object
managed by Spring by setting the appropriate bean properties on the
FreeMarkerConfigurer
bean. The
freemarkerSettings
property requires a
java.util.Properties
object and the
freemarkerVariables
property requires a
java.util.Map
.
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"> <property name="templateLoaderPath" value="/WEB-INF/freemarker/"/> <property name="freemarkerVariables"> <map> <entry key="xml_escape" value-ref="fmXmlEscape"/> </map> </property> </bean> <bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/>
See the FreeMarker documentation for details of settings and
variables as they apply to the Configuration
object.
Spring provides a tag library for use in JSP's that contains
(amongst other things) a <spring:bind/>
tag.
This tag primarily enables forms to display values from form backing
objects and to show the results of failed validations from a
Validator
in the web or business tier. From version
1.1, Spring now has support for the same functionality in both Velocity
and FreeMarker, with additional convenience macros for generating form
input elements themselves.
A standard set of macros are maintained within the
spring.jar
file for both languages, so they are
always available to a suitably configured application.
Some of the macros defined in the Spring libraries are
considered internal (private) but no such scoping exists in the macro
definitions making all macros visible to calling code and user
templates. The following sections concentrate only on the macros you
need to be directly calling from within your templates. If you wish to
view the macro code directly, the files are called spring.vm /
spring.ftl and are in the packages
org.springframework.web.servlet.view.velocity
or
org.springframework.web.servlet.view.freemarker
respectively.
In your html forms (vm / ftl templates) that act as the
'formView' for a Spring form controller, you can use code similar to
the following to bind to field values and display error messages for
each input field in similar fashion to the JSP equivalent. Note that
the name of the command object is "command" by default, but can be
overridden in your MVC configuration by setting the 'commandName' bean
property on your form controller. Example code is shown below for the
personFormV
and personFormF
views configured earlier;
<!-- velocity macros are automatically available --> <html> ... <form action="" method="POST"> Name: #springBind( "command.name" ) <input type="text" name="${status.expression}" value="$!status.value" /><br> #foreach($error in $status.errorMessages) <b>$error</b> <br> #end <br> ... <input type="submit" value="submit"/> </form> ... </html>
<!-- freemarker macros have to be imported into a namespace. We strongly recommend sticking to 'spring' --> <#import "spring.ftl" as spring /> <html> ... <form action="" method="POST"> Name: <@spring.bind "command.name" /> <input type="text" name="${spring.status.expression}" value="${spring.status.value?default("")}" /><br> <#list spring.status.errorMessages as error> <b>${error}</b> <br> </#list> <br> ... <input type="submit" value="submit"/> </form> ... </html>
#springBind
/
<@spring.bind>
requires a 'path' argument
which consists of the name of your command object (it will be
'command' unless you changed it in your FormController properties)
followed by a period and the name of the field on the command object
you wish to bind to. Nested fields can be used too such as
"command.address.street". The bind
macro assumes
the default HTML escaping behavior specified by the ServletContext
parameter defaultHtmlEscape
in web.xml
The optional form of the macro called
#springBindEscaped
/
<@spring.bindEscaped>
takes a second argument
and explicitly specifies whether HTML escaping should be used in the
status error messages or values. Set to true or false as required.
Additional form handling macros simplify the use of HTML escaping and
these macros should be used wherever possible. They are explained in
the next section.
Additional convenience macros for both languages simplify both binding and form generation (including validation error display). It is never necessary to use these macros to generate form input fields, and they can be mixed and matched with simple HTML or calls direct to the spring bind macros highlighted previously.
The following table of available macros show the VTL and FTL definitions and the parameter list that each takes.
Table 16.1. Table of macro definitions
macro | VTL definition | FTL definition |
---|---|---|
message (output a string from a resource bundle based on the code parameter) | #springMessage($code) | <@spring.message
code/> |
messageText (output a string from a resource bundle based on the code parameter, falling back to the value of the default parameter) | #springMessageText($code
$text) | <@spring.messageText code,
text/> |
url (prefix a relative URL with the application's context root) | #springUrl($relativeUrl) | <@spring.url
relativeUrl/> |
formInput (standard input field for gathering user input) | #springFormInput($path
$attributes) | <@spring.formInput path, attributes,
fieldType/> |
formHiddenInput * (hidden input field for submitting non-user input) | #springFormHiddenInput($path
$attributes) | <@spring.formHiddenInput path,
attributes/> |
formPasswordInput * (standard input field for gathering passwords. Note that no value will ever be populated in fields of this type) | #springFormPasswordInput($path
$attributes) | <@spring.formPasswordInput path,
attributes/> |
formTextarea (large text field for gathering long, freeform text input) | #springFormTextarea($path
$attributes) | <@spring.formTextarea path,
attributes/> |
formSingleSelect (drop down box of options allowing a single required value to be selected) | #springFormSingleSelect( $path $options
$attributes) | <@spring.formSingleSelect path, options,
attributes/> |
formMultiSelect (a list box of options allowing the user to select 0 or more values) | #springFormMultiSelect($path $options
$attributes) | <@spring.formMultiSelect path, options,
attributes/> |
formRadioButtons (a set of radio buttons allowing a single selection to be made from the available choices) | #springFormRadioButtons($path $options
$separator $attributes) | <@spring.formRadioButtons path, options
separator, attributes/> |
formCheckboxes (a set of checkboxes allowing 0 or more values to be selected) | #springFormCheckboxes($path $options
$separator $attributes) | <@spring.formCheckboxes path, options,
separator, attributes/> |
showErrors (simplify display of validation errors for the bound field) | #springShowErrors($separator
$classOrStyle) | <@spring.showErrors separator,
classOrStyle/> |
* In FTL (FreeMarker), these two macros are not actually
required as you can use the normal formInput
macro,
specifying 'hidden
' or
'password
' as the value for the
fieldType
parameter.
The parameters to any of the above macros have consistent meanings:
path: the name of the field to bind to (ie "command.name")
options: a Map of all the available values that can be
selected from in the input field. The keys to the map represent
the values that will be POSTed back from the form and bound to the
command object. Map objects stored against the keys are the labels
displayed on the form to the user and may be different from the
corresponding values posted back by the form. Usually such a map
is supplied as reference data by the controller. Any Map
implementation can be used depending on required behavior. For
strictly sorted maps, a SortedMap
such as a
TreeMap
with a suitable Comparator may be used
and for arbitrary Maps that should return values in insertion
order, use a LinkedHashMap
or a
LinkedMap
from commons-collections.
separator: where multiple options are available as discreet elements (radio buttons or checkboxes), the sequence of characters used to separate each one in the list (ie "<br>").
attributes: an additional string of arbitrary tags or text to be included within the HTML tag itself. This string is echoed literally by the macro. For example, in a textarea field you may supply attributes as 'rows="5" cols="60"' or you could pass style information such as 'style="border:1px solid silver"'.
classOrStyle: for the showErrors macro, the name of the CSS class that the span tag wrapping each error will use. If no information is supplied (or the value is empty) then the errors will be wrapped in <b></b> tags.
Examples of the macros are outlined below some in FTL and some in VTL. Where usage differences exist between the two languages, they are explained in the notes.
<!-- the Name field example from above using form macros in VTL --> ... Name: #springFormInput("command.name" "")<br> #springShowErrors("<br>" "")<br>
The formInput macro takes the path parameter (command.name) and an additional attributes parameter which is empty in the example above. The macro, along with all other form generation macros, performs an implicit spring bind on the path parameter. The binding remains valid until a new bind occurs so the showErrors macro doesn't need to pass the path parameter again - it simply operates on whichever field a bind was last created for.
The showErrors macro takes a separator parameter (the characters that will be used to separate multiple errors on a given field) and also accepts a second parameter, this time a class name or style attribute. Note that FreeMarker is able to specify default values for the attributes parameter, unlike Velocity, and the two macro calls above could be expressed as follows in FTL:
<@spring.formInput "command.name"/> <@spring.showErrors "<br>"/>
Output is shown below of the form fragment generating the name field, and displaying a validation error after the form was submitted with no value in the field. Validation occurs through Spring's Validation framework.
The generated HTML looks like this:
Name: <input type="text" name="name" value="" > <br> <b>required</b> <br> <br>
The formTextarea macro works the same way as the formInput macro and accepts the same parameter list. Commonly, the second parameter (attributes) will be used to pass style information or rows and cols attributes for the textarea.
Four selection field macros can be used to generate common UI value selection inputs in your HTML forms.
formSingleSelect
formMultiSelect
formRadioButtons
formCheckboxes
Each of the four macros accepts a Map of options containing the value for the form field, and the label corresponding to that value. The value and the label can be the same.
An example of radio buttons in FTL is below. The form backing object specifies a default value of 'London' for this field and so no validation is necessary. When the form is rendered, the entire list of cities to choose from is supplied as reference data in the model under the name 'cityMap'.
... Town: <@spring.formRadioButtons "command.address.town", cityMap, "" /><br><br>
This renders a line of radio buttons, one for each value in
cityMap
using the separator "". No additional
attributes are supplied (the last parameter to the macro is
missing). The cityMap uses the same String for each key-value pair
in the map. The map's keys are what the form actually submits as
POSTed request parameters, map values are the labels that the user
sees. In the example above, given a list of three well known cities
and a default value in the form backing object, the HTML would
be
Town: <input type="radio" name="address.town" value="London" > London <input type="radio" name="address.town" value="Paris" checked="checked" > Paris <input type="radio" name="address.town" value="New York" > New York
If your application expects to handle cities by internal codes for example, the map of codes would be created with suitable keys like the example below.
protected Map referenceData(HttpServletRequest request) throws Exception { Map cityMap = new LinkedHashMap(); cityMap.put("LDN", "London"); cityMap.put("PRS", "Paris"); cityMap.put("NYC", "New York"); Map m = new HashMap(); m.put("cityMap", cityMap); return m; }
The code would now produce output where the radio values are the relevant codes but the user still sees the more user friendly city names.
Town: <input type="radio" name="address.town" value="LDN" > London <input type="radio" name="address.town" value="PRS" checked="checked" > Paris <input type="radio" name="address.town" value="NYC" > New York
Default usage of the form macros above will result in HTML tags that are HTML 4.01 compliant and that use the default value for HTML escaping defined in your web.xml as used by Spring's bind support. In order to make the tags XHTML compliant or to override the default HTML escaping value, you can specify two variables in your template (or in your model where they will be visible to your templates). The advantage of specifying them in the templates is that they can be changed to different values later in the template processing to provide different behavior for different fields in your form.
To switch to XHTML compliance for your tags, specify a value of 'true' for a model/context variable named xhtmlCompliant:
## for Velocity.. #set($springXhtmlCompliant = true) <#-- for FreeMarker --> <#assign xhtmlCompliant = true in spring>
Any tags generated by the Spring macros will now be XHTML compliant after processing this directive.
In similar fashion, HTML escaping can be specified per field:
<#-- until this point, default HTML escaping is used --> <#assign htmlEscape = true in spring> <#-- next field will use HTML escaping --> <@spring.formInput "command.name" /> <#assign htmlEscape = false in spring> <#-- all future fields will be bound with HTML escaping off -->