14. Rendering web views – Spring in Action, Second Edition

Chapter 14. Rendering web views

This chapter covers

  • Matching controllers to views

  • Rendering views with JSP, Velocity, and FreeMarker

  • Laying out pages with Tiles

  • Generating PDF, Excel, and RSS output

The controllers, services, and DAOs in an application live in a box we call the server. Those application components may be doing something very important, but unless we can see what they’re doing, we can only guess what’s going on in there. For an application to be useful, it needs a way to communicate with the user.

That’s where the V of MVC comes into play. The view of an application communicates information back to the user and prompts the user to communicate with the application. Without the view layer of an application, we can only guess what’s inside.

In chapter 13, we looked at how to build the web layer of the RoadRantz application using Spring MVC. You learned how to configure Spring MVC and how to write controllers that would process user input and produce model data to present to the user. But at that time we conveniently ignored how that information would be presented to the user.

Now it’s time to see how to show the user what’s going on in the application by building the application’s view layer. We’ll start by looking at how Spring chooses a view based on the logical view name returned from a controller. Then we’ll explore various ways that Spring can produce output for the user, including template-based HTML, Excel spreadsheets, PDFs, and Rich Site Summary (RSS) feeds.

Resolving views

As you saw in the previous chapter, most of Spring MVC’s controllers return ModelAndView objects from their main execution method. You saw how model objects are passed to the view through the ModelAndView object, but we deferred discussion of how the logical view name is used to determine which view will render the results to the user.

In Spring MVC, a view is a bean that renders results to the user. How it performs the rendering depends on the type of view you’ll use. Most likely, you’ll want to use JavaServer Pages (JSP) to render the results. But you may also want to use alternate view technologies such as Velocity and FreeMarker templates or even views that produce PDF and Microsoft Excel documents. We’ll talk about all of these options later in this chapter.

The big question at this point is how a logical view name given to a ModelAndView object gets resolved into a View bean that will render output to the user. That’s where view resolvers come into play. Figure 14.1 shows how view resolvers work.

Figure 14.1. A view resolver uses the logical view name in the ModelAndView returned from a controller to look up a view to render results to the user.

A view resolver is any bean that implements org.springframework.web.servlet.ViewResolver. Spring MVC regards these beans as special and consults them when trying to determine which View bean to use. Spring comes with several implementations of ViewResolver, as listed in table 14.1.

Table 14.1. Spring MVC’s view resolvers help DispatcherServlet find view implementations based on a logical view name that was returned from a controller.

View resolver

How it works

InternalResourceViewResolver

Resolves logical view names into View objects that are rendered using template file resources (such as JSPs and Velocity templates)

BeanNameViewResolver

Looks up implementations of the View interface as beans in the Spring context, assuming that the bean name is the logical view name

ResourceBundleViewResolver

Uses a resource bundle (e.g., a properties file) that maps logical view names to implementations of the View interface

XmlViewResolver

Resolves View beans from an XML file that is defined separately from the application context definition files

Let’s have a look at a few of the most useful view resolvers, starting with InternalResourceViewResolver.

Using template views

Odds are good that most of the time templates will render the results of your controllers. For example, suppose that after RantsForVehicleController is finished, you’d like to display the list of rants using the following JSP:

<%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
  <head><title>Rantz For Vehicle</title></head>

  <body>
    <h2>Rantz for: ${vehicle.state} ${vehicle.plateNumber}</h2>

    <ul>
    <c:forEach items="${rants}" var="rant">
    <li><c:out value="${rant.vehicle.state}"/>/
        <c:out value="${rant.vehicle.plateNumber}"/> --
        <c:out value="${rant.rantText}"/></li>
    </c:forEach>
    </ul>
  </body>
</html>

Aesthetics aside, this JSP renders a list of the rants retrieved by RantsForVehicleController. Knowing that RantsForVehicleController’s handle() method concludes with the following return:

return new ModelAndView("vehicleRants", "rants", vehicleRants);

how can you tell Spring MVC that the logical view name vehicleRants means to use the rant-listing JSP to render the results?

InternalResourceViewResolver resolves a logical view name into a View object that delegates rendering responsibility to a template located in the web application’s context. As illustrated in figure 14.2, it does this by taking the logical view name returned in a ModelAndView object and surrounding it with a prefix and a suffix to arrive at the path of a template within the web application.

Figure 14.2. InternalResourceViewResolver resolves a view template’s path by attaching a specified prefix and suffix to the logical view name.

Let’s say that you’ve placed all of the JSPs for the RoadRantz application in the /WEB-INF/jsp/ directory. Given that arrangement, you’ll need to configure an InternalResourceViewResolver bean in roadrantzservlet.xml as follows:

<bean id="viewResolver" class=
    "org.springframework.web.servlet.view.
          InternalResourceViewResolver">
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
</bean>

When InternalResourceViewResolver is asked to resolve a view, it takes the logical view name, prefixes it with /WEB-INF/jsp/, and suffixes it with .jsp to arrive at the path of the JSP that will render the output. It then hands that path over to a View object that dispatches the request to the JSP.

So, when RantsForVehicleController returns a ModelAndView object with vehicleRants as the logical view name, it ends up resolving that view name to the path of a JSP: /WEB-INF/jsp/vehicleRants.jsp.

InternalResourceViewResolver then loads a View object with the path of the JSP. This implies that the rant list template must be named vehicleRants.jsp.

By default the View object is an InternalResourceView, which simply dispatches the request to the JSP to perform the actual rendering. But since vehicleRants.jsp uses JSTL tags, you may choose to replace InternalResourceView with JstlView by setting InternalResourceViewResolver’s viewClass property as follows:

<bean id="viewResolver" class=
    "org.springframework.web.servlet.view.
          InternalResourceViewResolver">
  <property name="viewClass"
    value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/jsp/" />
  <property name="suffix" value=".jsp" />
</bean>

JstlView dispatches the request to a JSP just like InternalResourceView. However, it also exposes JSTL-specific request attributes so that you can take advantage of JSTL’s internationalization support.

Although InternalResourceViewResolver is quite easy to use, it may not be the most appropriate view for all circumstances. It assumes that your view is defined in a template file within the web application. That may be the case in most situations, but not always. Let’s look at some other ways to resolve views.

Resolving view beans

When you first looked at RantsForVehicleController (listing 11.3), you may have assumed that the vehicleRants view would be rendered by a JSP. However, nothing about that controller implies that JSP will be used to render the output. What if instead of rendering the list of rants in HTML you want to offer the list as an RSS feed that the user can subscribe to?

Later, in section 14.5.3, you’ll learn how to create a custom view that produces RSS feeds. But for now, pretend that you’ve already written that custom view. Since the rant listing isn’t templated by JSP (or any other template resource for that matter) in the web application, InternalResourceViewResolver isn’t going to be of much help. Instead, you’re going to have to choose one of Spring’s other view resolvers.

BeanNameViewResolver is a view resolver that matches logical view names up with names of beans in the application context. Figure 14.3 shows how this works.

Figure 14.3. A BeanNameViewResolver looks up a view bean from the Spring context that has the same name as the logical view name.

<bean id="viewResolver" class=
     "org.springframework.web.servlet.view.BeanNameViewResolver"/>

Now when a controller returns a ModelAndView with a logical view name of rantsRss, BeanNameViewResolver will look for a bean named rantsRss. This means you must register RantRssView in the context configuration file as follows:

<bean id="rantsRss" class=
     "com.roadrantz.mvc.RantRssView"/>

Declaring view beans in a separate XML file

Another way to resolve View objects by their bean name is to use XmlFileViewResolver. XmlFileViewResolver works much like BeanNameViewResolver, but instead of looking for View beans in the main application context, it consults a separate XML file. To use XmlFileViewResolver, add the following XML to your context configuration file:

<bean id="viewResolver" class="org.springframework.web.
        servlet.view.XmlFileViewResolver">
  <property name="location">
    <value>/WEB-INF/roadrantz-views.xml</value>
  </property>
</bean>

By default, XmlFileViewResolver looks for View definitions in /WEB-INF/views.xml, but here we’ve set the location property to override the default with /WEB-INF/roadrantz-views.xml.

XmlFileViewResolver is useful if you end up declaring more than a handful of View beans in DispatcherServlet’s context configuration file. To keep the main context configuration file clean and tidy, you may separate the View declarations from the rest of the beans.

