Apache FreeMarker is a template engine for generating any kind of text output from HTML to email, etc. Spring Framework has built-in integration for using Spring MVC with FreeMarker templates.
View Configuration
The following example shows how to configure FreeMarker as your presentation technology:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.freeMarker();
}
// Configure FreeMarker...
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/freemarker");
return configurer;
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.freeMarker()
}
// Configure FreeMarker...
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("/WEB-INF/freemarker")
}
}
The following example shows how to configure the same in XML:
<mvc:annotation-driven/>
<mvc:view-resolvers>
<mvc:freemarker/>
</mvc:view-resolvers>
<!-- Configuring FreeMarker... -->
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
In addition, you can declare a FreeMarkerConfigurer
bean for complete control over all
properties, like shown in the following example:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
</bean>
Your templates should be stored in the directory specified by FreeMarkerConfigurer
, as shown in
the previous example. Given the previous configuration, if your controller returns the view name
welcome
, the resolver looks for the pattern /WEB-INF/freemarker/welcome.ftl
.
FreeMarker Configuration
It is possible to pass the FreeMarker handler's "Settings" and "SharedVariable"
directly to the FreeMarker handler's Configuration
object (which is managed by Spring) by setting the
appropriate bean properties in the FreeMarkerConfigurer
. The freemarkerSettings
property
requires a java.util.Properties
object, and the freemarkerVariables
property requires a
java.util.Map
object. The following example shows how to use FreeMarkerConfigurer
:
<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"/>
Details about the settings and variables that apply to the object Configuration
, see FreeMarker
documentation.
Form Handling
Spring provides a library of tags for use in JSP, which contains, among other things, the
<spring:bind/>
.
This element primarily allows forms to display values from underlying form objects and display the results of
failed validations from a Validator
in the web or business tier. Spring also has support for the
same functionality in FreeMarker, with additional convenience macros for generating the form input elements
themselves.
Binding macros
The support for the standard set of macros is in the file spring-webmvc.jar
for FreeMarker, so they
are always available to a suitably configured application.
Some macros defined in Spring templating libraries are considered internal (private), but there is no such
restriction in macro definitions , which makes all macros visible to calling code and user templates. The
following sections cover only macros that need to be called directly from templates. If you need to view the
macro code directly, the file is called spring.ftl
and is located in the org.springframework.web.servlet.view.freemarker
package.
Simple Binding
In your FreeMarker template-based HTML forms that act as the form view for a Spring MVC controller, you can use
code like the following example to bind to field values and output to Error message screen for each input field
is similar to the JSP equivalent. The following example shows the personForm
view:
<!-- FreeMarker macros must be imported into the namespace.
We strongly recommend sticking with the "spring" option. -->
<#import "/spring.ftl" as spring/>
<html>
...
<form action="" method="POST">
Name:
<@spring.bind "personForm.name"/>
<input type="text"
name="${spring.status.expression}"
value="${spring.status.value?html}"/><br/>
<#list spring.status.errorMessages as error> <b>${error}</b> <br/> </#list>
<br />
...
<input type="submit" value="submit"/>
</form>
...
</html>
<@spring.bind>
requires a "path" argument, which consists of the name of your command object
(this is "command" unless you changed it in the controller configuration), followed by a dot and the name of the
command object field you want to bind to. You can also use nested fields, such as
command.address.street
. The bind macro provides default HTML escape logic, specified by the
defaultHtmlEscape parameter of the ServletContext
context in web.xml.
An alternative form of the <@spring.bindEscaped>
macro takes a second argument that explicitly
specifies whether HTML escaping should be used in status detection error messages or values. You can set the
value to true
or false
depending on your need. Additional form macros make HTML
escaping easier to use, and you should use these macros whenever possible. These are described in the next
section.
Input macros
Additional helper macros for FreeMarker simplify form binding and generation (including displaying validation errors). There is no need to use these macros to create form input fields; they can be mixed and matched using plain HTML or direct calls to the Spring binding macros we covered earlier.
The following table of available macros summarizes the FreeMarker Template definitions (FTL) and a list of parameters that each of them accepts:
macro | FTL Definition |
---|---|
|
<@spring.message code/> |
|
<@spring.messageText code, text/> |
|
<@spring.url relativeUrl/> |
|
<@spring.formInput path, attributes, fieldType/> |
|
<@spring.formHiddenInput path, attributes/> |
|
<@spring.formPasswordInput path, attributes/> |
|
<@spring. formTextarea path, attributes/> |
|
<@spring.formSingleSelect path, options, attributes/> |
|
<@spring.formMultiSelect path, options, attributes/> |
|
<@spring.formRadioButtons path, options separator, attributes/> |
|
<@spring.formCheckboxes path, options, separator, attributes/> |
|
<@spring.formCheckbox path, attributes/> |
|
<@spring.showErrors separator, classOrStyle/> |
formHiddenInput
and formPasswordInput
are actually not needed, since you can use the regular formInput
macro by specifying
hidden
or password
as the value of the fieldType
parameter.
The parameters of any of the above macros have a clear meaning:
path
: name of the field to bind (i.e. "command.name")options
:Map
of all available values that can be selected in the input field. Map keys are values that are passed back from the form and bound to the command object. The Map objects stored along with the keys are the labels that are displayed on the form to the user and may differ from the corresponding values returned by the form. Typically such a Map is provided by the controller as reference data. You can use any Map implementation depending on the required operating logic. For strictly sorted Maps, you can use a SortedMap (such as a TreeMap) with a suitable Comparator, and for arbitrary Maps that need to return values in insertion order, use a LinkedHashMap or a LinkedMap from commons-collections.separator
: If multiple options are available as separate elements (radio buttons or checkboxes), then this parameter represents the sequence of characters used to separate each of them in the list (for example,<br>
).attributes
: An additional string of arbitrary tags or text to include in the HTML tag itself. This line is repeated letter by the macro. For example, thetextarea
field can pass attributes (for example, 'rows="5" cols="60"') or style information, for example, 'style="border:1px solid silver"'.classOrStyle
: for the macroshowErrors
- the name of the CSS class that is used in thespan
element, wrapping each error. If no information is provided (or the value is empty), errors are wrapped in<b></b>
tags.
The following sections provide examples of macros.
Input fields
The formInput
macro accepts the parameter path(command.name
) and an additional
parameter attributes
(which is empty in the following example). This macro, like all other form
generation macros, does an implicit Spring binding to the "path" parameter. The binding remains valid until a
new binding is made, so the showErrors
macro does not need to pass the path parameter again - it
operates on the field for which the binding was last created.
The showErrors
macro takes a separator parameter (characters that are used to separate multiple
errors in a given field) and also takes a second parameter - this time a class name or style attribute. Note
that FreeMarker can set default values for the "attributes" parameter. The following example shows how to use
the formInput
and showErrors
macros:
<@spring.formInput "command.name"/>
<@spring.showErrors "<br>"/>
The following example shows the output of a form fragment with generating a name field and displaying a validation error after how the form was submitted without a value in the field. Validation occurs through the Validation framework in Spring.
The generated HTML is similar to the following example:
Name:
<input type="text" name="name" value="">
<br>
<b>required</b>
<br>
<br>
The formTextarea
macro works the same as the formInput
macro, and accepts the same list
of parameters. Typically the second parameter (attributes
) is used to pass style information or the
rows
and cols
attributes for the textarea
.
Select Fields
You can use four select field macros to generate regular UI value selection inputs in your HTML forms :
formSingleSelect
formMultiSelect
formRadioButtons
formCheckboxes
Each of the four macros accepts a Map
option, which contains a value for the form field and a label
corresponding to that value. The value and label can be the same.
The following example concerns radio buttons in FTL. The underlying form object sets this field to a default value of "London", so no validation is required. When the form is displayed, the entire list of cities to select is provided as reference data in the model under the name "cityMap". The following listing shows an example:
...
Town:
<@spring.formRadioButtons "command.address.town", cityMap, ""/><br><br>
The previous listing displays a row of radio buttons, one for each value in the cityMap
, and uses
the delimiter ""
. No additional attributes are assigned (the last macro parameter is missing).
cityMap
uses the same String
for each key-value pair in the Map. Map keys are what the
form actually sends as parameters to the POST
request. Map values are the labels that the user
sees. In the previous example, given a list of three known cities and a default value in the base form object,
the HTML looks like this:
Town:
<input type="radio" name="address.town" value="London">London</input>
<input type="radio" name="address.town" value="Paris" checked="checked">Paris</input>
<input type="radio" name="address.town" value="New York">New York</input>
If your The application assumes working with cities using internal codes (for example), then you can create a Map of codes with the corresponding keys, as shown in the following example:
protected Map<String, ?> referenceData(HttpServletRequest request) throws Exception {
Map<String, String> cityMap = new LinkedHashMap<>();
cityMap.put("LDN", "London");
cityMap.put("PRS", "Paris");
cityMap.put("NYC", "New York");
Map<String, Object> model = new HashMap<>();
model.put("cityMap", cityMap);
return model;
}
protected fun referenceData(request: HttpServletRequest): Map<String, *> {
val cityMap = linkedMapOf(
"LDN" to "London",
"PRS" to "Paris",
"NYC" to "New York"
)
return hashMapOf("cityMap" to cityMap)
}
The code now outputs data where the switch values are the corresponding codes, but the user still sees more user-friendly city names, as shown below:
Town:
<input type="radio" name="address.town" value="LDN">London</input>
<input type="radio" name="address.town" value="PRS" checked="checked">Paris</input>
<input type="radio" name="address.town" value="NYC">New York</input>
HTML escaping
Using the default form macros described earlier results in HTML elements that conform to the HTML 4.01
standard and use the default HTML escaping value defined in your web.xml
file, which is used
by the Spring binding support tools. To make elements XHTML compliant, or to override the default HTML
escaping value, you can set two variables in your template (or in your model, where your templates see
them). The advantage of setting them in templates is that they can be changed to others values later in
template processing to provide different logic for different fields in your form.
To switch to XHTML compliant mode for your tags, set the value to true
for the model or context
variable named xhtmlCompliant
, as shown in the following example:
<#-- for FreeMarker -->
<#assign xhtmlCompliant = true>
After processing this directive, all elements created by Spring macros will now be compliant with the XHTML standard.
Similarly, you can specify HTML escaping for each field, as shown in the following example:
<#-- until this point, default HTML escaping is used -->
<#assign htmlEscape = true>
<#-- 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 -->