Professional Java Development with the Spring Framework
FreeMarker and Velocity are templating tools with different aims than JSP. Both tools offer a sophisticated templating language, entirely based on a proprietary engine, written in Java. As opposed to JavaServer Pages, both FreeMarker and Velocity promote the separation of logic from presentation as much as possible, not even offering the possibility of including Java code in the template. We won't go too deeply into the advantages and disadvantages of the two approaches here. In a team where responsibilities are strictly separated and where you have one or more graphical designers and HTML programmers, you might be better off choosing FreeMarker or Velocity because it offers a more HTML-oriented templating language and there's no danger of Java developers putting Java code in templates.
Spring offers support for both FreeMarker-based views as well as views created using Velocity, through the org.springframework.web.servlet.view.freemarker and org.springframework.web.servlet.view.velocity packages, respectively. We'll cover Velocity and FreeMarker together, as the features Spring offers for integrating them are very similar. Please refer to the section "JavaServer Pages" earlier in this chapter as necessary, as some of the concepts are more thoroughly explained there. Pointers will be offered where necessary.
Important | Note that both Velocity as well as FreeMarker can be used to do email templating, for example. Using Velocity to send emails is covered in-depth in Chapter 9. |
Configuring the View Resolver
As you've seen in the example right at the beginning of this chapter, configuring Spring to work with Velocity is a matter of adding a view resolver to your web application context alongside a so-called configurer. To start working with FreeMarker you'd have to do the same thing.
Configuring Velocity
Velocity templates created with the Velocity Template Language (VTL) are rendered using the VelocityEngine. Configuring the engine has to be done using the org.springframework.web.servlet.view.velocity.VelocityConfigurer. The simplest configuration of them all is the following, where using the resourceLoaderPath, you can indicate where your Velocity templates are placed:
<bean > <property name="resourceLoaderPath"><value>WEB-INF/views/</value></property> </bean>
After adding this bean to your context, the VelocityEngine will be configured for you. As you might know, configuring a VelocityEngine happens using a Properties file. With the Spring VelocityConfigurer, you can specify the properties inline or reference them using the configLocation property. More information on the properties available to configure the engine can be found in the JavaDoc of the org.apache.velocity.runtime.Runtime class and in the Velocity Developers guide (http://jakarta.apache.org/velocity/developer-guide.html#Velocity Configuration Keys and Values).
<bean > <property name="configLocation"><value>WEB-INF/velocity.properties</property> </bean>
After adding the configurer, you will have to add a ViewResolver to complete the integration of Velocity in your application. Here's how to create the view resolver:
<bean > <property name="suffix"><value>.vm</value></property> </bean>
This bean indicates that all your Velocity templates end with a .vm extension. Using the resource LoaderPath, we already specified where the view resolver will get its templates from.
Velocity has a built-in capability to provide your templates with so-called tools to format dates and numbers, for example. The Velocity documentation includes a detailed section on a set of generic tools that come with the Velocity distribution and how to use them. The documentation can be found at http://jakarta.apache.org/velocity/tools/.
The VelocityViewResolver class provides two properties to enable the inclusion of tools to format dates and numbers. (The tools from the Velocity distribution by default use the default system locale; Spring's LocaleAwareDateTool and LocaleAwareNumber tool use Spring's built-in locale resolution strategies to format dates and numbers using the user's locale.) The following example enables the inclusion of the date tool and number tool in the Velocity context:
<bean > > <property name="numberToolAttribute"><value>numbertool</value></property> <property name="dateToolAttribute"><value>datetool</value></property> </bean>
Suppose your model (returned from your controller) includes a date, identified by the key currentDate; you can format it in a Velocity template as follows:
$date.format("yyyy-MM-dd", $currentDate)
Configuring FreeMarker
FreeMarker configuration closely resembles the configuration of the Velocity engine. Including the org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer and the org.spring framework.web.servlet.view.freemarker.FreeMarkerViewResolver in your application context is all you need to do to add FreeMarker support to your web application:
<bean > <property name="templateLoaderPath"><value>/WEB-INF/templates/</value></property> </bean> <bean > <property name="suffix"><value>.ftl</value></property> </bean>
Templating tools are often used not only to generate HTML pages displayed in a browser, but also to programmatically send template-based emails. Spring's FreeMarker support features a FreeMarker ConfigurationFactoryBean, which allows developers to externalize the freemarker.template.Configuration object and use it, for example, for both email templates and templates used in a Web MVC application. In the following example, TemplateMailSender is responsible for sending emails using Spring's mail sending infrastructure and using the freemarker.template.Configuration.getTemplate() and freemarker.template.Template.process() methods. For more information about how to programmatically use the FreeMarker template engine, have a look at the FreeMarker documentation at www.freemarker.org.
<bean > <property name="freemarkerConfiguration"> <ref bean="freemarkerConfig"/> </property> </bean> <bean > </bean> <bean > <property name="templateLoaderPath"><value>/WEB-INF/templates/</value></property> <property name="dateFormat"><value>MM/dd/yyyy</value></property> <property name="timeFormat"><value>MM/dd/yyyy HH:mm</value></property> </bean>
You might wonder why we don't need to pass the configuration (the freemarkerConfig bean shown earlier) to the configurer. Spring automatically picks up factories creating FreeMarker configurations and processes them for you.
Using the Form Simplification Macros
Spring's support for Velocity and FreeMarker comes with a set of form simplification macros that facilitate the creation of forms and working with Spring's command controllers. The form simplification macros to some extent resemble the custom tags described in the preceding section on JSPs. However, there are a few extras. Both macros and the custom tags simplify the binding of command objects edited or created by form controllers. For more information on concepts such as BindStatus and binding, please refer to the section "Creating Forms and Using Custom Tags."
Configuring Your FreeMarker and Velocity Templates to Use Macros
FreeMarker as well as Velocity includes ways to enable macros in specific templates. Spring allows you to specify whether or not to include the macros using the exposeSpringHelperMacros property on both the FreeMarkerView and the VelocityView. For example, using a ResourceBundleViewResolver, you can specify for each individual template whether or not to include macros:
<bean > <property name="basename"><value>views</value></property> </bean>
Along with a views.properties file in /WEB-INF/classes, the preceding view resolver would do the job and turn on form simplification macros for both the showForm view and the confirmReservation view. The other view won't have them included.
showForm.class=org.springframework.web.servlet.view.velocity.VelocityView showForm.url=show-form.vm showForm.exposeSpringMacroHelpers=true confirmReservation.class=\ org.springframework.web.servlet.view.freemarker.FreeMarkerView confirmReservation.url=confirm-reservation.ftl confirmReservation.exposeSpringMacroHelpers=true login.class=org.springframework.web.servlet.view.velocity.VelocityView login.url=login.vm login.exposeSpringMacroHelpers=false
Important | As you can see, this example also shows you how to use both Velocity and FreeMarker in one web application. Using the ResourceBundleViewResolver (but also using the XmlViewResolver) you can use many different types of views at the same time, a requirement often encountered in applications that need to export to Excel or PDF, for example. |
Note that by default the exposeSpringMacroHelpers property is set to false. You can either turn it on per bean, or you can use the notion of parent bean definitions. Consider the following:
showForm.class=org.springframework.web.servlet.view.velocity.VelocityView showForm.url=show-form.vm showDetails.parent=showForm showDetails.url=show-details.vm
The view class of the showDetails view is now automatically inherited from the showForm view. Of course, specifying a parent for every view is somewhat of a hassle, so it's also possible to specify a default parent bean, which all views will inherit:
defaultParentView=showForm showForm.class=org.springframework.web.servlet.view.velocity.VelocityView showForm.url=show-form.vm
It is also possible to indicate that you want form simplification macros to be included in all your Velocity- or FreeMarker-based views. Setting the same property (exposeSpringMacroHelpers), but this time on either the VelocityViewResolver or the FreeMarkerViewResolver, is all you need to do; for example:
<bean > <property name="exposeSpringMacroHelpers"><value>true</value></property> </bean>
Using Velocity or FreeMarker Macros to Create a Form
To illustrate the Velocity and FreeMarker macros, we'll use a Reservation class (as we did with the examples for using the JSP custom tags) for which we will create a form. The end-user will be placing a reservation using the form and the associated form controller.
public class Reservation { public void setShow(Show show) { ... } public Show getShow() { ... } public void setDate(Date d) { ... } public Date getDate() { ... } public void setNumberOfPersons(int p) { ... } public int getNumberOfPersons() { ... } }
The form controller is shown here:
public class ReservationFormController { // non-relevant methods left out protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception { binder.registerCustomEditor(Show.class, new ShowEditor(...)); binder.registerCustomerEditor(Date.class, new CustomDateEditor("yyyy-MM-dd", true); } protected Map referenceData(HttpServletRequest request) throws Exception { Map refData = new HashMap(); Map shows; // lookup shows refData.put("shows", shows); } public ModelAndView onSubmit(Object command) { Reservation r = (Reservation)command; // do something with the reservation return new ModelAndView(getSuccessView()); } }
As you can see, we're binding a custom editor to be able to transform shows to Strings (usable in an HTML form) and one to transform dates to Strings (and of course the other way around when the user submits the form). The referenceData shows the inclusion of a list of shows a user will be able to choose from. The property editors will be used by the macros and the helper class BindStatus. The following example shows how to use the springFormSingleSelect and springFormInput macros. We're passing the springFormSingleSelect macro a Map of shows (identifiers mapped to show names) bound in the request by the controller where the springFormInput macro just needs a path (command.date) to generate an input with type text. Using the last parameter of both the springFormInput as well as the springFormSingleSelect macro, you can pass any additional attributes that will be included in the input and the select tags respectively.
<form method="post"> Shows: #springFormSingleSelect("command.show", $shows, "style='width:100px;'") <br> Date: #springFormInput("command.date", "style='width:100px;'") <br> People: #springFormInput("command.numberOfPersons", "") <br> <input type="submit"/> </form>
We've just shown the Velocity markup while using macros. FreeMarker resembles the Velocity syntax a lot.
The following list shows all macros that are available since Spring 1.1:
-
formInput: Generates a standard input field with type text. The only parameter except the attributes parameter available for all macros is the command path you're binding on.
-
formTextArea: Generates a text area using the command path specified. This macro also allows for passing in attributes such as style.
-
formSingleSelect: Generates a select box where the user will be able to select only one of the options available. As always, the first parameter is the command path you're binding on. The second parameter is a Map of options that will be included in the drop-down box. The key is used later to bind the property (in our example controller, this would be the show identifier, used by the property editor to look up the correct show). The last parameter again has to include any additional HTML options you wish to pass along.
-
formMultiSelect: Has the same syntax as formSingleSelect, except for the fact that this macro generates a drop-down box where the user can select more than just one option.
-
formCheckboxes and formRadioButton: Two macros that facilitate the creation of a list of checkboxes or radio buttons. The first parameter is again the command path and the second parameter a Map of options to include. Often, you want each checkbox to be placed on a single line in your web page. The third parameter allows you to specify a separator character that will be included after rendering a checkbox or radio button. With the last parameter you can pass additional HTML attributes to the checkboxes and radio buttons.
More information about the Velocity macros can be found online at www.springframework.org.