Resolving views from resource bundles

Yet another way of resolving Views by name is to use ResourceBundleViewResolver. Unlike BeanNameViewResolver and XmlFileViewResolver, ResourceBundleViewResolver manages view definitions in a properties file instead of XML (as shown in figure 14.4).

Figure 14.4. ResourceBundleViewResolver resolves views by consulting a properties file.

To use ResourceBundleViewResolver, configure ResourceBundleViewResolver in roadrantz-servlet.xml as follows:

<bean id="viewResolver" class="org.springframework.web.
        servlet.view.ResourceBundleViewResolver">
  <property name="basename" value="views" />
</bean>

The basename property is used to tell ResourceBundleViewResolver how to construct the names of the properties files that contain View definitions. Here it has been set to views, which means that the View definitions could be listed in views.properties. For example, to add the RantRssView, place the following line in views.properties:

rantsRss.class=com.roadrantz.mvc.RantRssView

The name of this property can be broken down into two parts. The first part is rantsRss, which is the logical name of the View as returned in ModelAndView. The second part, class, indicates that you are setting the class name of the View implementation that should render the output for the rantsRss view (in this case, RantRssView).

By employing properties files, ResourceBundleViewResolver has an advantage over the other view resolvers with regard to internationalization. Whereas the other view resolvers always resolved a logical view name to a single View implementation, ResourceBundleViewResolver could return a different View implementation for the same logical view name, based on the user’s Locale.

For example, if the user’s browser is configured for English-speaking users in the United States then the views definitions will be retrieved from views_en_US.properties. Alternatively, for French users, the views would be defined in views_fr_FR.properties. The benefit here is that you are able to define a distinct set of views for different locales. Perhaps U.S. users prefer RSS 0.9 for their feeds, but French users prefer Atom feeds. Using ResourceBundleViewResolver, you could satisfy both countries.

Now that you have seen four different view resolvers that come with Spring, which one do you choose? The next section provides some guidelines to help you decide.

Choosing a view resolver

Many projects rely on JSP (or some other template language) to render the view results. Assuming that your application isn’t internationalized or that you won’t need to display a completely different view based on a user’s locale, we recommend InternalResourceViewResolver because it is simply and tersely defined (as opposed to the other view resolvers that require you to explicitly define each view).

If, however, your views will be rendered using a custom View implementation (e.g., RSS, PDF, Excel, images, etc.), you’ll need to consider one of the other view resolvers. We favor BeanNameViewResolver and XmlFileViewResolver over ResourceBundleViewResolver because they let you define your View beans in a Spring context configuration XML file. By defining the View in a Spring application context, you’re able to configure it using the same syntax as you use for the other components in your application.

Given the choice between BeanNameViewResolver and XmlFileViewResolver, I’d settle on BeanNameViewResolver only when you have a handful of View beans that would not significantly increase the size of DispatcherServlet’s context file. If the view resolver is managing a large number of View objects, I’d choose XmlFileViewResolver to separate the View bean definitions into a separate file.

In the rare case that you must render a completely different view depending on a user’s locale, you have no choice but to use ResourceBundleViewResolver.

Using multiple view resolvers

Consider the case where most of an application’s views are JSP based but a handful require one of the other view resolvers. For example, most of the RoadRantz application will use JSPs to render output, but (as you’ll see in section 14.5) some responses will render RSS, PDF, and Excel output. Must you choose a BeanNameViewResolver or XmlFileViewResolver and explicitly declare all of your views just to handle the special cases of PDF and Excel?

Fortunately, you aren’t limited to choosing only one view resolver for your application. To use multiple view resolvers, simply declare all the view resolver beans you will need in your context configuration file. For example, to use InternalResourceViewResolver, BeanNameViewResolver, and XmlFileViewResolver all together, declare them as follows:

<bean id="viewResolver" class=
    "org.springframework.web.servlet.view.
          InternalResourceViewResolver">
  <property name="prefix"><value>/WEB-INF/jsp/</value></property>
  <property name="suffix"><value>.jsp</value></property>
</bean>

<bean id="beanNameViewResolver" class=
     "org.springframework.web.servlet.view.BeanNameViewResolver">
  <property name="order"><value>1</value></property>
</bean>

<bean id="xmlFileViewResolver" class=
     "org.springframework.web.servlet.view.XmlFileViewResolver">
  <property name="location">
    <value>/WEB-INF/views.xml</value>
  </property>
  <property name="order"><value>2</value></property>
</bean>

Because it’s quite possible that more than one view resolver may be able to resolve the same logical view name, you should set the order property on each of your view resolvers to help Spring determine which resolver has priority over the others when a logical view name is ambiguous among more than one resolver. The exception to this rule is InternalResourceViewResolver, which is always the last view resolver in the chain.[1]

View resolvers help DispatcherServlet find a view that will render output to the user. Now we must define the views themselves. Spring MVC supports several view layer template technologies, including JSP, Velocity, and FreeMarker. Let’s start by looking at JSP. (We’ll pick up the discussion on Velocity and FreeMarker in section 14.4.)

Using JSP templates

JavaServer Pages (JSPs) are the most common way of developing dynamic web pages in Java. In their simplest form, JSPs are HTML (or XML) files that are littered with chunks of Java code (known as scriptlets) and custom tags. Although other templating solutions have challenged JSP’s position as the standard template for Java-based web applications, JSP remains dominant.

Early versions of JSP relied heavily on scriptlets to render dynamic output. But modern JSP specifications avoid the use of scriptlets in favor of custom JSP tags. Many JSP tag libraries have emerged to perform all sorts of functionality—from simple date formatting tags to complex table rendering tags (see http://displaytag.sourceforge.net).

From the beginning, Spring has always included a small set of tags useful for things such as binding form values to fields and rendering externalized messages. Spring 2 introduces a powerful new set of form-binding tags that greatly simplify form binding in JSP pages.

Let’s start our exploration of Spring’s JSP tag libraries with the new form-binding tags.

Binding form data

As we discussed in chapter 13, Spring’s command and form controllers all have a command object associated with them. Request parameters are bound to properties of the command object for processing. And those command objects can be validated to ensure that the data bound to them meets certain criteria.

For example, recall that AddRantFormController (listing 13.4) has a Rant as its command object. When the form is submitted, the properties in the Rant object are set to the values of the corresponding request parameters. Then the Rant is validated to ensure that all of the required fields have been entered and that the vehicle’s plate number fits the format of a license plate number.

What we didn’t show you is where the request parameters come from. As you’ll recall, the formView property of AddRantFormController was set to addRant in roadrantz-servlet.xml. This means that if we’re using InternalResourceViewResolver, the view will be resolved to a JSP found in /WEB-INF/jsp/addRant.jsp, which is shown in listing 14.1.

Example 14.1. A JSP form for entering a rant

<%@ page contentType="text/html" %>

<html>
  <head>
      <title>Add Rant</title>
  </head>

  <body>
    <h2>Enter a rant...</h2>
    <form method="POST" action="addRant.htm">
      <b>State: </b><input type="text"
          name="rant.vehicle.state"/><br/>
      <b>Plate #: </b>
          <input type="text" name="rant.vehicle.plateNumber"/><br/>
       <textarea name="rant.rantText" rows="5" cols="50"></textarea>
       <input type="submit"/>
    </form>
  </body>
</html>

The main purpose of addRant.jsp is to render a form for entering a rant. Here the names of the form fields are used to tell Spring which properties of the command object (rant) to populate with the form data when the form is submitted. For example, the first <input> tag’s value will be given to the state property of the vehicle property of the command object.

There’s only one problem with using plain HTML form tags. If any errors are encountered after submitting the form, the user will be taken back to the form view to correct the errors. But what will become of the values that were submitted? With plain HTML form tags, the binding is one-way from the form fields to the command properties. If the form is redisplayed after an error, there’s no way to repopulate the form fields with the command properties. So the data entered will be lost and the user will have to reenter it all from scratch.

To address this problem, Spring 2 introduced a new tag library of form-binding JSP tags.[2] To start using the new tags, add the following JSP directive at the top of the addRant.jsp:

<%@ taglib prefix="form"
    uri="http://www.springframework.org/tags/form"%>

This tag library includes several JSP tags that render HTML form elements that are bound to the controller’s command object. For example, here’s the rant entry form, updated to use Spring’s form-binding tags:

<form:form method="POST" action="addRant.htm" commandName="rant">
  <b>State: </b><form:input path="vehicle.state" /><br/>
  <b>Plate #: </b><form:input path="vehicle.plateNumber" /><br/>
  <form:textarea path="rantText" rows="5" cols="50" />
  <input type="submit"/>
</form:form>

In this new version of the form, we’re using three of the form-binding tags. For the state and plate number fields, we use the <form:input> tag. For the rant text field we want the user to enter a lot of text, so a <form:textarea> is in order. In both cases, the path attribute defines the command property that the field is to be bound to. Finally, the <form:form> tag sets the command context for the form tags contained within it through the value of the commandName attribute.

When rendered, the JSP above is translated into the following HTML:

<form method="POST" action="addRant.htm">
  <b>State: </b><input name="vehicle.state" type="text"
     value=""/><br/>
  <b>Plate #: </b><input name="vehicle.plateNumber"
     type="text" value=""/><br/>
  <textarea name="rantText" rows="5" cols="50"></textarea>
  <input type="submit"/>
</form>

The nice thing about these form-binding tags is that, unlike regular HTML form tags, the binding goes both ways. Not only is the command populated with the field values, but if the form must be redisplayed after an error, the fields will be automatically populated with the data that caused the error.

This example only showed a few of the form-binding tags that come with Spring. But forms are often more than text fields and Spring provides form-binding tags for all occasions. Refer to appendix B (available at www.manning.com/walls3) for the complete catalog of Spring’s JSP tags.

Binding form fields is only one of the many functions offered by Spring’s JSP tag libraries. Next up, let’s have a look at how to externalize text on JSP pages.

Rendering externalized messages

In listing 14.1, the labels preceding the form fields are hard-coded in the JSP. This presents several problems:

  • Any time that the same text appears on multiple pages, there exists a possibility that each occurrence will be inconsistent with the others. For example, what appears as Plate # in addRant.jsp may appear as Plate number on another page.

  • If a decision is made to change the text, you must apply the change to every single JSP page where the text appears. If it only appears in one JSP then no problem—but it’s a much different story if the text appears in dozens of pages.

  • Hard-coded text doesn’t lend itself to internationalization. Should you need to expand your application’s audience across language boundaries, you’ll have a hard time creating custom language versions of your application’s templates.

To address these problems, Spring provides the <spring:message> tag. As shown in figure 14.5, <spring:message> renders a message from an external message properties file to the output. Using <spring:message> you can reference an externalized message in your JSP and have the actual message rendered when the view is rendered.

Figure 14.5. The <spring:message> tag resolves messages from an external message properties file.

For example, listing 14.2 shows the new version of addRant.jsp, which uses the <spring:message> tag to render the field labels.

Example 14.2. Using externalized messages in addRant.jsp

To use the <spring:message> tag, you must import the spring tag library by using the following <%@taglib %> directive on every JSP that will use the tag:

<%@taglib prefix="spring"
    uri="http://www.springframework.org/tags"%>

With this directive in place, you can reference externalized messages by passing the message code to <spring:message>’s code attribute.

Okay... so, <spring:message> renders externalized messages, but where exactly are these messages externalized?

Spring’s ResourceBundleMessageSource works hand in hand with <spring:message> to resolve message codes to actual message values. The following <bean> declaration registers a ResourceBundleMessageSource in roadrantzservlet.xml:

<bean id="messageSource" class=
    "org.springframework.context.support.
         ResourceBundleMessageSource">
  <property name="basename" value="messages" />
</bean>

The first thing to point out about this <bean> is its id. It’s important to name the bean messageSource because that’s the name Spring will use to look for a message source.

As for the location of the message properties file, this is determined by the basename property. Here the base name is set to messages. This means that, by default, externalized messages will be retrieved from a file called messages.properties in the classpath. The following excerpt from /WEB-INF/classes/messages.properties shows how the messages in addRant.jsp are defined:

field.state=State:
field.plateNumber=Plate #:
field.rantText=Rant text:
title.addRant=Add a rant

These same properties could also be referenced by using <spring:message> on another JSP. If so then the text rendered by these messages will be consistent across all JSPs in the application. Moreover, changes to the values in messages.properties will be applied universally to all JSPs in the application.

Another benefit of using externalized messages is that it makes it simple to internationalize your application. For example, consider the following excerpt from /WEB-INF/classes/messages_es.properties:

field.state=Estado:
field.plateNumber=Numero del plato:
field.rantText=Despotrique texto:

This version of the properties file provides a Spanish flair to the RoadRantz application. If the user has their locale and language settings set for Spanish, the message properties will be resolved from messages_es.properties instead of the default messages.properties file and our Spanish-speaking users will be able to rant about traffic to su contenido de corazón.

Displaying errors

In chapter 13, you saw how to validate command objects using either Spring’s Validator interface (listing 13.5) or Commons Validator (listing 13.6). In those examples, a failed validation resulted in a message code being placed in the Errors object. But the actual error message resides in an external properties file.

Where <spring:message> renders general messages from an external properties file, <form:errors> renders externalized error messages based on error codes in the Errors object. The newest form of addRant.jsp in listing 14.3 shows how to use <form:errors> to render validation errors.

Example 14.3. Using externalized messages in addRant.jsp

When a field’s value is rejected during validation, an error message code is associated with the field in the Errors object. The <form:errors> tag looks for any error message codes associated with the field (which is specified with the path attribute) and then tries to resolve those messages from an external properties file.

We could put the error messages in the same messages file as the other externalized messages. But let’s keep things neat and tidy and place the error messages in their own properties file. To do this, we’ll tweak the messageSource bean to have multiple base names instead of a single base name:

<bean id="messageSource" class=
    "org.springframework.context.support.
         ResourceBundleMessageSource">
  <property name="basenames">
    <list>
      <value>messages</value>
      <value>errors</value>
    </list>
  </property>
</bean>

The following excerpt from /WEB-INF/classes/errors.properties shows the error messages that could result from problems with validation when adding a rant:

required.state=State is required.
required.plateNumber=License plate number is required.
required.rantText=Rant text is required.
invalid.plateNumber={0} is an invalid license plate number.

Just like other externalized messages, error messages can also be internationalized. For example, here’s the Spanish version of the errors file (/WEB-INF/ classes/errors_es.properties):

required.state=El estado se requiere.
required.plateNumber=El numero de la matricula se requiere.
required.rantText=El texto de lenguaje declamatorio se requiere.
invalid.plateNumber={0} es un numero invalido de matricula.

Now we’ve created a few JSP pages that define the view of the RoadRantz application. Up until now, we’ve kept the look and feel of the RoadRantz application very generic. We’ve focused on how to write Spring-enabled web applications with little regard for aesthetics. But how an application looks often dictates its success. To make the RoadRantz application visually appealing, it needs to be placed in a template that frames its generic pages with eye-popping graphics. Let’s see how to use Jakarta Tiles, a page layout framework, with Spring MVC to dress up the application’s appearance.

Laying out pages with Tiles

Jakarta Tiles is a framework for laying out pieces of a page in a template. Although originally created as part of Jakarta Struts, Tiles can be used even when the MVC framework isn’t Struts. For our purposes, we’re going to use Tiles alongside Spring’s MVC framework.

Although we’ll give a brief overview of working with Tiles, we will not go into too many details of how Tiles works. For more information on Tiles, we recommend that you read Struts in Action (Manning, 2002).

Tile views

The template for the RoadRantz application will be kept reasonably simple for the sake of brevity. It will have a header where the company logo and motto will be displayed, a footer where contact and copyright information will be displayed, and a larger area in the middle where the main content will be displayed. Figure 14.6 shows a box diagram of how the template will be laid out.

Figure 14.6. The RoadRantz application uses Tiles for page layout. To keep things simple, there are only three tiles: header, content, and footer.

The template for the RoadRantz application is defined in rantzTemplate.jsp (listing 14.4).

Example 14.4. Using Tiles to put a skin on RoadRantz

rantzTemplate.jsp uses the Tiles <tiles:insert> JSP tag to include content into this template. The details of where the included content originates are specified in the Tiles definition file. A Tiles definition file is XML that describes how to fill in the template. The file can be named anything you want, but for the purposes of the RoadRantz application, roadrantz-tiles.xml seems appropriate.

The following excerpt from roadrantz-tiles.xml outlines the main template (called template), filling in each of its components with some default values:

<tiles-definitions>
  <definition name="template"
      page="/WEB-INF/jsp/rantzTemplate.jsp">
    <put name="title" value="RoadRantz"/>
    <put name="header" value="/WEB-INF/jsp/header.jsp"/>
    <put name="content"
        value="/WEB-INF/jsp/defaultContentPage.jsp"/>
    <put name="footer" value="/WEB-INF/jsp/footer.jsp"/>
  </definition>
...
</tiles-definitions>

Here, the header and footer components are given the path to JSP files that define how the header and footer should look. When Tiles builds a page, it will replace the <tiles:insert> tags named header and footer with the output resulting from header.jsp and footer.jsp, respectively.

As for the title and content components, they are just given some dummy values. Because it’s just a template, you’ll never view the template page directly. Instead, when you view another page that is based on template, the dummy values for title and content will be overridden with real values.

The homepage is a typical example of the pages in the application that will be based on template. It is defined in roadrantz-tiles.xml like this:

<definition name="home" extends="template">
  <put name="title" value="Welcome to RoadRantz" />
  <put name="content" value="/WEB-INF/jsp/home.jsp"/>
</definition>

Extending template ensures that the homepage will inherit all of its component definitions. However, we want each page to have a unique title and certainly need each page to have unique content. So, we have overridden the template’s title component with “Welcome to RoadRantz” so that the page will have an appropriate title in the browser’s title bar. And the main content for the homepage is defined by home.jsp, so the content component is overridden to be /WEB-INF/ jsp/home.jsp.

So far, this is a typical Tiles-based application. You’ve seen nothing Spring-specific yet. But now we’re ready to integrate Tiles into Spring MVC by performing these two steps:

  • Configuring a TilesConfigurer to load the Tiles definition file

  • Declaring a Spring MVC view resolver to resolve logical view names to Tiles definitions

Configuring Tiles

The first step in integrating Tiles into Spring MVC is to tell Spring to load the Tiles configuration file(s). Spring comes with TilesConfigurer, a bean that loads Tiles configuration files and makes them available for rendering Tiles views. To load the Tiles configuration into Spring, declare a TilesConfigurer instance as follows:

<bean id="tilesConfigurer" class="org.springframework.
        web.servlet.view.tiles.TilesConfigurer">

  <property name="definitions">
    <list>
      <value>/WEB-INF/roadrantz-tiles.xml</value>
    </list>
  </property>
</bean>

The definitions property is given a list of Tiles definition files to load. But in the case of the RoadRantz application, there’s only one definition file: roadrantztiles.xml.

Resolving Tiles views

The second and final step to integrate Tiles into Spring MVC is to configure a view resolver that will send the user to a page defined by Tiles. InternalResourceViewResolver will do the trick:

<bean id="viewResolver"
    class="org.springframework.web.servlet.
        view.InternalResourceViewResolver">
  <property name="viewClass"
      value="org.springframework.web.servlet.view.tiles.
           TilesJstlView"/>
</bean>

Normally, InternalResourceViewResolver resolves logical views from resources (typically JSPs) in the web application. But for Tiles, you’ll need it to resolve views as definitions in a Tiles definition file. For that, the viewClass property has been set to use a TilesJstlView.

There are actually two view classes to choose from when working with Tiles: TilesView and TilesJstlView. The difference is that TilesJstlView will place localization information into the request for JSTL pages. Even though we’re using JSTL, we’re not taking advantage of JSTL’s support for internationalization. Nevertheless, we may choose to internationalize RoadRantz in the future, so there’s no harm in using TilesJstlView. If you’re not using JSTL-based views, you should use TilesView instead.

With InternalResourceViewResolver configured with TilesJstlView (or TilesView), the rules have changed. Instead of trying to resolve a view by prefixing and suffixing the logical view name, now InternalResourceViewResolver will resolve views by looking in the Tiles definition file(s). If a <definition> in the Tiles definition file has a same name that matches the logical view name, it will be used to render the page to the user.

For example, consider how the resulting view of HomeController is resolved. When finished, HomeController returns the following ModelAndView:

return new ModelAndView("home", "rantz", recentRants);

The logical view name is home, so TilesView will look for the view definition in the Tiles configuration. In this case, it finds the <definition> named home. Since home is based on template, the resulting HTML page will be structured like rantzTemplate.jsp (listing 14.4), but will have its title set to “Welcome to RoadRantz” and its content will be derived from the JSP in /WEB-INF/jsp/home.jsp.

Nothing about the RoadRantz controller classes will need to change to support Tiles. That’s because the page definitions in roadrantz-tiles.xml are cleverly named to be the same as the logical view names returned by all the controllers.

Creating Tile controllers

Now let’s make the RoadRantz application a bit more personable. As it exists, the header is somewhat plain and boring. To make it more interesting, we’d like to put a message in the header that indicates the number of rants that have been posted for the current day.

One way to accomplish this is to place the following code in each of the controllers:

modelMap.add("rantsToday",
      rantService.getRantsForDay(new Date()).size();

This would place the number of rants for today into the request so that it can be displayed in header.jsp like this:

Helping <b>${rantsToday}</b> motorists deal
     with road rage today!

But for this to work on all pages, you’d need to repeat the rant count code in all of the application’s controller classes. There are options to eliminate the redundant code, including creating a common base controller for all other controllers to subclass or putting this functionality in a utility class used by all controllers. But all of these options add complexity that you’d like to avoid.

A unique feature of Tiles is that each component on a page can have its own controller. Be aware that this is a Tiles-specific controller, not to be confused with a Spring MVC controller. Unfortunately, the word “controller” has been overloaded here, which can lead to some confusion. As we saw in chapter 13, Spring MVC controllers process a request on behalf of DispatcherServlet. Tiles controllers, on the other hand, can be associated with Tiles components so that each component can perform functionality specific to that component.

To include the rant count message on each page of the RoadRantz application, we will need to build a controller for the header component. HeaderTileController (listing 14.5) retrieves the number of rants that have been posted for the current day and places that information into the component context for display in the banner.

Example 14.5. Counting rants for the day using a Tiles controller

HeaderTileController extends ComponentControllerSupport, a Spring-specific extension of Tiles’s ControllerSupport class. ComponentControllerSupport makes the Spring application context available via its getApplicationContext() method. This is perfect, because HeaderTileController is going to need the Spring application context to look up the rantService bean.

HeaderTileController makes a call to getApplicationContext() and uses the application context to look up a reference to the rantService bean so that it can find out how many rants have been posted today. Once it has the information, it places it into the Tiles component context so that the header component can display it.

The only thing left to do is to associate this component controller with the header component. Revisiting the header definition in roadrantz-tiles.xml, extract the header definition and set its controllerClass attribute to point to the HeaderTileController:

<definition name=".header" page="/WEB-INF/jsp/header.jsp"
    controllerClass="com.roadrantz.tiles.HeaderTileController" />

<definition name="template" page="/WEB-INF/jsp/rantzTemplate.jsp">
  <put name="title" value="RoadRantz"/>
  <put name="header" value=".header"/>
  <put name="content" value="/WEB-INF/jsp/defaultContentPage.jsp"/>
  <put name="footer" value="/WEB-INF/jsp/footer.jsp"/>
</definition>

Now, as the page is constructed, Tiles will use HeaderTileController to set up the component context prior to displaying the header component. In header.jsp, the rant count can be displayed like this:

Helping <b><tiles:getAsString name="rantsToday"/></b> motorists deal
with road rage today!

At this point, we’ve developed most of the view layer of the RoadRantz application using JSP and Tiles. Now let’s do it again!

JSP is the standard way of building the web layer in Java-based web applications. But, as it turns out, not everybody’s a fan of JSP. Many believe that it’s bloated and unnecessarily complex. If you’re a JSP dissenter then read on... in the next section, we’re going to look at how Spring MVC can use JSP alternatives such as Velocity and FreeMarker.

Working with JSP alternatives

In October 1908, Henry Ford rolled out the “car for the great multitude”: the Model-T Ford. The sticker price: $950. To speed assembly, all Model-Ts were painted black because black paint dried the fastest. Legend quotes Henry Ford as saying, “Any customer can have a car painted any color that he wants so long as it is black.”

Automobiles have come a long way since 1908. In addition to a dizzying selection of body styles, you also get to choose among several options, including the type of radio/CD player, whether or not you get power windows and door locks, and cloth versus leather upholstery. And nowadays any customer can have any color that they want—including, but not limited to, black.

Up to now we’ve used JSP to define the view of the RoadRantz application. But unlike Henry Ford’s black paint, JSP isn’t the only choice when it comes to the view layer of your application. Two other popular templating engines are Velocity and FreeMarker. Let’s have a look at how to use these templating engines with Spring MVC.

Using Velocity templates

Velocity is an easy-to-use template language for Java applications. Velocity templates contain no Java code, thus making them easy to understand by nondevelopers and developers alike. From Velocity’s user guide: “Velocity separates Java code from the web pages, making the web site more maintainable over the long run and providing a viable alternative to JavaServer Pages.”

Aside from JSP, Velocity is probably the most popular template language for web-based applications. So it is highly likely that you may want to develop your Spring-based application using Velocity as the view-layer technology. Fortunately, Spring supports Velocity as a view-layer templating language for Spring MVC.

Let’s see how to use Velocity with Spring MVC by reimplementing the view layer of the RoadRantz application so that it’s based on Velocity.

Defining the Velocity view

Suppose that you’ve chosen to use Velocity, instead of JSP, as the view-layer technology for the RoadRantz application. In listing 11.2, we created a JSP version of the RoadRantz homepage. But now let’s look at home.vm (listing 14.6), a Velocity template that renders the home page.

Example 14.6. A Velocity version of the RoadRantz home page

Not much is different between the Velocity template and the original JSP. But one thing you’ll notice about this template is that there are no template tags. That’s because Velocity isn’t tag-based like JSP. Instead, Velocity employs its own language—known as Velocity Template Language (VTL)—for control flow and other directives. In home.vm, the #foreach directive is used to loop through a list of rants, displaying rant details with each iteration.

Despite this basic difference between Velocity and JSP, you’ll find that Velocity’s expression language resembles that of JSP. In fact, JSP merely followed in Velocity’s footsteps when using the ${} notation in its own expression language.

This template demonstrates only a fraction of what you can do with Velocity. To learn more, visit the Velocity homepage at http://jakarta.apache.org/velocity.

Now that the template has been created, you’ll need to configure Spring to use Velocity templates for the view in MVC applications.

Configuring the Velocity engine

The first thing to configure is the Velocity engine itself. To do this, declare a VelocityConfigurer bean in the Spring configuration file, as follows:

<bean id="velocityConfigurer" class=
    "org.springframework.web.servlet.view.velocity.
         VelocityConfigurer">
  <property name="resourceLoaderPath" value="WEB-INF/velocity/" />
</bean>

VelocityConfigurer sets up the Velocity engine in Spring. Here, we’ve told Velocity where to find its templates by setting the resourceLoaderPath property. I recommend placing the templates in a directory underneath the WEB-INF directory so that the templates can’t be accessed directly.

If you’re familiar with Velocity, you already know that you can configure the behavior of Velocity using a velocity.properties file. But with VelocityConfigurer, you can also set those configuration details by setting the velocityProperties property. For example, consider the following declaration of VelocityConfigurer:

<bean id="velocityConfigurer" class=
    "org.springframework.web.servlet.view.velocity.
         VelocityConfigurer">
  <property name="resourceLoaderPath" value="WEB-INF/velocity/" />
  <property name="velocityProperties">
    <props>
      <prop key="directive.foreach.counter.name">loopCounter</prop>
      <prop key="directive.foreach.counter.initial.value">0</prop>
    </props>
  </property>
</bean>

Here we’ve configured the Velocity engine, changing the behavior of the #foreach loop. By default, Velocity’s #foreach loop maintains a counter variable called $velocityCount that starts with a value of 1 on the first iteration of the loop. But here we’ve set the directive.foreach.counter.name property to loopCounter so that the loop counter can be referred to with $loopCounter. We’ve also made the loop counter zero-based by setting the directive.foreach.counter.initial.value property to 0. (For more on Velocity configuration properties, refer to Velocity’s developer guide at http://jakarta.apache.org/velocity/developer-guide.html.)

Resolving Velocity views

The final thing you must do to use Velocity template views is to configure a view resolver. Specifically, declare a VelocityViewResolver bean in the context configuration file as follows:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
     velocity.VelocityViewResolver">
  <property name="suffix" value=".vm" />
</bean>

VelocityViewResolver is to Velocity what InternalResourceViewResolver is to JSP. Just like InternalResourceViewResolver, it has prefix and suffix properties that it uses with the view’s logical name to construct a path to the template. Here, only the suffix property is set with the .vm extension. No prefix is required because the path to the template directory has already been set through VelocityConfigurer’s resourceLoaderPath property.

Note

Here the bean’s ID is set to viewResolver. This is significant when DispatcherServlet is not configured to detect all view resolvers. If you are using multiple view resolvers, you’ll probably need to change the ID to something more appropriate (and unique), such as velocityViewResolver.

At this point, your application is ready to render views based on Velocity templates. All you need to do is return a ModelAndView object that references the view by its logical name. In the case of HomeController, there’s nothing to do because it already returns a ModelAndView as follows:

return new ModelAndView("home", "rants", recentRants);

The view’s logical name is home. When the view is resolved, home will be suffixed with .vm to create the template name of home.vm. VelocityViewResolver will find this template in the WEB-INF/velocity/ path.

As for the rants model object, it will be exposed in the Velocity template as a Velocity property. In listing 14.6, it is the collection that the #foreach directive iterates over.

Formatting dates and numbers

Although the application is now set to render Velocity views, we have a few loose ends to tie up. If you compare home.vm from listing 14.6 to home.jsp, you’ll notice that home.vm doesn’t apply the same formatting to the rant’s posted date as in home.jsp. In home.jsp, the posted date is displayed in “full” format. For home.vm to be complete, you’ll need to tweak it to properly format the date.

The VTL doesn’t directly support date formatting. However, Velocity does have tools for date and number formatting. To enable these tools, you’ll need to tell the VelocityViewResolver the name of the attributes to expose them through. These attributes are specified through VelocityViewResolver’s dateToolAttribute and numberToolAttribute properties:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
     velocity.VelocityViewResolver">
  <property name="suffix" value=".vm" />
  <property name="dateToolAttribute">
    <value>dateTool</value>
  </property>
  <property name="numberToolAttribute">
    <value>numberTool</value>
  </property>
</bean>

Here, the date tool is assigned to a $dateTool attribute in Velocity. So, to format the rant’s posted date, all you need to do is reference the date through the number tool’s format() function. For example:

$dateTool.format("FULL", rant.postedDate)

The first parameter is the pattern string. This string adheres to the same syntax as that of java.text.SimpleDateFormat. In addition, you can specify one of the standard java.text.DateFormat patterns by setting the pattern string to one of FULL, LONG, MEDIUM, SHORT, or DEFAULT. Here we’ve set it to FULL to indicate the full date format.

As mentioned, the $numberTool attribute provides a tool for formatting numbers in the Velocity template. Refer to Velocity’s documentation for more information on this tool’s and the date tool’s functions.

Exposing request and session attributes

Although most data that needs to be displayed in a Velocity template can be passed to the view through the model Map given to the ModelAndView object, there are times when you may wish to display attributes that are in the servlet’s request or session. For example, if a user is logged into the application, that user’s information may be carried in the servlet session.

It would be clumsy to copy attributes out of the request or session into the model Map in each controller. Fortunately, VelocityViewResolver can copy the attributes into the model for you. The exposeRequestAttributes and exposeSessionAttributes properties tell VelocityViewResolver whether or not you want servlet request and session attributes copied into the model. For example:

<bean id="viewResolver" class="org.springframework.
        web.servlet.view.velocity.VelocityViewResolver">
...
  <property name="exposeRequestAttributes">
    <value>true</value>
  </property>
  <property name="exposeSessionAttributes">
    <value>true</value>
  </property>
</bean>

By default, both of these properties are false. But here we’ve set them both to true so that both request and session attributes will be copied into the model and therefore will be visible in the Velocity template.

Binding form fields in Velocity

Earlier in this chapter, you saw how to use Spring’s JSP tag libraries to bind form fields to properties of a command object and to display error messages. Although Velocity doesn’t have tags, Spring does provide a set of Velocity macros that provide equivalent functionality to Spring’s JSP tag libraries. Table 14.2 lists the Velocity macros that come with Spring.

Table 14.2. Spring MVC provides a handy collection of Velocity macros that bind form fields to a controller’s command object.

Macro

Purpose

#springFormCheckboxes(path options separator attributes)

Renders a set of check boxes. Checks the box(es) whose value matches that of a command object property.

#springFormHiddenInput(path attributes)

Renders a hidden field bound to a command object property.

#springFormInput(path attributes)

Renders a text field bound to a command object property.

#springFormMultiSelect(path options attributes)

Renders a selection list allowing multiple selection. Selected values are bound to a command object property.

#springFormPasswordInput(path attributes)

Renders a password field bound to a command object property.

#springFormRadioButtons(path options separator attributes)

Renders a set of radio buttons where the selected radio button is bound to a command object property.

#springFormSingleSelect(path options attributes)

Renders a selection list, allowing only a single entry to be selected. The selected value is bound to a command object property.

#springFormTextarea(path attributes)

Renders a text area bound to a command object property.

#springMessage(messageCode)

Renders a message externalized in a resource bundle.

#springMessageText(messageCode text)

Renders a message externalized in a resource bundle, with a default value if the message isn’t found in the resource bundle.

#springShowErrors(separator class/style)

Renders validation errors.

#springUrl(relativeUrl)

Renders an absolute URL given a relative URL.

Most of the macros in table 14.2 are form-binding macros. That is, they render HTML form elements whose values are bound to a property of a command object. The specific property that they’re bound to is specified in the first parameter (called path in the table). Most of the macros also have a parameter that allows you to specify additional attributes to be placed on the rendered HTML elements (e.g., length='20').

As an illustration of how to use Spring’s Velocity macros, let’s revisit the addRant view. Earlier in this chapter we defined that view as a JSP. However, listing 14.7 shows addRant.vm, the Velocity version of that view.

Example 14.7. Adding a rant through a Velocity template

<html>
  <head>
      <title>#springMessage("title.addRant")</title>
  </head>

    <body>
    <h2>#springMessage("title.addRant")</h2>
    <form method="POST" action="addRant.htm">
      <b>#springMessage("field.state")</b>#springFormInput(
              "rant.vehicle.state" "")<br/>
      <b>#springMessage("field.plateNumber") </b>#springFormInput(
              "rant.vehicle.plateNumber" "")<br/>
      #springMessage("field.rantText")
      #springFormTextarea("rant.rantText" "rows='5' cols='50'")
      <input type="submit"/>
    </form>
  </body>
</html>

For the state and plate number fields, we’re using #springFormInput bound to rant.vehicle.state and rant.vehicle.plateNumber, respectively. This means that when the form is submitted, the values will be bound to the state and plateNumber properties of the vehicle property of the command object (rant). In both cases, there’s no need to set additional attributes on the HTML, so the second parameter is empty. The resulting HTML for these two fields looks like this:

<b>State: </b><input type="text" id="vehicle.state"
      name="vehicle.state" value="" /> <br/>
<b>Plate #: </b><input type="text" id="vehicle.plateNumber"
      name="vehicle.plateNumber" value="" /> <br/>

For the text area where the user enters the rant text, an HTML <textarea> is in order. The #springFormTextarea macro renders a <textarea> that is bound to rant.rantText. When the form is submitted, the value will be bound to the rantText property of the command object. In this case, however, we need to set the size of the <textarea>, so we’re passing additional attributes in the second parameter. The HTML for the text area is as follows:

<textarea id="rantText" name="rantText"
     rows='5' cols='50'></textarea>

To be able to use the Spring macros in your templates, you’ll need to enable the macro using the exposeSpringMacroHelpers property of VelocityViewResolver:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
     velocity.VelocityViewResolver">
  <property name="suffix" value=".vm" />
  <property name="exposeSpringMacroHelpers" value="true" />
</bean>

By setting the exposeSpringMacroHelpers property to true, you’ll ensure that your Velocity templates will have access to Spring’s macros for Velocity.

Although Velocity is a widely used alternative to JSP, it is not the only alternate templating option available. FreeMarker is another well-known template language that aims to replace JSP in the view layer of MVC applications. Let’s see how to plug FreeMarker into your Spring MVC application.

Working with FreeMarker

FreeMarker is slightly more complex than Velocity, but only as the result of being slightly more powerful. FreeMarker comes with built-in support for several useful tasks, such as date and number formatting and white-space removal. These features are only available in Velocity through add-on tools.

You’ll soon see how using FreeMarker with Spring MVC isn’t much different than using Velocity with Spring MVC. But first things first—let’s start by writing a FreeMarker template to be used in the RoadRantz application.

Constructing a FreeMarker view

Suppose that after further consideration, you decide that FreeMarker templates are more suited to your tastes than Velocity. So, instead of developing the view layer of the RoadRantz application using Velocity, you’d like to plug FreeMarker into Spring MVC. Revisiting the home page, you produce home.ftl (listing 14.8), the FreeMarker template that renders the home page.

Example 14.8. A FreeMarker rendition of the RoadRantz homepage

<html>
  <head><title>Rantz</title></head>

  <body>
    <h2>Rantz:</h2>

    <a href="addRant.htm">Add rant</a><br/>
    <a href="register.htm">Register new motorist</a><br/>
    <ul>
    <#list rants as rant>
    <li>${rant.vehicle.state}/
        ${rant.vehicle.plateNumber} --
        ${rant.rantText}</li>
    </#list>
    </ul>
  </body>
</html>

You’ll notice that the FreeMarker version of the homepage isn’t dramatically different from the Velocity version from listing 14.6. Just as with Velocity (and JSP, for that matter), the ${} notation is used as an expression language to display attribute values.

The home.ftl template barely scratches the surface of FreeMarker’s capabilities. For more information on FreeMarker, visit the FreeMarker home page at http://freemarker.sourceforge.net.

Configuring the FreeMarker engine

Just like Velocity, FreeMarker’s engine must be configured in order for Spring’s MVC to use FreeMarker templates for rendering views. Declare a FreeMarkerConfigurer in the context configuration file like this:

<bean id="freemarkerConfig"
    class="org.springframework.web.servlet.view.
         freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="WEB-INF/freemarker/" />
</bean>

FreeMarkerConfigurer is to FreeMarker as VelocityConfigurer is to Velocity. You use it to configure the FreeMarker engine. As a minimum, you must tell FreeMarker where to find the templates. You do this by setting the templateLoaderPath property (here set to look for templates in WEB-INF/freemarker/).

You can configure additional FreeMarker settings by setting them as properties through the freemarkerSettings property. For example, FreeMarker reloads and reparses templates if five seconds (by default) have elapsed since the template was last checked for updates. But checking for template changes can be time consuming. If your application is in production and you don’t expect the template to change very often, you may want to stretch the update delay to an hour or more.

To do this, modify FreeMarker’s template_update_delay setting through the freemarkerSettings property. For example:

<bean id="freemarkerConfig"
    class="org.springframework.web.servlet.view.
         freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath" value="WEB-INF/freemarker/" />
  <property name="freemarkerSettings">
    <props>
      <prop key="template_update_delay">3600</prop>
    </props>
  </property>
</bean>

Notice that as with VelocityConfigurer’s velocityProperties property, the freemarkerSettings property takes a <props> element. In this case, the only <prop> is one to set the template_update_delay setting to 3600 (seconds) so that the template will only be checked for updates after an hour has passed.

Resolving FreeMarker views

The next thing you’ll need to do is to declare a view resolver for FreeMarker:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
         freemarker.FreeMarkerViewResolver">
  <property name="suffix" value=".ftl" />
</bean>

FreeMarkerViewResolver works just like VelocityViewResolver and InternalResourceViewResolver. Template resources are resolved by prefixing a view’s logical name with the value of the prefix property and are suffixed with the value of the suffix property. Again, just as with VelocityViewResolver, we’ve only set the suffix property because the template path is already defined in FreeMarkerConfigurer’s templateLoaderPath property.

Exposing request and session attributes

In section 14.4.1, you saw how to tell VelocityViewResolver to copy request and/or session attributes into the model map so that they’ll be available as variables in the template. You can do the same thing with FreeMarkerViewResolver to expose request and session attributes as variables in a FreeMarker template. To do so, set either the exposeRequestAttributes or exposeSessionAttributes property (or both) to true:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
         freemarker.FreeMarkerViewResolver">
...
  <property name="exposeRequestAttributes">
    <value>true</value>
  </property>
  <property name="exposeSessionAttributes">
    <value>true</value>
  </property>
</bean>

Here, both properties have been set to true. As a result, both request and session attributes will be copied into the template’s set of attributes and will be available to display using FreeMarker’s expression language.

Binding form fields in FreeMarker

One last thing you may want to do with FreeMarker is to bind form fields to command properties. You’ve already seen how to use JSP binding tags and Velocity binding macros in this chapter. Not to be unfair, Spring provides a set of FreeMarker macros that mirror the functionality of the Velocity macros. The FreeMarker macros are listed in table 14.3.

Table 14.3. Spring comes with a set of FreeMarker macros useful for binding form fields to a controller’s command object.

Macro

Purpose

<@spring.formCheckboxes path, options, separator, attributes />

Renders a set of check boxes. Checks the box(es) whose value matches that of a command object property.

<@spring.formHiddenInput path, attributes />

Renders a hidden field bound to a command object property.

<@spring.formInput path, attributes, fieldType />

Renders a text field bound to a command object property.

<@spring.formMultiSelect path, options, attributes />

Renders a selection list allowing multiple selection. Selected values are bound to a command object property.

<@spring.formPasswordInput path, attributes />

Renders a password field bound to a command object property.

<@spring.formRadioButtons path, options, separator, attributes />

Renders a set of radio buttons where the selected radio button is bound to a command object property.

<@spring.formSingleSelect path, options, attributes />

Renders a selection list allowing only a single entry to be selected. The selected value is bound to a command object property.

<@spring.formTextarea path, attributes />

Renders a text area bound to a command object property.

<@spring.message messageCode />

Render a message externalized in a resource bundle.

<@spring.messageText messageCode, text />

Renders a message externalized in a resource bundle, with a default value if the message isn’t found in the resource bundle.

<@spring.showErrors separator, class/style/>

Renders validation errors.

<@spring.url relativeUrl />

Renders an absolute URL given a relative URL.

Except for a few minor syntactical differences, the FreeMarker macros are identical to the Velocity macros. Listing 14.9 shows them in action in addRant.ftl, the FreeMarker version of the addRant view.

Example 14.9. Entering rants using FreeMarker templates

You may have noticed that listing 14.9 is very similar to the Velocity macro in listing 14.7. But there are two subtle differences. Instead of #springFormInput, the FreeMarker version uses <@spring.formInput>. And instead of #springFormTextarea, <@spring.formTextarea> is the way to go in FreeMarker.

Also, unlike Velocity in which the macros were automatically available, FreeMarker macros must be imported. The first line of addRant.ftl imports the Spring form-binding macros.

Just as with Spring’s Velocity, macros, in order to use these macros you must enable the FreeMarker macros by setting the exposeMacroHelpers property of FreeMarkerViewResolver to true:

<bean id="viewResolver"
    class="org.springframework.web.servlet.view.
         freemarker.FreeMarkerViewResolver">
  <property name="suffix" value=".ftl" />
  <property name="exposeSpringMacroHelpers" value="true" />
</bean>

Now you have three capable templating options for building web applications in Spring. But all of these options produce HTML. Sometimes HTML isn’t enough and you need something a bit richer. Let’s switch gears and look at how to generate non-HTML output.

Generating non-HTML output

Up to now, the output produced by the RoadRantz web layer has been HTML based. Indeed, HTML is the typical way to display information on the Web. But HTML doesn’t always lend itself to the information being presented.

For example, if the data you are presenting is in tabular format, it may be preferable to present information in the form of a spreadsheet. Spreadsheets may also be useful if you want to enable the users of your application to manipulate the data being presented.

Or perhaps you’d like precise control over how a document is formatted. Formatting HTML documents precisely is virtually impossible, especially when viewed across various browser implementations. But Adobe’s Portable Document Format (PDF) has become the de facto standard for producing documents with precise formatting that are viewable on many different platforms.

Spreadsheets and PDF files are commonly static files. But Spring provides view classes that enable you to dynamically create spreadsheets and PDF documents that are based on your application’s data.

Let’s explore Spring’s support for non-HTML views, starting with dynamic generation of Excel spreadsheets.

Producing Excel spreadsheets

If you’ve been developing software for any considerable length of time, you’ve probably noticed that Microsoft Excel spreadsheets are the lifeblood of business. For good or bad, businesspeople love their spreadsheets. They communicate, analyze, chart, plan, and budget using spreadsheets. If it weren’t for Excel, many businesses would come to a grinding halt.

With such a fondness in the workplace for spreadsheets, it’s important to be able to produce spreadsheets from your applications. And there’s good news: Spring comes with AbstractExcelView, a custom view suitable for producing spreadsheets.

Although the data presented in RoadRantz is hardly mission-critical business data, we can only assume that many motorists on the road are businesspeople. And it’s quite possible that while driving they are thinking about facts and figures (and spreadsheets) and aren’t driving well. Since these motorists have such a tight connection with spreadsheets, it may prove worthwhile to provide those businesspeople with a list of their vehicle’s rants in spreadsheet form.

Spring supports the generation of Excel output through AbstractExcelView. As its name implies, this is an abstract class that you must subclass to give the details of the spreadsheet.

As an example of how to subclass AbstractExcelView, consider RantExcelView (listing 14.10). This view implementation produces a list of rants within an Excel spreadsheet.

Example 14.10. Listing rants in a spreadsheet

There’s a lot going on in RantExcelView, but the only method required by AbstractExcelView is buildExcelDocument(). This method is given a Map of model data to use when constructing the spreadsheet. It is also given an HttpServletRequest and HttpServletResponse, in case information is required that isn’t available in the model data. Only the model data is used in RantExcelView, however.

buildExcelDocument() is also provided with an HSSFWorkbook. HSSFWorkbook is a component of Jakarta POI that represents an Excel workbook.[3] Implementing a custom Excel view in Spring MVC is simply a matter of using POI’s API to render model data in a workbook. In RantExcelView, the list of rants is extracted from the model data and is iterated over to add rows to the spreadsheet.

To make RantExcelView available to Spring MVC, we need to register it with either ResourceBundleViewResolver or XmlViewResolver. Since we’re using XmlViewResolver, the following entry in roadrantz-views.xml will do the trick:

<bean id="vehicleRants.xls"
      class="com.roadrantz.mvc.RantExcelView" />

Now all we need to demonstrate RantExcelView is a controller that places a list of rants into the model data. It just so happens that RantsForVehicleController already does everything we need. The only problem is that RantsForVehicleController is already being used to render HTML output. We’ll need to modify it a bit to be more flexible with regard to its view choices.

The first thing to do is to add a URL mapping for the Excel request. Add the following <prop> entry to the mappings property of the urlMapping bean:

<prop key="/rantsForVehicle.xls">
    rantsForVehicleController
</prop>

So, if DispatcherServlet receives a request for /rantsForVehicle.xls, it knows to dispatch the request to the rantsForVehicleController bean. This is the same controller that’s mapped to /rantsForVehicle.htm. But how will it know to use the Excel view instead of the JSP view?

The request’s URI provides a clue as to the type of view. The request URI already ends with htm for HTML requests. For Excel requests, we’ll map it to end with xls. The following getViewName() method extracts the extension of the URI and uses it to derive the view name:

private static final String BASE_VIEW_NAME = "vehicleRants";
private String getViewName(HttpServletRequest request) {
  String requestUri = request.getRequestURI();
  String extension = "." +
      requestUri.substring(requestUri.lastIndexOf("."));
  if("htm".equals(extension)) { extension=""; }
  return BASE_VIEW_NAME + extension;
}

If the URI ends with htm then it’s an HTML request and we’re going to let InternalResourceViewResolver resolve to a JSP view. Otherwise, the view name will be vehicleRants followed by the extension of the URI.

Next we need to modify the handle() method of RantsForVehicleController to use the getViewName() method when choosing a view:

protected ModelAndView handle(HttpServletRequest request,
    HttpServletResponse response, Object command,
    BindException errors) throws Exception {
...
  return new ModelAndView(getViewName(request), model);
}

There’s just one more thing needed to make this work. DispatcherServlet will never receive a request for /rantsForVehicle.xls because it is configured in web.xml to handle *.htm requests. We’ll need to configure another <servlet-mapping> as follows:

<servlet-mapping>
  <servlet-name>roadrantz</servlet-name>
  <url-pattern>*.xls</url-pattern>
</servlet-mapping>

Now DispatcherServlet will handle both *.htm and *.xls requests and the RoadRantz application is capable of producing Excel lists of rants.

The rant spreadsheet appeals to those businesspeople who are accustomed to working in Excel. But spreadsheets may seem intimidating to some people. For those users, a friendlier output is desirable. To make those users happy, let’s see how Spring supports rendering of PDF documents.

Generating PDF documents

PDF documents are commonly used on the Internet to depict information in a format that is both precise in layout and universal. Although Cascading Style Sheets (CSS) go a long way to provide professional layout capabilities to HTML, they have their limitations. Conversely, the contents of a PDF document can be laid out in virtually any arrangement.

Furthermore, CSS implementations vary across different browsers, whereas PDF documents are rendered identically in Adobe’s Acrobat Viewer, regardless of the platform.

Suppose that in addition to rendering a rant list in Excel, you’d like to offer a PDF version of the rant list. With PDF, you can dress up the output a bit and be certain that it will appear the same for all users.

Spring’s AbstractPdfView supports rendering of PDF documents as a view in Spring MVC. Much like AbstractExcelView, you’ll need to subclass AbstractPdfView and implement the buildPdfDocument() method to construct a PDF document.

RantPdfView (listing 14.11) is an example of a class that extends AbstractPdfView to produce a list of rants in PDF form.

Example 14.11. Generating a PDF report of rants

Like AbstractExcelView’s buildExcelDocument() method, the buildPdfDocument() method is provided with a Map of model data, along with an HttpServletRequest and HttpServletResponse. But it is also provided with a Document and a PdfWriter. These two classes are part of the iText PDF library (www.lowagie.com/iText) and are used to construct a PDF document. For more information on iText, I recommend iText in Action (Manning, 2006).

The Document object passed to buildPdfDocument() is an empty iText document waiting to be filled with content. In RantPdfView, the rant list is pulled from the model and used to construct a table, with one row per rant. Once all rants have been added to the table, the table is added to the Document.

To make RantPdfView available to Spring MVC, let’s add it to roadrantzviews.xml alongside RantExcelView:

<bean id="vehicleRants.pdf"
      class="com.roadrantz.mvc.RantPdfView" />

Now any controller that returns a ModelAndView whose view name is vehicleRants.pdf will have its view rendered by RantPdfView.

In section 14.5.1, we altered RantsForVehicleController to dynamically choose its view based on the request URI’s extension. No further changes need to be made to RantsForVehicleController to use RantPdfView. We just need to register a URL mapping so that DispatcherServlet will dispatch requests for /rantsForVehicle.pdf to RantsForVehicleController:

<prop key="/rantsForVehicle.pdf">
    rantsForVehicleController
</prop>

Also, as with Excel views, we need to create a <servlet-mapping> in web.xml that will direct *.pdf requests to DispatcherServlet:

<servlet-mapping>
  <servlet-name>roadrantz</servlet-name>
  <url-pattern>*.pdf</url-pattern>
</servlet-mapping>

Spring’s AbstractExcelView and AbstractPdfView make quick work of producing Excel and PDF documents. But what if you need to produce output that isn’t covered by Spring’s out-of-the-box solutions? Let’s look at how to develop custom view implementations for Spring MVC.

Developing custom views

Excel and PDF documents are great. But syndication is all the rage on the Internet. One of the requirements for the RoadRantz application is to syndicate a vehicle’s rants as a Rich Site Summary (RSS) feed.

RSS is an XML dialect that concisely describes website content so that it can be subscribed to. It’s often used to subscribe to newsfeeds such as Fox (www.foxnews.com/rss/index.html) and CNN (www.cnn.com/services/rss). And RSS feeds are the best way to stay caught up on your favorite weblogs (such as www.jroller.com/rss/habuma). RSS is a great way to keep RoadRantz users up-to-date on the latest rants that are being written about their vehicle.

Unfortunately, Spring doesn’t come prepackaged with RSS-producing view classes. Fear not, however. This presents us with an opportunity to develop a custom RSS view.

RantRssView (listing 14.12) is a view implementation that uses the Rome (https://rome.dev.java.net) utility to produce RSS output for a list of rants.

Example 14.12. Syndicating rants with RSS

RantRssView extends Spring’s AbstractView class. The only method that AbstractView requires RantRssView to implement is renderMergedOutputModel(). This method is given the Model object along with an HttpServletRequest and HttpServletResponse and is expected to render the output to the HttpServletResponse’s writer.

Here RantRssView uses Rome’s API to create a feed, populate it with rant entries (expected to be passed in the model), and then render the output.

Once again, RantsForVehicleController will be used to produce the list of rants for this view. For the RSS feed, we’ll map this controller to /rantsForVehicle.rss:

<prop key="/rantsForVehicle.rss">
    rantsForVehicleController
</prop>

Since the URI will end in rss, the view name returned from getViewName() will be vehicleRants.rss. The following entry in roadrantz-views.xml will help XmlViewResolver find the custom RSS view:

<bean id="vehicleRants.rss"
    class="com.roadrantz.mvc.RantRssView">
  <property name="title" value="RoadRantz" />
  <property name="description" value="RoadRantz.com" />
  <property name="author" value="RoadRantz.com" />
  <property name="link" value="http://www.roadrantz.com" />
</bean>

Notice that some of the feed details (title, description, author and link) are configured on the view using dependency injection.

Summary

A web application isn’t a web application unless it interacts with the user. In an MVC web application, the application interacts with the user through the view.

In the previous chapter, you learned how to handle web requests with controllers and to produce model data to be presented to the user. In this chapter you’ve seen several ways to render model data in the view layer.

HTML is the primary means of rendering information on the web. Views based on JSP, Velocity, or FreeMarker make simple work of dynamically producing HTML output. And Spring provides a rich selection of custom JSP tags and Velocity/FreeMarker macros for binding form input to command objects.

Once you’ve built a set of basic pages for your application using JSP, Velocity, or FreeMarker, you’ll want to adorn them with a visually pleasant template. For that, we’ve seen how TilesView and TilesJstlView help integrate Jakarta Tiles into the view of a Spring MVC application.

When HTML isn’t good enough, Spring steps up with built-in support for views that produce Excel spreadsheets and PDF documents. You’ve also seen that it’s possible to create custom views by implementing Spring’s View interface.

Bridging the controllers in chapter 11 with the views in this chapter are view resolvers. Spring offers several out-of-the-box view controllers from which to choose.

By now you’ve seen that Spring MVC maintains a loose coupling between request handling, controller implementations, and views. This is a powerful concept, allowing you to mix-‘n’-match different Spring MVC parts to build a web layer most appropriate for your application.

Coming up in the next chapter, we’re going to build on what we know about Spring MVC by looking at an exciting new extension to Spring MVC called Spring Web Flow. Spring Web Flow provides a new controller class for Spring MVC that enables you to define a navigational flow to your web application, where the application guides the user through a series of steps to achieve a certain goal.



[1] In case you’re wondering—InternalResourceViewResolver is the last in the chain because it will always resolve to a view. While the other view resolvers may not find a view for a given view name, InternalResourceViewResolver will always resolve to a view by using the prefix and suffix values (even if the actual view template doesn’t exist). Therefore, it is necessary for InternalResourceViewResolver to always be last or the other view resolvers won’t get a chance to resolve the view.

[2] In versions of Spring prior to 2.0, you would use the <spring:bind> tag to bind command object properties to form fields. But the <spring:bind> tag was awkward to use. Since the new <form:xxx> tags are so much better, the only mention of <spring:bind> will be in this footnote.

[3] The “HSSF” in HSSFWorkbook and other POI classes is an acronym for “Horrible SpreadSheet Format.” Apparently, the POI developers have formed an opinion of the Excel file format.