Since dynamic attributes were allowed in Spring 3, it raised the possibility to specify a type attribute on a number of the form tags. Where it makes sense (see below) that attribute is now rejected and reversely where it makes sense it is accepted. InputTag allows types other than "text" but rejects type="radio" or type="checkbox" since there is a good reason for those to be used only in conjunction with the appropriate form library tags. Other HTML input tags such as PasswordTag, HiddenInputTag, Checkbox(es)Tag and RadioBox(es)Tag check the dynamic attributes and reject them if they contain a type attribute since.
2644 lines
113 KiB
XML
2644 lines
113 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="view">
|
|
<title>View technologies</title>
|
|
|
|
<section id="view-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>One of the areas in which Spring excels is in the separation of view
|
|
technologies from the rest of the MVC framework. For example, deciding to
|
|
use Velocity or XSLT in place of an existing JSP is primarily a matter of
|
|
configuration. This chapter covers the major view technologies that work
|
|
with Spring and touches briefly on how to add new ones. This chapter
|
|
assumes you are already familiar with <xref linkend="mvc-viewresolver" />
|
|
which covers the basics of how views in general are coupled to the MVC
|
|
framework.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp">
|
|
<title>JSP & JSTL</title>
|
|
|
|
<para>Spring provides a couple of out-of-the-box solutions for JSP and
|
|
JSTL views. Using JSP or JSTL is done using a normal view resolver defined
|
|
in the <interfacename>WebApplicationContext</interfacename>. Furthermore,
|
|
of course you need to write some JSPs that will actually render the
|
|
view.</para>
|
|
|
|
<note>
|
|
<para>
|
|
Setting up your application to use JSTL is a common source of error,
|
|
mainly caused by confusion over the different servlet spec., JSP and JSTL
|
|
version numbers, what they mean and how to declare the taglibs correctly.
|
|
The article
|
|
<ulink url="http://www.mularien.com/blog/2008/04/24/how-to-reference-and-use-jstl-in-your-web-application/">
|
|
How to Reference and Use JSTL in your Web Application</ulink> provides a
|
|
useful guide to the common pitfalls and how to avoid them. Note that as of
|
|
Spring 3.0, the minimum supported servlet version is 2.4 (JSP 2.0 and JSTL 1.1),
|
|
which reduces the scope for confusion somewhat.
|
|
</para>
|
|
</note>
|
|
|
|
<section id="view-jsp-resolver">
|
|
<title>View resolvers</title>
|
|
|
|
<para>Just as with any other view technology you're integrating with
|
|
Spring, for JSPs you'll need a view resolver that will resolve your
|
|
views. The most commonly used view resolvers when developing with JSPs
|
|
are the <classname>InternalResourceViewResolver</classname> and the
|
|
<classname>ResourceBundleViewResolver</classname>. Both are declared in
|
|
the <interfacename>WebApplicationContext</interfacename>:</para>
|
|
|
|
<programlisting language="xml"><lineannotation><!-- the <classname>ResourceBundleViewResolver</classname> --></lineannotation>
|
|
<bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
|
|
<property name="basename" value="views"/>
|
|
</bean>
|
|
|
|
<lineannotation># And a sample properties file is uses (views.properties in WEB-INF/classes):</lineannotation>
|
|
welcome.(class)=org.springframework.web.servlet.view.JstlView
|
|
welcome.url=/WEB-INF/jsp/welcome.jsp
|
|
|
|
productList.(class)=org.springframework.web.servlet.view.JstlView
|
|
productList.url=/WEB-INF/jsp/productlist.jsp</programlisting>
|
|
|
|
<para>As you can see, the
|
|
<classname>ResourceBundleViewResolver</classname> needs a properties
|
|
file defining the view names mapped to 1) a class and 2) a URL. With a
|
|
<classname>ResourceBundleViewResolver</classname> you can mix different
|
|
types of views using only one resolver.</para>
|
|
|
|
<programlisting language="xml"><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></programlisting>
|
|
|
|
<para>The <classname>InternalResourceBundleViewResolver</classname> can
|
|
be configured for using JSPs as described above. As a best practice, we
|
|
strongly encourage placing your JSP files in a directory under the
|
|
<filename class="directory">'WEB-INF'</filename> directory, so there can
|
|
be no direct access by clients.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-jstl">
|
|
<title>'Plain-old' JSPs versus JSTL</title>
|
|
|
|
<para>When using the Java Standard Tag Library you must use a special
|
|
view class, the <classname>JstlView</classname>, as JSTL needs some
|
|
preparation before things such as the I18N features will work.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-tags">
|
|
<title>Additional tags facilitating development</title>
|
|
|
|
<para>Spring provides data binding of request parameters to command
|
|
objects as described in earlier chapters. To facilitate the development
|
|
of JSP pages in combination with those data binding features, Spring
|
|
provides a few tags that make things even easier. All Spring tags have
|
|
<emphasis>HTML escaping</emphasis> features to enable or disable
|
|
escaping of characters.</para>
|
|
|
|
<para>The tag library descriptor (TLD) is included in the <filename
|
|
class="libraryfile">spring-webmvc.jar</filename>.
|
|
Further information about the individual tags can be found in
|
|
the appendix entitled <xref linkend="spring.tld" />.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib">
|
|
<title>Using Spring's form tag library</title>
|
|
|
|
<para>As of version 2.0, Spring provides a comprehensive set of data
|
|
binding-aware tags for handling form elements when using JSP and Spring
|
|
Web MVC. Each tag provides support for the set of attributes of its
|
|
corresponding HTML tag counterpart, making the tags familiar and
|
|
intuitive to use. The tag-generated HTML is HTML 4.01/XHTML 1.0
|
|
compliant.</para>
|
|
|
|
<para>Unlike other form/input tag libraries, Spring's form tag library
|
|
is integrated with Spring Web MVC, giving the tags access to the command
|
|
object and reference data your controller deals with. As you will see in
|
|
the following examples, the form tags make JSPs easier to develop, read
|
|
and maintain.</para>
|
|
|
|
<para>Let's go through the form tags and look at an example of how each
|
|
tag is used. We have included generated HTML snippets where certain tags
|
|
require further commentary.</para>
|
|
|
|
<section id="view-jsp-formtaglib-configuration">
|
|
<title>Configuration</title>
|
|
|
|
<para>The form tag library comes bundled in
|
|
<literal>spring-webmvc.jar</literal>.
|
|
The library descriptor is called
|
|
<literal>spring-form.tld</literal>.</para>
|
|
|
|
<para>To use the tags from this library, add the following directive
|
|
to the top of your JSP page:</para>
|
|
|
|
<programlisting language="xml"><%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %></programlisting>
|
|
|
|
<para>... where <literal>form</literal> is the tag name prefix you
|
|
want to use for the tags from this library.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-formtag">
|
|
<title>The <literal>form</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'form' tag and exposes a binding path
|
|
to inner tags for binding. It puts the command object in the
|
|
<literal>PageContext</literal> so that the command object can be
|
|
accessed by inner tags. <emphasis>All the other tags in this library
|
|
are nested tags of the <literal>form</literal> tag</emphasis>.</para>
|
|
|
|
<para>Let's assume we have a domain object called
|
|
<classname>User</classname>. It is a JavaBean with properties such as
|
|
<literal>firstName</literal> and <literal>lastName</literal>. We will
|
|
use it as the form backing object of our form controller which returns
|
|
<literal>form.jsp</literal>. Below is an example of what
|
|
<literal>form.jsp</literal> would look like:</para>
|
|
|
|
<programlisting language="xml"><form:form>
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><form:input path="firstName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><form:input path="lastName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
|
|
<para>The <literal>firstName</literal> and <literal>lastName</literal>
|
|
values are retrieved from the command object placed in the
|
|
<interfacename>PageContext</interfacename> by the page controller.
|
|
Keep reading to see more complex examples of how inner tags are used
|
|
with the <literal>form</literal> tag.</para>
|
|
|
|
<para>The generated HTML looks like a standard form:</para>
|
|
|
|
<programlisting language="xml"><form method="POST">
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><input name="firstName" type="text" value="Harry"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><input name="lastName" type="text" value="Potter"/></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form></programlisting>
|
|
|
|
<para>The preceding JSP assumes that the variable name of the form
|
|
backing object is <literal>'command'</literal>. If you have put the
|
|
form backing object into the model under another name (definitely a
|
|
best practice), then you can bind the form to the named variable like
|
|
so:</para>
|
|
|
|
<programlisting language="xml"><form:form <lineannotation><emphasis
|
|
role="bold">commandName="user"</emphasis></lineannotation>>
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><form:input path="firstName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><form:input path="lastName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="2">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-inputtag">
|
|
<title>The <literal>input</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'input' tag using the bound value
|
|
and type='text' by default. For an example of this tag, see <xref
|
|
linkend="view-jsp-formtaglib-formtag" />. Starting with Spring 3.1
|
|
you can use other types such HTML5-specific types like 'email',
|
|
'tel', 'date', and others.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-checkboxtag">
|
|
<title>The <literal>checkbox</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'input' tag with type
|
|
'checkbox'.</para>
|
|
|
|
<para>Let's assume our <classname>User</classname> has preferences
|
|
such as newsletter subscription and a list of hobbies. Below is an
|
|
example of the <classname>Preferences</classname> class:</para>
|
|
|
|
<programlisting language="java">public class Preferences {
|
|
|
|
private boolean receiveNewsletter;
|
|
|
|
private String[] interests;
|
|
|
|
private String favouriteWord;
|
|
|
|
public boolean isReceiveNewsletter() {
|
|
return receiveNewsletter;
|
|
}
|
|
|
|
public void setReceiveNewsletter(boolean receiveNewsletter) {
|
|
this.receiveNewsletter = receiveNewsletter;
|
|
}
|
|
|
|
public String[] getInterests() {
|
|
return interests;
|
|
}
|
|
|
|
public void setInterests(String[] interests) {
|
|
this.interests = interests;
|
|
}
|
|
|
|
public String getFavouriteWord() {
|
|
return favouriteWord;
|
|
}
|
|
|
|
public void setFavouriteWord(String favouriteWord) {
|
|
this.favouriteWord = favouriteWord;
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>The <literal>form.jsp</literal> would look like:</para>
|
|
|
|
<programlisting language="xml"><form:form>
|
|
<table>
|
|
<tr>
|
|
<td>Subscribe to newsletter?:</td>
|
|
<lineannotation><%-- Approach 1: Property is of type <classname>java.lang.Boolean</classname> --%></lineannotation>
|
|
<td><form:checkbox path="preferences.receiveNewsletter"/></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Interests:</td>
|
|
<td>
|
|
<lineannotation><%-- Approach 2: Property is of an array or of type <interfacename>java.util.Collection</interfacename> --%></lineannotation>
|
|
Quidditch: <form:checkbox path="preferences.interests" value="Quidditch"/>
|
|
Herbology: <form:checkbox path="preferences.interests" value="Herbology"/>
|
|
Defence Against the Dark Arts: <form:checkbox path="preferences.interests"
|
|
value="Defence Against the Dark Arts"/>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Favourite Word:</td>
|
|
<td>
|
|
<lineannotation><%-- Approach 3: Property is of type <classname>java.lang.Object</classname> --%></lineannotation>
|
|
Magic: <form:checkbox path="preferences.favouriteWord" value="Magic"/>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
|
|
<para>There are 3 approaches to the <literal>checkbox</literal> tag
|
|
which should meet all your checkbox needs.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>Approach One - When the bound value is of type
|
|
<literal>java.lang.Boolean</literal>, the
|
|
<literal>input(checkbox)</literal> is marked as 'checked' if the
|
|
bound value is <literal>true</literal>. The
|
|
<literal>value</literal> attribute corresponds to the resolved
|
|
value of the <literal>setValue(Object)</literal> value
|
|
property.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Approach Two - When the bound value is of type
|
|
<literal>array</literal> or
|
|
<interfacename>java.util.Collection</interfacename>, the
|
|
<literal>input(checkbox)</literal> is marked as 'checked' if the
|
|
configured <literal>setValue(Object)</literal> value is present in
|
|
the bound <interfacename>Collection</interfacename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Approach Three - For any other bound value type, the
|
|
<literal>input(checkbox)</literal> is marked as 'checked' if the
|
|
configured <literal>setValue(Object)</literal> is equal to the
|
|
bound value.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Note that regardless of the approach, the same HTML structure is
|
|
generated. Below is an HTML snippet of some checkboxes:</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Interests:</td>
|
|
<td>
|
|
Quidditch: <input name="preferences.interests" type="checkbox" value="Quidditch"/>
|
|
<input type="hidden" value="1" name="_preferences.interests"/>
|
|
Herbology: <input name="preferences.interests" type="checkbox" value="Herbology"/>
|
|
<input type="hidden" value="1" name="_preferences.interests"/>
|
|
Defence Against the Dark Arts: <input name="preferences.interests" type="checkbox"
|
|
value="Defence Against the Dark Arts"/>
|
|
<input type="hidden" value="1" name="_preferences.interests"/>
|
|
</td>
|
|
</tr></programlisting>
|
|
|
|
<para>What you might not expect to see is the additional hidden field
|
|
after each checkbox. When a checkbox in an HTML page is
|
|
<emphasis>not</emphasis> checked, its value will not be sent to the
|
|
server as part of the HTTP request parameters once the form is
|
|
submitted, so we need a workaround for this quirk in HTML in order for
|
|
Spring form data binding to work. The <literal>checkbox</literal> tag
|
|
follows the existing Spring convention of including a hidden parameter
|
|
prefixed by an underscore ("_") for each checkbox. By doing this, you
|
|
are effectively telling Spring that <quote>
|
|
<emphasis>the checkbox was visible in the form and I want my object
|
|
to which the form data will be bound to reflect the state of the
|
|
checkbox no matter what</emphasis>
|
|
</quote>.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-checkboxestag">
|
|
<title>The <literal>checkboxes</literal> tag</title>
|
|
|
|
<para>This tag renders multiple HTML 'input' tags with type
|
|
'checkbox'.</para>
|
|
|
|
<para>Building on the example from the previous
|
|
<classname>checkbox</classname> tag section. Sometimes you prefer not
|
|
to have to list all the possible hobbies in your JSP page. You would
|
|
rather provide a list at runtime of the available options and pass
|
|
that in to the tag. That is the purpose of the
|
|
<classname>checkboxes</classname> tag. You pass in an
|
|
<classname>Array</classname>, a <classname>List</classname> or a
|
|
<classname>Map</classname> containing the available options in the
|
|
"items" property. Typically the bound property is a collection so it
|
|
can hold multiple values selected by the user. Below is an example of
|
|
the JSP using this tag:</para>
|
|
|
|
<programlisting language="xml"><form:form>
|
|
<table>
|
|
<tr>
|
|
<td>Interests:</td>
|
|
<td>
|
|
<lineannotation><%-- Property is of an array or of type <interfacename>java.util.Collection</interfacename> --%></lineannotation>
|
|
<form:checkboxes path="preferences.interests" items="${interestList}"/>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
|
|
<para>This example assumes that the "interestList" is a
|
|
<classname>List</classname> available as a model attribute containing
|
|
strings of the values to be selected from. In the case where you use a
|
|
Map, the map entry key will be used as the value and the map entry's
|
|
value will be used as the label to be displayed. You can also use a
|
|
custom object where you can provide the property names for the value
|
|
using "itemValue" and the label using "itemLabel".</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-radiobuttontag">
|
|
<title>The <literal>radiobutton</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'input' tag with type 'radio'.</para>
|
|
|
|
<para>A typical usage pattern will involve multiple tag instances
|
|
bound to the same property but with different values.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Sex:</td>
|
|
<td>Male: <form:radiobutton path="sex" value="M"/> <br/>
|
|
Female: <form:radiobutton path="sex" value="F"/> </td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-radiobuttonstag">
|
|
<title>The <literal>radiobuttons</literal> tag</title>
|
|
|
|
<para>This tag renders multiple HTML 'input' tags with type
|
|
'radio'.</para>
|
|
|
|
<para>Just like the <classname>checkboxes</classname> tag above, you
|
|
might want to pass in the available options as a runtime variable. For
|
|
this usage you would use the <classname>radiobuttons</classname> tag.
|
|
You pass in an <classname>Array</classname>, a
|
|
<classname>List</classname> or a <classname>Map</classname> containing
|
|
the available options in the "items" property. In the case where you
|
|
use a Map, the map entry key will be used as the value and the map
|
|
entry's value will be used as the label to be displayed. You can also
|
|
use a custom object where you can provide the property names for the
|
|
value using "itemValue" and the label using "itemLabel".</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Sex:</td>
|
|
<td><form:radiobuttons path="sex" items="${sexOptions}"/></td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-passwordtag">
|
|
<title>The <literal>password</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'input' tag with type 'password' using
|
|
the bound value.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Password:</td>
|
|
<td>
|
|
<form:password path="password" />
|
|
</td>
|
|
</tr></programlisting>
|
|
|
|
<para>Please note that by default, the password value is
|
|
<emphasis>not</emphasis> shown. If you do want the password value to
|
|
be shown, then set the value of the <literal>'showPassword'</literal>
|
|
attribute to true, like so.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Password:</td>
|
|
<td>
|
|
<form:password path="password" value="^76525bvHGq" showPassword="true" />
|
|
</td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-selecttag">
|
|
<title>The <literal>select</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'select' element. It supports data
|
|
binding to the selected option as well as the use of nested
|
|
<literal>option</literal> and <literal>options</literal> tags.</para>
|
|
|
|
<para>Let's assume a <classname>User</classname> has a list of
|
|
skills.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Skills:</td>
|
|
<td><form:select path="skills" items="${skills}"/></td>
|
|
</tr></programlisting>
|
|
|
|
<para>If the <literal>User's</literal> skill were in Herbology, the
|
|
HTML source of the 'Skills' row would look like:</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Skills:</td>
|
|
<td><select name="skills" multiple="true">
|
|
<option value="Potions">Potions</option>
|
|
<option value="Herbology" selected="selected">Herbology</option>
|
|
<option value="Quidditch">Quidditch</option></select>
|
|
</td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-optiontag">
|
|
<title>The <literal>option</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'option'. It sets 'selected' as
|
|
appropriate based on the bound value.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>House:</td>
|
|
<td>
|
|
<form:select path="house">
|
|
<form:option value="Gryffindor"/>
|
|
<form:option value="Hufflepuff"/>
|
|
<form:option value="Ravenclaw"/>
|
|
<form:option value="Slytherin"/>
|
|
</form:select>
|
|
</td>
|
|
</tr></programlisting>
|
|
|
|
<para>If the <literal>User's</literal> house was in Gryffindor, the
|
|
HTML source of the 'House' row would look like:</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>House:</td>
|
|
<td>
|
|
<select name="house">
|
|
<option value="Gryffindor" selected="selected">Gryffindor</option>
|
|
<option value="Hufflepuff">Hufflepuff</option>
|
|
<option value="Ravenclaw">Ravenclaw</option>
|
|
<option value="Slytherin">Slytherin</option>
|
|
</select>
|
|
</td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-optionstag">
|
|
<title>The <literal>options</literal> tag</title>
|
|
|
|
<para>This tag renders a list of HTML 'option' tags. It sets the
|
|
'selected' attribute as appropriate based on the bound value.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Country:</td>
|
|
<td>
|
|
<form:select path="country">
|
|
<form:option value="-" label="--Please Select"/>
|
|
<form:options items="${countryList}" itemValue="code" itemLabel="name"/>
|
|
</form:select>
|
|
</td>
|
|
</tr></programlisting>
|
|
|
|
<para>If the <classname>User</classname> lived in the UK, the HTML
|
|
source of the 'Country' row would look like:</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Country:</td>
|
|
<td>
|
|
<select name="country">
|
|
<option value="-">--Please Select</option>
|
|
<option value="AT">Austria</option>
|
|
<option value="UK" selected="selected">United Kingdom</option>
|
|
<option value="US">United States</option>
|
|
</select>
|
|
</td>
|
|
</tr></programlisting>
|
|
|
|
<para>As the example shows, the combined usage of an
|
|
<literal>option</literal> tag with the <literal>options</literal> tag
|
|
generates the same standard HTML, but allows you to explicitly specify
|
|
a value in the JSP that is for display only (where it belongs) such as
|
|
the default string in the example: "-- Please Select".</para>
|
|
|
|
<para>The <literal>items</literal> attribute is typically populated
|
|
with a collection or array of item objects.
|
|
<literal>itemValue</literal> and <literal>itemLabel</literal> simply
|
|
refer to bean properties of those item objects, if specified;
|
|
otherwise, the item objects themselves will be stringified.
|
|
Alternatively, you may specify a <literal>Map</literal> of items, in
|
|
which case the map keys are interpreted as option values and the map
|
|
values correspond to option labels. If <literal>itemValue</literal>
|
|
and/or <literal>itemLabel</literal> happen to be specified as well,
|
|
the item value property will apply to the map key and the item label
|
|
property will apply to the map value.</para>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-textAreatag">
|
|
<title>The <literal>textarea</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'textarea'.</para>
|
|
|
|
<programlisting language="xml"><tr>
|
|
<td>Notes:</td>
|
|
<td><form:textarea path="notes" rows="3" cols="20" /></td>
|
|
<td><form:errors path="notes" /></td>
|
|
</tr></programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-hiddeninputtag">
|
|
<title>The <literal>hidden</literal> tag</title>
|
|
|
|
<para>This tag renders an HTML 'input' tag with type 'hidden' using
|
|
the bound value. To submit an unbound hidden value, use the HTML
|
|
<literal>input</literal> tag with type 'hidden'.</para>
|
|
|
|
<programlisting language="xml"><form:hidden path="house" />
|
|
</programlisting>
|
|
|
|
<para>If we choose to submit the 'house' value as a hidden one, the
|
|
HTML would look like:</para>
|
|
|
|
<programlisting language="xml"><input name="house" type="hidden" value="Gryffindor"/>
|
|
</programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-errorstag">
|
|
<title>The <literal>errors</literal> tag</title>
|
|
|
|
<para>This tag renders field errors in an HTML 'span' tag. It provides
|
|
access to the errors created in your controller or those that were
|
|
created by any validators associated with your controller.</para>
|
|
|
|
<para>Let's assume we want to display all error messages for the
|
|
<literal>firstName</literal> and <literal>lastName</literal> fields
|
|
once we submit the form. We have a validator for instances of the
|
|
<classname>User</classname> class called
|
|
<classname>UserValidator</classname>.</para>
|
|
|
|
<programlisting language="java">public class UserValidator implements Validator {
|
|
|
|
public boolean supports(Class candidate) {
|
|
return User.class.isAssignableFrom(candidate);
|
|
}
|
|
|
|
public void validate(Object obj, Errors errors) {
|
|
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "required", "Field is required.");
|
|
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "required", "Field is required.");
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>The <literal>form.jsp</literal> would look like:</para>
|
|
|
|
<programlisting language="xml"><form:form>
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><form:input path="firstName" /></td>
|
|
<lineannotation><%-- Show errors for firstName field --%></lineannotation>
|
|
<td><form:errors path="firstName" /></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><form:input path="lastName" /></td>
|
|
<lineannotation><%-- Show errors for lastName field --%></lineannotation>
|
|
<td><form:errors path="lastName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
|
|
<para>If we submit a form with empty values in the
|
|
<literal>firstName</literal> and <literal>lastName</literal> fields,
|
|
this is what the HTML would look like:</para>
|
|
|
|
<programlisting language="xml"><form method="POST">
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><input name="firstName" type="text" value=""/></td>
|
|
<lineannotation><%-- Associated errors to firstName field displayed --%></lineannotation>
|
|
<td><span name="firstName.errors">Field is required.</span></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><input name="lastName" type="text" value=""/></td>
|
|
<lineannotation><%-- Associated errors to lastName field displayed --%></lineannotation>
|
|
<td><span name="lastName.errors">Field is required.</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form></programlisting>
|
|
|
|
<para>What if we want to display the entire list of errors for a given
|
|
page? The example below shows that the <literal>errors</literal> tag
|
|
also supports some basic wildcarding functionality.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>path="*"</literal> - displays all errors</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>path="lastName"</literal> - displays all errors
|
|
associated with the <literal>lastName</literal> field</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The example below will display a list of errors at the top of
|
|
the page, followed by field-specific errors next to the fields:</para>
|
|
|
|
<programlisting language="xml"><form:form>
|
|
<form:errors path="*" cssClass="errorBox" />
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><form:input path="firstName" /></td>
|
|
<td><form:errors path="firstName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><form:input path="lastName" /></td>
|
|
<td><form:errors path="lastName" /></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</form:form></programlisting>
|
|
|
|
<para>The HTML would look like:</para>
|
|
|
|
<programlisting language="xml"><form method="POST">
|
|
<span name="*.errors" class="errorBox">Field is required.<br/>Field is required.</span>
|
|
<table>
|
|
<tr>
|
|
<td>First Name:</td>
|
|
<td><input name="firstName" type="text" value=""/></td>
|
|
<td><span name="firstName.errors">Field is required.</span></td>
|
|
</tr>
|
|
|
|
<tr>
|
|
<td>Last Name:</td>
|
|
<td><input name="lastName" type="text" value=""/></td>
|
|
<td><span name="lastName.errors">Field is required.</span></td>
|
|
</tr>
|
|
<tr>
|
|
<td colspan="3">
|
|
<input type="submit" value="Save Changes" />
|
|
</td>
|
|
</tr>
|
|
</form></programlisting>
|
|
</section>
|
|
|
|
<section id="rest-method-conversion">
|
|
<title>HTTP Method Conversion</title>
|
|
|
|
<para>A key principle of REST is the use of the Uniform Interface.
|
|
This means that all resources (URLs) can be manipulated using the same
|
|
four HTTP methods: GET, PUT, POST, and DELETE. For each method, the
|
|
HTTP specification defines the exact semantics. For instance, a GET
|
|
should always be a safe operation, meaning that is has no side
|
|
effects, and a PUT or DELETE should be idempotent, meaning that you
|
|
can repeat these operations over and over again, but the end result
|
|
should be the same. While HTTP defines these four methods, HTML only
|
|
supports two: GET and POST. Fortunately, there are two possible
|
|
workarounds: you can either use JavaScript to do your PUT or DELETE,
|
|
or simply do a POST with the 'real' method as an additional parameter
|
|
(modeled as a hidden input field in an HTML form). This latter trick
|
|
is what Spring's <classname>HiddenHttpMethodFilter</classname> does.
|
|
This filter is a plain Servlet Filter and therefore it can be used in
|
|
combination with any web framework (not just Spring MVC). Simply add
|
|
this filter to your web.xml, and a POST with a hidden _method
|
|
parameter will be converted into the corresponding HTTP method
|
|
request.</para>
|
|
|
|
<para>To support HTTP method conversion the Spring MVC form tag was
|
|
updated to support setting the HTTP method. For example, the following
|
|
snippet taken from the updated Petclinic sample</para>
|
|
|
|
<programlisting language="xml"><form:form method="delete">
|
|
<p class="submit"><input type="submit" value="Delete Pet"/></p>
|
|
</form:form></programlisting>
|
|
|
|
<para>This will actually perform an HTTP POST, with the 'real' DELETE
|
|
method hidden behind a request parameter, to be picked up by the
|
|
<classname>HiddenHttpMethodFilter</classname>, as defined in web.xml:</para>
|
|
<programlisting language="java"><filter>
|
|
<filter-name>httpMethodFilter</filter-name>
|
|
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
|
|
</filter>
|
|
|
|
<filter-mapping>
|
|
<filter-name>httpMethodFilter</filter-name>
|
|
<servlet-name>petclinic</servlet-name>
|
|
</filter-mapping></programlisting><para>The corresponding @Controller method
|
|
is shown below:</para>
|
|
|
|
<programlisting language="java">@RequestMapping(method = RequestMethod.DELETE)
|
|
public String deletePet(@PathVariable int ownerId, @PathVariable int petId) {
|
|
this.clinic.deletePet(petId);
|
|
return "redirect:/owners/" + ownerId;
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="view-jsp-formtaglib-html5">
|
|
<title>HTML5 Tags</title>
|
|
|
|
<para>Starting with Spring 3, the Spring form tag library allows entering
|
|
dynamic attributes, which means you can enter any HTML5 specific attributes.
|
|
</para>
|
|
|
|
<para>In Spring 3.1, the form input tag supports entering a type attribute
|
|
other than 'text'. This is intended to allow rendering new HTML5 specific
|
|
input types such as 'email', 'date', 'range', and others. Note that
|
|
entering type='text' is not required since 'text' is the default type.
|
|
</para>
|
|
|
|
</section>
|
|
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-tiles">
|
|
<title>Tiles</title>
|
|
|
|
<para>It is possible to integrate Tiles - just as any other view
|
|
technology - in web applications using Spring. The following describes in
|
|
a broad way how to do this.</para>
|
|
|
|
<para><emphasis>NOTE:</emphasis> This section focuses on Spring's support
|
|
for Tiles 2 (the standalone version of Tiles, requiring Java 5+) in the
|
|
<literal>org.springframework.web.servlet.view.tiles2</literal> package.
|
|
Spring also continues to support Tiles 1.x (a.k.a. "Struts Tiles", as
|
|
shipped with Struts 1.1+; compatible with Java 1.4) in the original
|
|
<literal>org.springframework.web.servlet.view.tiles</literal>
|
|
package.</para>
|
|
|
|
<section id="view-tiles-dependencies">
|
|
<title>Dependencies</title>
|
|
|
|
<para>To be able to use Tiles you have to have a couple of additional
|
|
dependencies included in your project. The following is the list of
|
|
dependencies you need.</para>
|
|
|
|
<itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para><literal>Tiles version 2.1.2 or higher</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>Commons BeanUtils</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>Commons Digester</literal></para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><literal>Commons Logging</literal></para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
</section>
|
|
|
|
<section id="view-tiles-integrate">
|
|
<title>How to integrate Tiles</title>
|
|
|
|
<para>To be able to use Tiles, you have to configure it using files
|
|
containing definitions (for basic information on definitions and other
|
|
Tiles concepts, please have a look at <ulink
|
|
url="http://tiles.apache.org" />). In Spring this is done using the
|
|
<classname>TilesConfigurer</classname>. Have a look at the following
|
|
piece of example ApplicationContext configuration:</para>
|
|
|
|
<programlisting language="xml"><bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
|
|
<property name="definitions">
|
|
<list>
|
|
<value>/WEB-INF/defs/general.xml</value>
|
|
<value>/WEB-INF/defs/widgets.xml</value>
|
|
<value>/WEB-INF/defs/administrator.xml</value>
|
|
<value>/WEB-INF/defs/customer.xml</value>
|
|
<value>/WEB-INF/defs/templates.xml</value>
|
|
</list>
|
|
</property>
|
|
</bean></programlisting>
|
|
|
|
<para>As you can see, there are five files containing definitions, which
|
|
are all located in the <filename
|
|
class="directory">'WEB-INF/defs'</filename> directory. At initialization
|
|
of the <interfacename>WebApplicationContext</interfacename>, the files
|
|
will be loaded and the definitions factory will be initialized. After
|
|
that has been done, the Tiles includes in the definition files can be
|
|
used as views within your Spring web application. To be able to use the
|
|
views you have to have a <interfacename>ViewResolver</interfacename>
|
|
just as with any other view technology used with Spring. Below you can
|
|
find two possibilities, the <classname>UrlBasedViewResolver</classname>
|
|
and the <classname>ResourceBundleViewResolver</classname>.</para>
|
|
|
|
<section id="view-tiles-url">
|
|
<title>
|
|
<classname>UrlBasedViewResolver</classname>
|
|
</title>
|
|
|
|
<para>The <classname>UrlBasedViewResolver</classname> instantiates the
|
|
given <literal>viewClass</literal> for each view it has to
|
|
resolve.</para>
|
|
|
|
<programlisting language="xml"><bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
|
|
<property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
|
|
</bean></programlisting>
|
|
</section>
|
|
|
|
<section id="view-tiles-resource">
|
|
<title>
|
|
<classname>ResourceBundleViewResolver</classname>
|
|
</title>
|
|
|
|
<para>The <classname>ResourceBundleViewResolver</classname> has to be
|
|
provided with a property file containing viewnames and viewclasses the
|
|
resolver can use:</para>
|
|
|
|
<programlisting language="xml"><bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
|
|
<property name="basename" value="views"/>
|
|
</bean></programlisting>
|
|
|
|
<programlisting language="java">...
|
|
welcomeView.(class)=org.springframework.web.servlet.view.tiles2.TilesView
|
|
welcomeView.url=welcome <lineannotation>(this is the name of a Tiles definition)</lineannotation>
|
|
|
|
vetsView.(class)=org.springframework.web.servlet.view.tiles2.TilesView
|
|
vetsView.url=vetsView <lineannotation>(again, this is the name of a Tiles definition)</lineannotation>
|
|
|
|
findOwnersForm.(class)=org.springframework.web.servlet.view.JstlView
|
|
findOwnersForm.url=/WEB-INF/jsp/findOwners.jsp
|
|
...</programlisting>
|
|
|
|
<para>As you can see, when using the
|
|
<classname>ResourceBundleViewResolver</classname>, you can easily mix
|
|
different view technologies.</para>
|
|
|
|
<para>Note that the <classname>TilesView</classname> class for Tiles 2
|
|
supports JSTL (the JSP Standard Tag Library) out of the box, whereas
|
|
there is a separate <classname>TilesJstlView</classname> subclass in the
|
|
Tiles 1.x support.</para>
|
|
</section>
|
|
|
|
<section id="view-tiles-preparer">
|
|
<title><classname>SimpleSpringPreparerFactory</classname> and
|
|
<classname>SpringBeanPreparerFactory</classname></title>
|
|
|
|
<para>As an advanced feature, Spring also supports two special Tiles 2
|
|
<interfacename>PreparerFactory</interfacename> implementations. Check
|
|
out the Tiles documentation for details on how to use
|
|
<interfacename>ViewPreparer</interfacename> references in your Tiles
|
|
definition files.</para>
|
|
|
|
<para>Specify <classname>SimpleSpringPreparerFactory</classname> to
|
|
autowire ViewPreparer instances based on specified preparer classes,
|
|
applying Spring's container callbacks as well as applying configured
|
|
Spring BeanPostProcessors. If Spring's context-wide annotation-config
|
|
has been activated, annotations in ViewPreparer classes will be
|
|
automatically detected and applied. Note that this expects preparer
|
|
<emphasis>classes</emphasis> in the Tiles definition files, just like
|
|
the default <classname>PreparerFactory</classname> does.</para>
|
|
|
|
<para>Specify <classname>SpringBeanPreparerFactory</classname> to
|
|
operate on specified preparer <emphasis>names</emphasis> instead of
|
|
classes, obtaining the corresponding Spring bean from the
|
|
DispatcherServlet's application context. The full bean creation
|
|
process will be in the control of the Spring application context in
|
|
this case, allowing for the use of explicit dependency injection
|
|
configuration, scoped beans etc. Note that you need to define one
|
|
Spring bean definition per preparer name (as used in your Tiles
|
|
definitions).</para>
|
|
|
|
<programlisting language="xml"><bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
|
|
<property name="definitions">
|
|
<list>
|
|
<value>/WEB-INF/defs/general.xml</value>
|
|
<value>/WEB-INF/defs/widgets.xml</value>
|
|
<value>/WEB-INF/defs/administrator.xml</value>
|
|
<value>/WEB-INF/defs/customer.xml</value>
|
|
<value>/WEB-INF/defs/templates.xml</value>
|
|
</list>
|
|
</property>
|
|
|
|
<lineannotation><!-- resolving preparer names as Spring bean definition names --></lineannotation>
|
|
<property name="preparerFactoryClass"
|
|
value="org.springframework.web.servlet.view.tiles2.SpringBeanPreparerFactory"/>
|
|
|
|
</bean></programlisting>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-velocity">
|
|
<title>Velocity & FreeMarker</title>
|
|
|
|
<para><ulink url="http://velocity.apache.org">Velocity</ulink> and <ulink
|
|
url="http://www.freemarker.org">FreeMarker</ulink> are two templating
|
|
languages that can be used as view technologies within Spring MVC
|
|
applications. The languages are quite similar and serve similar needs and
|
|
so are considered together in this section. For semantic and syntactic
|
|
differences between the two languages, see the <ulink
|
|
url="http://www.freemarker.org">FreeMarker</ulink> web site.</para>
|
|
|
|
<section id="view-velocity-dependencies">
|
|
<title>Dependencies</title>
|
|
|
|
<para>Your web application will need to include <filename
|
|
class="libraryfile">velocity-1.x.x.jar</filename> or <filename
|
|
class="libraryfile">freemarker-2.x.jar</filename> in order to work with
|
|
Velocity or FreeMarker respectively and <filename
|
|
class="libraryfile">commons-collections.jar</filename> is required for
|
|
Velocity. Typically they are included in the
|
|
<literal>WEB-INF/lib</literal> folder where they are guaranteed to be
|
|
found by a Java EE server and added to the classpath for your application.
|
|
It is of course assumed that you already have the <filename
|
|
class="libraryfile">spring-webmvc.jar</filename> in your <filename
|
|
class="directory">'WEB-INF/lib'</filename> directory too! If you make use of
|
|
Spring's 'dateToolAttribute' or 'numberToolAttribute' in your Velocity
|
|
views, you will also need to include the <filename
|
|
class="libraryfile">velocity-tools-generic-1.x.jar</filename></para>
|
|
</section>
|
|
|
|
<section id="view-velocity-contextconfig">
|
|
<title>Context configuration</title>
|
|
|
|
<para>A suitable configuration is initialized by adding the relevant
|
|
configurer bean definition to your <filename>'*-servlet.xml'</filename>
|
|
as shown below:</para>
|
|
|
|
<programlisting language="xml"><lineannotation><!--
|
|
This bean sets up the Velocity environment for us based on a root path for templates.
|
|
Optionally, a properties file can be specified for more control over the Velocity
|
|
environment, but the defaults are pretty sane for file based template loading.
|
|
--></lineannotation>
|
|
<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
|
|
<property name="resourceLoaderPath" value="/WEB-INF/velocity/"/>
|
|
</bean>
|
|
|
|
<lineannotation><!--
|
|
|
|
View resolvers can also be configured with ResourceBundles or XML files. If you need
|
|
different view resolving based on Locale, you have to use the resource bundle resolver.
|
|
|
|
--></lineannotation>
|
|
<bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityViewResolver">
|
|
<property name="cache" value="true"/>
|
|
<property name="prefix" value=""/>
|
|
<property name="suffix" value=".vm"/>
|
|
</bean></programlisting>
|
|
|
|
<programlisting><lineannotation><!-- freemarker config --></lineannotation>
|
|
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
|
|
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
|
|
</bean>
|
|
|
|
<lineannotation><!--
|
|
|
|
View resolvers can also be configured with ResourceBundles or XML files. If you need
|
|
different view resolving based on Locale, you have to use the resource bundle resolver.
|
|
|
|
--></lineannotation>
|
|
<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
|
|
<property name="cache" value="true"/>
|
|
<property name="prefix" value=""/>
|
|
<property name="suffix" value=".ftl"/>
|
|
</bean></programlisting>
|
|
|
|
<note>
|
|
<para>For non web-apps add a
|
|
<classname>VelocityConfigurationFactoryBean</classname> or a
|
|
<classname>FreeMarkerConfigurationFactoryBean</classname> to your
|
|
application context definition file.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="view-velocity-createtemplates">
|
|
<title>Creating templates</title>
|
|
|
|
<para>Your templates need to be stored in the directory specified by the
|
|
<literal>*Configurer</literal> bean shown above. This document does not
|
|
cover details of creating templates for the two languages - please see
|
|
their relevant websites for information. If you use the view resolvers
|
|
highlighted, then the logical view names relate to the template file
|
|
names in similar fashion to
|
|
<classname>InternalResourceViewResolver</classname> for JSP's. So if
|
|
your controller returns a ModelAndView object containing a view name of
|
|
"welcome" then the resolvers will look for the
|
|
<literal>/WEB-INF/freemarker/welcome.ftl</literal> or
|
|
<literal>/WEB-INF/velocity/welcome.vm</literal> template as
|
|
appropriate.</para>
|
|
</section>
|
|
|
|
<section id="view-velocity-advancedconfig">
|
|
<title>Advanced configuration</title>
|
|
|
|
<para>The basic configurations highlighted above will be suitable for
|
|
most application requirements, however additional configuration options
|
|
are available for when unusual or advanced requirements dictate.</para>
|
|
|
|
<section id="view-velocity-example-velocityproperties">
|
|
<title>velocity.properties</title>
|
|
|
|
<para>This file is completely optional, but if specified, contains the
|
|
values that are passed to the Velocity runtime in order to configure
|
|
velocity itself. Only required for advanced configurations, if you
|
|
need this file, specify its location on the
|
|
<literal>VelocityConfigurer</literal> bean definition above.</para>
|
|
|
|
<programlisting language="xml"><bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
|
|
<property name="configLocation" value="/WEB-INF/velocity.properties"/>
|
|
</bean></programlisting>
|
|
|
|
<para>Alternatively, you can specify velocity properties directly in
|
|
the bean definition for the Velocity config bean by replacing the
|
|
"configLocation" property with the following inline properties.</para>
|
|
|
|
<programlisting language="xml"><bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
|
|
<property name="velocityProperties">
|
|
<props>
|
|
<prop key="resource.loader">file</prop>
|
|
<prop key="file.resource.loader.class">
|
|
org.apache.velocity.runtime.resource.loader.FileResourceLoader
|
|
</prop>
|
|
<prop key="file.resource.loader.path">${webapp.root}/WEB-INF/velocity</prop>
|
|
<prop key="file.resource.loader.cache">false</prop>
|
|
</props>
|
|
</property>
|
|
</bean></programlisting>
|
|
|
|
<para>Refer to the <ulink
|
|
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/ui/velocity/VelocityEngineFactory.html">API
|
|
documentation</ulink> for Spring configuration of Velocity, or the
|
|
Velocity documentation for examples and definitions of the
|
|
<filename>'velocity.properties'</filename> file itself.</para>
|
|
</section>
|
|
|
|
<section id="views-freemarker">
|
|
<title>FreeMarker</title>
|
|
|
|
<para>FreeMarker 'Settings' and 'SharedVariables' can be passed
|
|
directly to the FreeMarker <literal>Configuration</literal> object
|
|
managed by Spring by setting the appropriate bean properties on the
|
|
<literal>FreeMarkerConfigurer</literal> bean. The
|
|
<literal>freemarkerSettings</literal> property requires a
|
|
<literal>java.util.Properties</literal> object and the
|
|
<literal>freemarkerVariables</literal> property requires a
|
|
<literal>java.util.Map</literal>.</para>
|
|
|
|
<programlisting language="xml"><bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
|
|
<property name="templateLoaderPath" value="/WEB-INF/freemarker/"/>
|
|
<property name="freemarkerVariables">
|
|
<map>
|
|
<entry key="xml_escape" value-ref="fmXmlEscape"/>
|
|
</map>
|
|
</property>
|
|
</bean>
|
|
|
|
<bean id="fmXmlEscape" class="freemarker.template.utility.XmlEscape"/></programlisting>
|
|
|
|
<para>See the FreeMarker documentation for details of settings and
|
|
variables as they apply to the <classname>Configuration</classname>
|
|
object.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-velocity-forms">
|
|
<title>Bind support and form handling</title>
|
|
|
|
<para>Spring provides a tag library for use in JSP's that contains
|
|
(amongst other things) a <literal><spring:bind/></literal> tag.
|
|
This tag primarily enables forms to display values from form backing
|
|
objects and to show the results of failed validations from a
|
|
<literal>Validator</literal> in the web or business tier. From version
|
|
1.1, Spring now has support for the same functionality in both Velocity
|
|
and FreeMarker, with additional convenience macros for generating form
|
|
input elements themselves.</para>
|
|
|
|
<section id="view-bind-macros">
|
|
<title>The bind macros</title>
|
|
|
|
<para>A standard set of macros are maintained within the
|
|
<literal>spring-webmvc.jar</literal> file for both languages, so they are
|
|
always available to a suitably configured application.</para>
|
|
|
|
<para>Some of the macros defined in the Spring libraries are
|
|
considered internal (private) but no such scoping exists in the macro
|
|
definitions making all macros visible to calling code and user
|
|
templates. The following sections concentrate only on the macros you
|
|
need to be directly calling from within your templates. If you wish to
|
|
view the macro code directly, the files are called spring.vm /
|
|
spring.ftl and are in the packages
|
|
<literal>org.springframework.web.servlet.view.velocity</literal> or
|
|
<literal>org.springframework.web.servlet.view.freemarker</literal>
|
|
respectively.</para>
|
|
</section>
|
|
|
|
<section id="view-simple-binding">
|
|
<title>Simple binding</title>
|
|
|
|
<para>In your html forms (vm / ftl templates) that act as the
|
|
'formView' for a Spring form controller, you can use code similar to
|
|
the following to bind to field values and display error messages for
|
|
each input field in similar fashion to the JSP equivalent. Note that
|
|
the name of the command object is "command" by default, but can be
|
|
overridden in your MVC configuration by setting the 'commandName' bean
|
|
property on your form controller. Example code is shown below for the
|
|
<literal>personFormV</literal> and <literal>personFormF</literal>
|
|
views configured earlier;</para>
|
|
|
|
<programlisting language="xml"><!-- velocity macros are automatically available -->
|
|
<html>
|
|
...
|
|
<form action="" method="POST">
|
|
Name:
|
|
#springBind( "command.name" )
|
|
<input type="text"
|
|
name="${status.expression}"
|
|
value="$!status.value" /><br>
|
|
#foreach($error in $status.errorMessages) <b>$error</b> <br> #end
|
|
<br>
|
|
...
|
|
<input type="submit" value="submit"/>
|
|
</form>
|
|
...
|
|
</html></programlisting>
|
|
|
|
<programlisting language="xml"><!-- freemarker macros have to be imported into a namespace. We strongly
|
|
recommend sticking to 'spring' -->
|
|
<#import "/spring.ftl" as spring />
|
|
<html>
|
|
...
|
|
<form action="" method="POST">
|
|
Name:
|
|
<@spring.bind "command.name" />
|
|
<input type="text"
|
|
name="${spring.status.expression}"
|
|
value="${spring.status.value?default("")}" /><br>
|
|
<#list spring.status.errorMessages as error> <b>${error}</b> <br> </#list>
|
|
<br>
|
|
...
|
|
<input type="submit" value="submit"/>
|
|
</form>
|
|
...
|
|
</html></programlisting>
|
|
|
|
<para><literal>#springBind</literal> /
|
|
<literal><@spring.bind></literal> requires a 'path' argument
|
|
which consists of the name of your command object (it will be
|
|
'command' unless you changed it in your FormController properties)
|
|
followed by a period and the name of the field on the command object
|
|
you wish to bind to. Nested fields can be used too such as
|
|
"command.address.street". The <literal>bind</literal> macro assumes
|
|
the default HTML escaping behavior specified by the ServletContext
|
|
parameter <literal>defaultHtmlEscape</literal> in web.xml</para>
|
|
|
|
<para>The optional form of the macro called
|
|
<literal>#springBindEscaped</literal> /
|
|
<literal><@spring.bindEscaped></literal> takes a second argument
|
|
and explicitly specifies whether HTML escaping should be used in the
|
|
status error messages or values. Set to true or false as required.
|
|
Additional form handling macros simplify the use of HTML escaping and
|
|
these macros should be used wherever possible. They are explained in
|
|
the next section.</para>
|
|
</section>
|
|
|
|
<section id="views-form-macros">
|
|
<title>Form input generation macros</title>
|
|
|
|
<para>Additional convenience macros for both languages simplify both
|
|
binding and form generation (including validation error display). It
|
|
is never necessary to use these macros to generate form input fields,
|
|
and they can be mixed and matched with simple HTML or calls direct to
|
|
the spring bind macros highlighted previously.</para>
|
|
|
|
<para>The following table of available macros show the VTL and FTL
|
|
definitions and the parameter list that each takes.</para>
|
|
|
|
<table id="views-macros-defs-tbl">
|
|
<title>Table of macro definitions</title>
|
|
|
|
<tgroup cols="3">
|
|
<colspec align="left" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry align="center">macro</entry>
|
|
|
|
<entry align="center">VTL definition</entry>
|
|
|
|
<entry align="center">FTL definition</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><emphasis role="bold">message</emphasis> (output a
|
|
string from a resource bundle based on the code
|
|
parameter)</entry>
|
|
|
|
<entry><literal>#springMessage($code)</literal></entry>
|
|
|
|
<entry><literal><@spring.message
|
|
code/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">messageText</emphasis> (output a
|
|
string from a resource bundle based on the code parameter,
|
|
falling back to the value of the default parameter)</entry>
|
|
|
|
<entry><literal>#springMessageText($code
|
|
$text)</literal></entry>
|
|
|
|
<entry><literal><@spring.messageText code,
|
|
text/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">url</emphasis> (prefix a relative
|
|
URL with the application's context root)</entry>
|
|
|
|
<entry><literal>#springUrl($relativeUrl)</literal></entry>
|
|
|
|
<entry><literal><@spring.url
|
|
relativeUrl/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formInput</emphasis> (standard
|
|
input field for gathering user input)</entry>
|
|
|
|
<entry><literal>#springFormInput($path
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formInput path, attributes,
|
|
fieldType/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formHiddenInput *</emphasis>
|
|
(hidden input field for submitting non-user input)</entry>
|
|
|
|
<entry><literal>#springFormHiddenInput($path
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formHiddenInput path,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formPasswordInput</emphasis> *
|
|
(standard input field for gathering passwords. Note that no
|
|
value will ever be populated in fields of this type)</entry>
|
|
|
|
<entry><literal>#springFormPasswordInput($path
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formPasswordInput path,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formTextarea</emphasis> (large
|
|
text field for gathering long, freeform text input)</entry>
|
|
|
|
<entry><literal>#springFormTextarea($path
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formTextarea path,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formSingleSelect</emphasis> (drop
|
|
down box of options allowing a single required value to be
|
|
selected)</entry>
|
|
|
|
<entry><literal>#springFormSingleSelect( $path $options
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formSingleSelect path, options,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formMultiSelect</emphasis> (a
|
|
list box of options allowing the user to select 0 or more
|
|
values)</entry>
|
|
|
|
<entry><literal>#springFormMultiSelect($path $options
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formMultiSelect path, options,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formRadioButtons</emphasis> (a
|
|
set of radio buttons allowing a single selection to be made
|
|
from the available choices)</entry>
|
|
|
|
<entry><literal>#springFormRadioButtons($path $options
|
|
$separator $attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formRadioButtons path, options
|
|
separator, attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formCheckboxes</emphasis> (a set
|
|
of checkboxes allowing 0 or more values to be
|
|
selected)</entry>
|
|
|
|
<entry><literal>#springFormCheckboxes($path $options
|
|
$separator $attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formCheckboxes path, options,
|
|
separator, attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">formCheckbox</emphasis> (a single
|
|
checkbox)</entry>
|
|
|
|
<entry><literal>#springFormCheckbox($path
|
|
$attributes)</literal></entry>
|
|
|
|
<entry><literal><@spring.formCheckbox path,
|
|
attributes/></literal></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><emphasis role="bold">showErrors</emphasis> (simplify
|
|
display of validation errors for the bound field)</entry>
|
|
|
|
<entry><literal>#springShowErrors($separator
|
|
$classOrStyle)</literal></entry>
|
|
|
|
<entry><literal><@spring.showErrors separator,
|
|
classOrStyle/></literal></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>* In FTL (FreeMarker), these two macros are not actually
|
|
required as you can use the normal <literal>formInput</literal> macro,
|
|
specifying '<literal>hidden</literal>' or
|
|
'<literal>password</literal>' as the value for the
|
|
<literal>fieldType</literal> parameter.</para>
|
|
|
|
<para>The parameters to any of the above macros have consistent
|
|
meanings:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>path: the name of the field to bind to (ie
|
|
"command.name")</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>options: a Map of all the available values that can be
|
|
selected from in the input field. The keys to the map represent
|
|
the values that will be POSTed back from the form and bound to the
|
|
command object. Map objects stored against the keys are the labels
|
|
displayed on the form to the user and may be different from the
|
|
corresponding values posted back by the form. Usually such a map
|
|
is supplied as reference data by the controller. Any Map
|
|
implementation can be used depending on required behavior. For
|
|
strictly sorted maps, a <literal>SortedMap</literal> such as a
|
|
<literal>TreeMap</literal> with a suitable Comparator may be used
|
|
and for arbitrary Maps that should return values in insertion
|
|
order, use a <literal>LinkedHashMap</literal> or a
|
|
<literal>LinkedMap</literal> from commons-collections.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>separator: where multiple options are available as discreet
|
|
elements (radio buttons or checkboxes), the sequence of characters
|
|
used to separate each one in the list (ie "<br>").</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>attributes: an additional string of arbitrary tags or text
|
|
to be included within the HTML tag itself. This string is echoed
|
|
literally by the macro. For example, in a textarea field you may
|
|
supply attributes as 'rows="5" cols="60"' or you could pass style
|
|
information such as 'style="border:1px solid silver"'.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>classOrStyle: for the showErrors macro, the name of the CSS
|
|
class that the span tag wrapping each error will use. If no
|
|
information is supplied (or the value is empty) then the errors
|
|
will be wrapped in <b></b> tags.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Examples of the macros are outlined below some in FTL and some
|
|
in VTL. Where usage differences exist between the two languages, they
|
|
are explained in the notes.</para>
|
|
|
|
<section id="views-form-macros-input">
|
|
<title>Input Fields</title>
|
|
|
|
<para><programlisting language="xml"><!-- the Name field example from above using form macros in VTL -->
|
|
...
|
|
Name:
|
|
#springFormInput("command.name" "")<br>
|
|
#springShowErrors("<br>" "")<br></programlisting></para>
|
|
|
|
<para>The formInput macro takes the path parameter (command.name)
|
|
and an additional attributes parameter which is empty in the example
|
|
above. The macro, along with all other form generation macros,
|
|
performs an implicit spring bind on the path parameter. The binding
|
|
remains valid until a new bind occurs so the showErrors macro
|
|
doesn't need to pass the path parameter again - it simply operates
|
|
on whichever field a bind was last created for.</para>
|
|
|
|
<para>The showErrors macro takes a separator parameter (the
|
|
characters that will be used to separate multiple errors on a given
|
|
field) and also accepts a second parameter, this time a class name
|
|
or style attribute. Note that FreeMarker is able to specify default
|
|
values for the attributes parameter, unlike Velocity, and the two
|
|
macro calls above could be expressed as follows in FTL:</para>
|
|
|
|
<programlisting language="xml"><@spring.formInput "command.name"/>
|
|
<@spring.showErrors "<br>"/></programlisting>
|
|
|
|
<para>Output is shown below of the form fragment generating the name
|
|
field, and displaying a validation error after the form was
|
|
submitted with no value in the field. Validation occurs through
|
|
Spring's Validation framework.</para>
|
|
|
|
<para>The generated HTML looks like this:</para>
|
|
|
|
<programlisting>Name:
|
|
<input type="text" name="name" value=""
|
|
>
|
|
<br>
|
|
<b>required</b>
|
|
<br>
|
|
<br></programlisting>
|
|
|
|
<para>The formTextarea macro works the same way as the formInput
|
|
macro and accepts the same parameter list. Commonly, the second
|
|
parameter (attributes) will be used to pass style information or
|
|
rows and cols attributes for the textarea.</para>
|
|
</section>
|
|
|
|
<section id="views-form-macros-select">
|
|
<title>Selection Fields</title>
|
|
|
|
<para>Four selection field macros can be used to generate common UI
|
|
value selection inputs in your HTML forms.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>formSingleSelect</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>formMultiSelect</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>formRadioButtons</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>formCheckboxes</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Each of the four macros accepts a Map of options containing
|
|
the value for the form field, and the label corresponding to that
|
|
value. The value and the label can be the same.</para>
|
|
|
|
<para>An example of radio buttons in FTL is below. The form backing
|
|
object specifies a default value of 'London' for this field and so
|
|
no validation is necessary. When the form is rendered, the entire
|
|
list of cities to choose from is supplied as reference data in the
|
|
model under the name 'cityMap'.</para>
|
|
|
|
<programlisting>...
|
|
Town:
|
|
<@spring.formRadioButtons "command.address.town", cityMap, "" /><br><br></programlisting>
|
|
|
|
<para>This renders a line of radio buttons, one for each value in
|
|
<literal>cityMap</literal> using the separator "". No additional
|
|
attributes are supplied (the last parameter to the macro is
|
|
missing). The cityMap uses the same String for each key-value pair
|
|
in the map. The map's keys are what the form actually submits as
|
|
POSTed request parameters, map values are the labels that the user
|
|
sees. In the example above, given a list of three well known cities
|
|
and a default value in the form backing object, the HTML would
|
|
be</para>
|
|
|
|
<programlisting>Town:
|
|
<input type="radio" name="address.town" value="London"
|
|
|
|
>
|
|
London
|
|
<input type="radio" name="address.town" value="Paris"
|
|
checked="checked"
|
|
>
|
|
Paris
|
|
<input type="radio" name="address.town" value="New York"
|
|
|
|
>
|
|
New York</programlisting>
|
|
|
|
<para>If your application expects to handle cities by internal codes
|
|
for example, the map of codes would be created with suitable keys
|
|
like the example below.</para>
|
|
|
|
<programlisting language="java">protected Map referenceData(HttpServletRequest request) throws Exception {
|
|
Map cityMap = new LinkedHashMap();
|
|
cityMap.put("LDN", "London");
|
|
cityMap.put("PRS", "Paris");
|
|
cityMap.put("NYC", "New York");
|
|
|
|
Map m = new HashMap();
|
|
m.put("cityMap", cityMap);
|
|
return m;
|
|
}</programlisting>
|
|
|
|
<para>The code would now produce output where the radio values are
|
|
the relevant codes but the user still sees the more user friendly
|
|
city names.</para>
|
|
|
|
<programlisting>Town:
|
|
<input type="radio" name="address.town" value="LDN"
|
|
|
|
>
|
|
London
|
|
<input type="radio" name="address.town" value="PRS"
|
|
checked="checked"
|
|
>
|
|
Paris
|
|
<input type="radio" name="address.town" value="NYC"
|
|
|
|
>
|
|
New York</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="views-form-macros-html-escaping">
|
|
<title>HTML escaping and XHTML compliance</title>
|
|
|
|
<para>Default usage of the form macros above will result in HTML tags
|
|
that are HTML 4.01 compliant and that use the default value for HTML
|
|
escaping defined in your web.xml as used by Spring's bind support. In
|
|
order to make the tags XHTML compliant or to override the default HTML
|
|
escaping value, you can specify two variables in your template (or in
|
|
your model where they will be visible to your templates). The
|
|
advantage of specifying them in the templates is that they can be
|
|
changed to different values later in the template processing to
|
|
provide different behavior for different fields in your form.</para>
|
|
|
|
<para>To switch to XHTML compliance for your tags, specify a value of
|
|
'true' for a model/context variable named xhtmlCompliant:</para>
|
|
|
|
<programlisting>## for Velocity..
|
|
#set($springXhtmlCompliant = true)
|
|
|
|
<#-- for FreeMarker -->
|
|
<#assign xhtmlCompliant = true in spring></programlisting>
|
|
|
|
<para>Any tags generated by the Spring macros will now be XHTML
|
|
compliant after processing this directive.</para>
|
|
|
|
<para>In similar fashion, HTML escaping can be specified per
|
|
field:</para>
|
|
|
|
<programlisting language="xml"><#-- until this point, default HTML escaping is used -->
|
|
|
|
<#assign htmlEscape = true in spring>
|
|
<#-- next field will use HTML escaping -->
|
|
<@spring.formInput "command.name" />
|
|
|
|
<#assign htmlEscape = false in spring>
|
|
<#-- all future fields will be bound with HTML escaping off --></programlisting>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-xslt">
|
|
<title>XSLT</title>
|
|
|
|
<para>XSLT is a transformation language for XML and is popular as a view
|
|
technology within web applications. XSLT can be a good choice as a view
|
|
technology if your application naturally deals with XML, or if your model
|
|
can easily be converted to XML. The following section shows how to produce
|
|
an XML document as model data and have it transformed with XSLT in a
|
|
Spring Web MVC application.</para>
|
|
|
|
<section id="view-xslt-firstwords">
|
|
<title>My First Words</title>
|
|
|
|
<para>This example is a trivial Spring application that creates a list
|
|
of words in the <interfacename>Controller</interfacename> and adds them
|
|
to the model map. The map is returned along with the view name of our
|
|
XSLT view. See <xref linkend="mvc-controller" /> for details of Spring Web MVC's
|
|
<interfacename>Controller</interfacename> interface. The XSLT view will
|
|
turn the list of words into a simple XML document ready for
|
|
transformation.</para>
|
|
|
|
<section id="view-xslt-beandefs">
|
|
<title>Bean definitions</title>
|
|
|
|
<para>Configuration is standard for a simple Spring application. The
|
|
dispatcher servlet config file contains a reference to a
|
|
<interfacename>ViewResolver</interfacename>, URL mappings and a single
|
|
controller bean...</para>
|
|
|
|
<programlisting language="xml"><bean id="homeController"class="xslt.HomeController"/></programlisting>
|
|
|
|
<para>... that encapsulates our word generation logic.</para>
|
|
</section>
|
|
|
|
<section id="view-xslt-controllercode">
|
|
<title>Standard MVC controller code</title>
|
|
|
|
<para>The controller logic is encapsulated in a subclass of
|
|
<classname>AbstractController</classname>, with the handler method
|
|
being defined like so...</para>
|
|
|
|
<programlisting language="java">protected ModelAndView handleRequestInternal(
|
|
HttpServletRequest request,
|
|
HttpServletResponse response) throws Exception {
|
|
|
|
Map map = new HashMap();
|
|
List wordList = new ArrayList();
|
|
|
|
wordList.add("hello");
|
|
wordList.add("world");
|
|
|
|
map.put("wordList", wordList);
|
|
|
|
return new ModelAndView("home", map);
|
|
}</programlisting>
|
|
|
|
<para>So far we've done nothing that's XSLT specific. The model data
|
|
has been created in the same way as you would for any other Spring MVC
|
|
application. Depending on the configuration of the application now,
|
|
that list of words could be rendered by JSP/JSTL by having them added
|
|
as request attributes, or they could be handled by Velocity by adding
|
|
the object to the <classname>VelocityContext</classname>. In order to
|
|
have XSLT render them, they of course have to be converted into an XML
|
|
document somehow. There are software packages available that will
|
|
automatically 'domify' an object graph, but within Spring, you have
|
|
complete flexibility to create the DOM from your model in any way you
|
|
choose. This prevents the transformation of XML playing too great a
|
|
part in the structure of your model data which is a danger when using
|
|
tools to manage the domification process.</para>
|
|
</section>
|
|
|
|
<section id="view-xslt-subclassing">
|
|
<title>Convert the model data to XML</title>
|
|
|
|
<para>In order to create a DOM document from our list of words or any
|
|
other model data, we must subclass the (provided)
|
|
<classname>org.springframework.web.servlet.view.xslt.AbstractXsltView</classname>
|
|
class. In doing so, we must also typically implement the abstract
|
|
method <methodname>createXsltSource(..)</methodname> method. The first
|
|
parameter passed to this method is our model map. Here's the complete
|
|
listing of the <classname>HomePage</classname> class in our trivial
|
|
word application:</para>
|
|
|
|
<programlisting language="java">
|
|
package xslt;
|
|
|
|
<lineannotation>// imports omitted for brevity</lineannotation>
|
|
|
|
public class HomePage extends AbstractXsltView {
|
|
|
|
protected Source createXsltSource(Map model, String rootName, HttpServletRequest
|
|
request, HttpServletResponse response) throws Exception {
|
|
|
|
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
|
|
Element root = document.createElement(rootName);
|
|
|
|
List words = (List) model.get("wordList");
|
|
for (Iterator it = words.iterator(); it.hasNext();) {
|
|
String nextWord = (String) it.next();
|
|
Element wordNode = document.createElement("word");
|
|
Text textNode = document.createTextNode(nextWord);
|
|
wordNode.appendChild(textNode);
|
|
root.appendChild(wordNode);
|
|
}
|
|
return new DOMSource(root);
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>A series of parameter name/value pairs can optionally be defined
|
|
by your subclass which will be added to the transformation object. The
|
|
parameter names must match those defined in your XSLT template
|
|
declared with <literal><xsl:param
|
|
name="myParam">defaultValue</xsl:param></literal>. To specify
|
|
the parameters, override the <methodname>getParameters()</methodname>
|
|
method of the <classname>AbstractXsltView</classname> class and return
|
|
a <interfacename>Map</interfacename> of the name/value pairs. If your
|
|
parameters need to derive information from the current request, you
|
|
can override the <methodname>getParameters(HttpServletRequest
|
|
request)</methodname> method instead.</para>
|
|
</section>
|
|
|
|
<section id="view-xslt-viewdefinitions">
|
|
<title>Defining the view properties</title>
|
|
|
|
<para>The views.properties file (or equivalent xml definition if
|
|
you're using an XML based view resolver as we did in the Velocity
|
|
examples above) looks like this for the one-view application that is
|
|
'My First Words':</para>
|
|
|
|
<programlisting>home.(class)=xslt.HomePage
|
|
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
|
|
home.root=words</programlisting>
|
|
|
|
<para>Here, you can see how the view is tied in with the
|
|
<classname>HomePage</classname> class just written which handles the
|
|
model domification in the first property <literal>'.(class)'</literal>.
|
|
The <literal>'stylesheetLocation'</literal> property points to the
|
|
XSLT file which will handle the XML transformation into HTML for us
|
|
and the final property <literal>'.root'</literal> is the name that
|
|
will be used as the root of the XML document. This gets passed to the
|
|
<classname>HomePage</classname> class above in the second parameter to
|
|
the <methodname>createXsltSource(..)</methodname> method(s).</para>
|
|
</section>
|
|
|
|
<section id="view-xslt-transforming">
|
|
<title>Document transformation</title>
|
|
|
|
<para>Finally, we have the XSLT code used for transforming the above
|
|
document. As shown in the above
|
|
<filename>'views.properties'</filename> file, the stylesheet is called
|
|
<filename>'home.xslt'</filename> and it lives in the war file in the
|
|
<filename class="directory">'WEB-INF/xsl'</filename> directory.</para>
|
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="utf-8"?>
|
|
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
|
|
|
<xsl:output method="html" omit-xml-declaration="yes"/>
|
|
|
|
<xsl:template match="/">
|
|
<html>
|
|
<head><title>Hello!</title></head>
|
|
<body>
|
|
<h1>My First Words</h1>
|
|
<xsl:apply-templates/>
|
|
</body>
|
|
</html>
|
|
</xsl:template>
|
|
|
|
<xsl:template match="word">
|
|
<xsl:value-of select="."/><br/>
|
|
</xsl:template>
|
|
|
|
</xsl:stylesheet></programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-xslt-summary">
|
|
<title>Summary</title>
|
|
|
|
<para>A summary of the files discussed and their location in the WAR
|
|
file is shown in the simplified WAR structure below.</para>
|
|
|
|
<programlisting>ProjectRoot
|
|
|
|
|
+- WebContent
|
|
|
|
|
+- WEB-INF
|
|
|
|
|
+- classes
|
|
| |
|
|
| +- xslt
|
|
| | |
|
|
| | +- HomePageController.class
|
|
| | +- HomePage.class
|
|
| |
|
|
| +- views.properties
|
|
|
|
|
+- lib
|
|
| |
|
|
| +- spring-*.jar
|
|
|
|
|
+- xsl
|
|
| |
|
|
| +- home.xslt
|
|
|
|
|
+- frontcontroller-servlet.xml</programlisting>
|
|
|
|
<para>You will also need to ensure that an XML parser and an XSLT engine
|
|
are available on the classpath. JDK 1.4 provides them by default, and
|
|
most Java EE containers will also make them available by default, but it's
|
|
a possible source of errors to be aware of.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-document">
|
|
<title>Document views (PDF/Excel)</title>
|
|
|
|
<section id="view-document-intro">
|
|
<title>Introduction</title>
|
|
|
|
<para>Returning an HTML page isn't always the best way for the user to
|
|
view the model output, and Spring makes it simple to generate a PDF
|
|
document or an Excel spreadsheet dynamically from the model data. The
|
|
document is the view and will be streamed from the server with the
|
|
correct content type to (hopefully) enable the client PC to run their
|
|
spreadsheet or PDF viewer application in response.</para>
|
|
|
|
<para>In order to use Excel views, you need to add the 'poi' library to
|
|
your classpath, and for PDF generation, the iText library.</para>
|
|
</section>
|
|
|
|
<section id="view-document-config">
|
|
<title>Configuration and setup</title>
|
|
|
|
<para>Document based views are handled in an almost identical fashion to
|
|
XSLT views, and the following sections build upon the previous one by
|
|
demonstrating how the same controller used in the XSLT example is
|
|
invoked to render the same model as both a PDF document and an Excel
|
|
spreadsheet (which can also be viewed or manipulated in Open
|
|
Office).</para>
|
|
|
|
<section id="view-document-configviews">
|
|
<title>Document view definitions</title>
|
|
|
|
<para>First, let's amend the views.properties file (or xml
|
|
equivalent) and add a simple view definition for both document types.
|
|
The entire file now looks like this with the XSLT view shown from
|
|
earlier:</para>
|
|
|
|
<programlisting>home.(class)=xslt.HomePage
|
|
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
|
|
home.root=words
|
|
|
|
xl.(class)=excel.HomePage
|
|
|
|
pdf.(class)=pdf.HomePage</programlisting>
|
|
|
|
<para><emphasis>If you want to start with a
|
|
template spreadsheet or a fillable PDF form to add your model data to, specify the location
|
|
as the 'url' property in the view definition</emphasis></para>
|
|
</section>
|
|
|
|
<section id="view-document-configcontroller">
|
|
<title>Controller code</title>
|
|
|
|
<para>The controller code we'll use remains exactly the same from the
|
|
XSLT example earlier other than to change the name of the view to use.
|
|
Of course, you could be clever and have this selected based on a URL
|
|
parameter or some other logic - proof that Spring really is very good
|
|
at decoupling the views from the controllers!</para>
|
|
</section>
|
|
|
|
<section id="view-document-configsubclasses">
|
|
<title>Subclassing for Excel views</title>
|
|
|
|
<para>Exactly as we did for the XSLT example, we'll subclass suitable
|
|
abstract classes in order to implement custom behavior in generating
|
|
our output documents. For Excel, this involves writing a subclass of
|
|
<literal>org.springframework.web.servlet.view.document.AbstractExcelView</literal>
|
|
(for Excel files generated by POI) or
|
|
<literal>org.springframework.web.servlet.view.document.AbstractJExcelView</literal>
|
|
(for JExcelApi-generated Excel files) and implementing the
|
|
<literal>buildExcelDocument()</literal> method.</para>
|
|
|
|
<para>Here's the complete listing for our POI Excel view which
|
|
displays the word list from the model map in consecutive rows of the
|
|
first column of a new spreadsheet:</para>
|
|
|
|
<programlisting language="java">package excel;
|
|
|
|
// imports omitted for brevity
|
|
|
|
public class HomePage extends AbstractExcelView {
|
|
|
|
protected void buildExcelDocument(
|
|
Map model,
|
|
HSSFWorkbook wb,
|
|
HttpServletRequest req,
|
|
HttpServletResponse resp)
|
|
throws Exception {
|
|
|
|
HSSFSheet sheet;
|
|
HSSFRow sheetRow;
|
|
HSSFCell cell;
|
|
|
|
// Go to the first sheet
|
|
// getSheetAt: only if wb is created from an existing document
|
|
// sheet = wb.getSheetAt(0);
|
|
sheet = wb.createSheet("Spring");
|
|
sheet.setDefaultColumnWidth((short) 12);
|
|
|
|
// write a text at A1
|
|
cell = getCell(sheet, 0, 0);
|
|
setText(cell, "Spring-Excel test");
|
|
|
|
List words = (List) model.get("wordList");
|
|
for (int i=0; i < words.size(); i++) {
|
|
cell = getCell(sheet, 2+i, 0);
|
|
setText(cell, (String) words.get(i));
|
|
|
|
}
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>And the following is a view generating the same Excel file, now using
|
|
JExcelApi:</para>
|
|
|
|
<programlisting language="java">package excel;
|
|
|
|
// imports omitted for brevity
|
|
|
|
public class HomePage extends AbstractJExcelView {
|
|
|
|
protected void buildExcelDocument(Map model,
|
|
WritableWorkbook wb,
|
|
HttpServletRequest request,
|
|
HttpServletResponse response)
|
|
throws Exception {
|
|
|
|
WritableSheet sheet = wb.createSheet("Spring", 0);
|
|
|
|
sheet.addCell(new Label(0, 0, "Spring-Excel test"));
|
|
|
|
List words = (List) model.get("wordList");
|
|
for (int i = 0; i < words.size(); i++) {
|
|
sheet.addCell(new Label(2+i, 0, (String) words.get(i)));
|
|
}
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Note the differences between the APIs. We've found that the
|
|
JExcelApi is somewhat more intuitive, and furthermore, JExcelApi has
|
|
slightly better image-handling capabilities. There have been memory
|
|
problems with large Excel files when using JExcelApi however.</para>
|
|
|
|
<para>If you now amend the controller such that it returns
|
|
<literal>xl</literal> as the name of the view (<literal>return new
|
|
ModelAndView("xl", map);</literal>) and run your application again,
|
|
you should find that the Excel spreadsheet is created and downloaded
|
|
automatically when you request the same page as before.</para>
|
|
</section>
|
|
|
|
<section id="view-document-configsubclasspdf">
|
|
<title>Subclassing for PDF views</title>
|
|
|
|
<para>The PDF version of the word list is even simpler. This time, the
|
|
class extends
|
|
<literal>org.springframework.web.servlet.view.document.AbstractPdfView</literal>
|
|
and implements the <literal>buildPdfDocument()</literal> method as
|
|
follows:</para>
|
|
|
|
<programlisting language="java">package pdf;
|
|
|
|
// imports omitted for brevity
|
|
|
|
public class PDFPage extends AbstractPdfView {
|
|
|
|
protected void buildPdfDocument(
|
|
Map model,
|
|
Document doc,
|
|
PdfWriter writer,
|
|
HttpServletRequest req,
|
|
HttpServletResponse resp)
|
|
throws Exception {
|
|
|
|
List words = (List) model.get("wordList");
|
|
|
|
for (int i=0; i<words.size(); i++)
|
|
doc.add( new Paragraph((String) words.get(i)));
|
|
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Once again, amend the controller to return the
|
|
<literal>pdf</literal> view with <literal>return new
|
|
ModelAndView("pdf", map);</literal>, and reload the URL in your
|
|
application. This time a PDF document should appear listing each of
|
|
the words in the model map.</para>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports">
|
|
<title>JasperReports</title>
|
|
|
|
<para>JasperReports (<ulink
|
|
url="http://jasperreports.sourceforge.net"></ulink>) is a powerful
|
|
open-source reporting engine that supports the creation of report designs
|
|
using an easily understood XML file format. JasperReports is capable of
|
|
rendering reports in four different formats: CSV, Excel, HTML and
|
|
PDF.</para>
|
|
|
|
<section id="view-jasper-reports-dependencies">
|
|
<title>Dependencies</title>
|
|
|
|
<para>Your application will need to include the latest release of
|
|
JasperReports, which at the time of writing was 0.6.1. JasperReports
|
|
itself depends on the following projects:</para>
|
|
|
|
<itemizedlist mark="bullet">
|
|
<listitem>
|
|
<para>BeanShell</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Commons BeanUtils</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Commons Collections</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Commons Digester</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Commons Logging</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>iText</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>POI</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>JasperReports also requires a JAXP compliant XML parser.</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-configuration">
|
|
<title>Configuration</title>
|
|
|
|
<para>To configure JasperReports views in your Spring container
|
|
configuration you need to define a
|
|
<interfacename>ViewResolver</interfacename> to map view names to the
|
|
appropriate view class depending on which format you want your report
|
|
rendered in.</para>
|
|
|
|
<section id="view-jasper-reports-configuration-resolver">
|
|
<title>Configuring the
|
|
<interfacename>ViewResolver</interfacename></title>
|
|
|
|
<para>Typically, you will use the
|
|
<classname>ResourceBundleViewResolver</classname> to map view names to
|
|
view classes and files in a properties file.</para>
|
|
|
|
<programlisting language="xml"><bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
|
|
<property name="basename" value="views"/>
|
|
</bean></programlisting>
|
|
|
|
<para>Here we've configured an instance of the
|
|
<classname>ResourceBundleViewResolver</classname> class that will look
|
|
for view mappings in the resource bundle with base name
|
|
<literal>views</literal>. (The content of this file is described in
|
|
the next section.)</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-configuration-views">
|
|
<title>Configuring the <literal>View</literal>s</title>
|
|
|
|
<para>The Spring Framework contains five different
|
|
<interfacename>View</interfacename> implementations for JasperReports,
|
|
four of which correspond to one of the four output formats supported
|
|
by JasperReports, and one that allows for the format to be determined
|
|
at runtime:</para>
|
|
|
|
<table id="view-jasper-reports-configuration-views-classes">
|
|
<title>JasperReports <interfacename>View</interfacename>
|
|
classes</title>
|
|
|
|
<tgroup cols="2">
|
|
<colspec colname="c1" colwidth="1*" />
|
|
|
|
<colspec colname="c2" colwidth="1*" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Class Name</entry>
|
|
|
|
<entry>Render Format</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><classname>JasperReportsCsvView</classname></entry>
|
|
|
|
<entry>CSV</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><classname>JasperReportsHtmlView</classname></entry>
|
|
|
|
<entry>HTML</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><classname>JasperReportsPdfView</classname></entry>
|
|
|
|
<entry>PDF</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><classname>JasperReportsXlsView</classname></entry>
|
|
|
|
<entry>Microsoft Excel</entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><classname>JasperReportsMultiFormatView</classname></entry>
|
|
|
|
<entry>The view is <link
|
|
linkend="view-jasper-reports-configuration-multiformat-view">decided
|
|
upon at runtime</link></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>Mapping one of these classes to a view name and a report file is
|
|
a matter of adding the appropriate entries in the resource bundle
|
|
configured in the previous section as shown here:</para>
|
|
|
|
<programlisting>simpleReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
|
|
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper</programlisting>
|
|
|
|
<para>Here you can see that the view with name
|
|
<literal>simpleReport</literal> is mapped to the
|
|
<classname>JasperReportsPdfView</classname> class, causing the output
|
|
of this report to be rendered in PDF format. The
|
|
<literal>url</literal> property of the view is set to the location of
|
|
the underlying report file.</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-configuration-report-files">
|
|
<title>About Report Files</title>
|
|
|
|
<para>JasperReports has two distinct types of report file: the design
|
|
file, which has a <literal>.jrxml</literal> extension, and the
|
|
compiled report file, which has a <literal>.jasper</literal>
|
|
extension. Typically, you use the JasperReports Ant task to compile
|
|
your <literal>.jrxml</literal> design file into a
|
|
<literal>.jasper</literal> file before deploying it into your
|
|
application. With the Spring Framework you can map either of these
|
|
files to your report file and the framework will take care of
|
|
compiling the <literal>.jrxml</literal> file on the fly for you. You
|
|
should note that after a <literal>.jrxml</literal> file is compiled by
|
|
the Spring Framework, the compiled report is cached for the lifetime
|
|
of the application. Thus, to make changes to the file you will need to
|
|
restart your application.</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-configuration-multiformat-view">
|
|
<title>Using
|
|
<classname>JasperReportsMultiFormatView</classname></title>
|
|
|
|
<para>The <classname>JasperReportsMultiFormatView</classname> allows
|
|
for the report format to be specified at runtime. The actual rendering of
|
|
the report is delegated to one of the other JasperReports view classes
|
|
- the <classname>JasperReportsMultiFormatView</classname> class simply
|
|
adds a wrapper layer that allows for the exact implementation to be
|
|
specified at runtime.</para>
|
|
|
|
<para>The <classname>JasperReportsMultiFormatView</classname> class
|
|
introduces two concepts: the format key and the discriminator key. The
|
|
<classname>JasperReportsMultiFormatView</classname> class uses the
|
|
mapping key to look up the actual view implementation class, and it uses
|
|
the format key to lookup up the mapping key. From a coding perspective
|
|
you add an entry to your model with the format key as the key and the
|
|
mapping key as the value, for example:</para>
|
|
|
|
<programlisting language="java">public ModelAndView handleSimpleReportMulti(HttpServletRequest request,
|
|
HttpServletResponse response) throws Exception {
|
|
|
|
String uri = request.getRequestURI();
|
|
String format = uri.substring(uri.lastIndexOf(".") + 1);
|
|
|
|
Map model = getModel();
|
|
model.put("format", format);
|
|
|
|
return new ModelAndView("simpleReportMulti", model);
|
|
}</programlisting>
|
|
|
|
<para>In this example, the mapping key is determined from the
|
|
extension of the request URI and is added to the model under the
|
|
default format key: <literal>format</literal>. If you wish to use a
|
|
different format key then you can configure this using the
|
|
<literal>formatKey</literal> property of the
|
|
<classname>JasperReportsMultiFormatView</classname> class.</para>
|
|
|
|
<para>By default the following mapping key mappings are configured in
|
|
<classname>JasperReportsMultiFormatView</classname>:</para>
|
|
|
|
<table id="view-jasper-reports-configuration-multiformat-view-mappings">
|
|
<title><classname>JasperReportsMultiFormatView</classname> Default
|
|
Mapping Key Mappings</title>
|
|
|
|
<tgroup cols="2">
|
|
<colspec colname="c1" colwidth="1*" />
|
|
|
|
<colspec colname="c2" colwidth="1*" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Mapping Key</entry>
|
|
|
|
<entry>View Class</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry>csv</entry>
|
|
|
|
<entry><classname>JasperReportsCsvView</classname></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>html</entry>
|
|
|
|
<entry><classname>JasperReportsHtmlView</classname></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>pdf</entry>
|
|
|
|
<entry><classname>JasperReportsPdfView</classname></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry>xls</entry>
|
|
|
|
<entry><classname>JasperReportsXlsView</classname></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>So in the example above a request to URI /foo/myReport.pdf would
|
|
be mapped to the <literal>JasperReportsPdfView</literal> class. You
|
|
can override the mapping key to view class mappings using the
|
|
<literal>formatMappings</literal> property of
|
|
<classname>JasperReportsMultiFormatView</classname>.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-model">
|
|
<title>Populating the <classname>ModelAndView</classname></title>
|
|
|
|
<para>In order to render your report correctly in the format you have
|
|
chosen, you must supply Spring with all of the data needed to populate
|
|
your report. For JasperReports this means you must pass in all report
|
|
parameters along with the report datasource. Report parameters are
|
|
simple name/value pairs and can be added to the
|
|
<interfacename>Map</interfacename> for your model as you would add any
|
|
name/value pair.</para>
|
|
|
|
<para>When adding the datasource to the model you have two approaches to
|
|
choose from. The first approach is to add an instance of
|
|
<classname>JRDataSource</classname> or a
|
|
<interfacename>Collection</interfacename> type to the model
|
|
<interfacename>Map</interfacename> under any arbitrary key. Spring will
|
|
then locate this object in the model and treat it as the report
|
|
datasource. For example, you may populate your model like so:</para>
|
|
|
|
<programlisting language="java">private Map getModel() {
|
|
Map model = new HashMap();
|
|
Collection beanData = getBeanData();
|
|
model.put("myBeanData", beanData);
|
|
return model;
|
|
}</programlisting>
|
|
|
|
<para>The second approach is to add the instance of
|
|
<literal>JRDataSource</literal> or <literal>Collection</literal> under a
|
|
specific key and then configure this key using the
|
|
<literal>reportDataKey</literal> property of the view class. In both
|
|
cases Spring will wrap instances of <literal>Collection</literal> in a
|
|
<literal>JRBeanCollectionDataSource</literal> instance. For
|
|
example:</para>
|
|
|
|
<programlisting language="java">private Map getModel() {
|
|
Map model = new HashMap();
|
|
Collection beanData = getBeanData();
|
|
Collection someData = getSomeData();
|
|
model.put("myBeanData", beanData);
|
|
model.put("someData", someData);
|
|
return model;
|
|
}</programlisting>
|
|
|
|
<para>Here you can see that two <literal>Collection</literal> instances
|
|
are being added to the model. To ensure that the correct one is used, we
|
|
simply modify our view configuration as appropriate:</para>
|
|
|
|
<programlisting>simpleReport.(class)=org.springframework.web.servlet.view.jasperreports.JasperReportsPdfView
|
|
simpleReport.url=/WEB-INF/reports/DataSourceReport.jasper
|
|
simpleReport.reportDataKey=myBeanData</programlisting>
|
|
|
|
<para>Be aware that when using the first approach, Spring will use the
|
|
first instance of <literal>JRDataSource</literal> or
|
|
<literal>Collection</literal> that it encounters. If you need to place
|
|
multiple instances of <literal>JRDataSource</literal> or
|
|
<literal>Collection</literal> into the model you need to use the
|
|
second approach.</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-subreports">
|
|
<title>Working with Sub-Reports</title>
|
|
|
|
<para>JasperReports provides support for embedded sub-reports within
|
|
your master report files. There are a wide variety of mechanisms for
|
|
including sub-reports in your report files. The easiest way is to hard
|
|
code the report path and the SQL query for the sub report into your
|
|
design files. The drawback of this approach is obvious: the values are
|
|
hard-coded into your report files reducing reusability and making it
|
|
harder to modify and update report designs. To overcome this you can
|
|
configure sub-reports declaratively, and you can include additional data
|
|
for these sub-reports directly from your controllers.</para>
|
|
|
|
<section id="view-jasper-reports-subreports-config-reports">
|
|
<title>Configuring Sub-Report Files</title>
|
|
|
|
<para>To control which sub-report files are included in a master
|
|
report using Spring, your report file must be configured to accept
|
|
sub-reports from an external source. To do this you declare a
|
|
parameter in your report file like so:</para>
|
|
|
|
<programlisting language="xml"><parameter name="ProductsSubReport" class="net.sf.jasperreports.engine.JasperReport"/></programlisting>
|
|
|
|
<para>Then, you define your sub-report to use this sub-report
|
|
parameter:</para>
|
|
|
|
<programlisting language="xml"><subreport>
|
|
<reportElement isPrintRepeatedValues="false" x="5" y="25" width="325"
|
|
height="20" isRemoveLineWhenBlank="true" backcolor="#ffcc99"/>
|
|
<subreportParameter name="City">
|
|
<subreportParameterExpression><![CDATA[$F{city}]]></subreportParameterExpression>
|
|
</subreportParameter>
|
|
<dataSourceExpression><![CDATA[$P{SubReportData}]]></dataSourceExpression>
|
|
<subreportExpression class="net.sf.jasperreports.engine.JasperReport">
|
|
<![CDATA[$P{ProductsSubReport}]]></subreportExpression>
|
|
</subreport></programlisting>
|
|
|
|
<para>This defines a master report file that expects the sub-report to
|
|
be passed in as an instance of
|
|
<literal>net.sf.jasperreports.engine.JasperReports</literal> under the
|
|
parameter <literal>ProductsSubReport</literal>. When configuring your
|
|
Jasper view class, you can instruct Spring to load a report file and
|
|
pass it into the JasperReports engine as a sub-report using the
|
|
<literal>subReportUrls</literal> property:</para>
|
|
|
|
<programlisting language="xml"><property name="subReportUrls">
|
|
<map>
|
|
<entry key="ProductsSubReport" value="/WEB-INF/reports/subReportChild.jrxml"/>
|
|
</map>
|
|
</property></programlisting>
|
|
|
|
<para>Here, the key of the <interfacename>Map</interfacename>
|
|
corresponds to the name of the sub-report parameter in the report
|
|
design file, and the entry is the URL of the report file. Spring will
|
|
load this report file, compiling it if necessary, and pass it into
|
|
the JasperReports engine under the given key.</para>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-subreports-config-datasources">
|
|
<title>Configuring Sub-Report Data Sources</title>
|
|
|
|
<para>This step is entirely optional when using Spring to configure your
|
|
sub-reports. If you wish, you can still configure the data source for
|
|
your sub-reports using static queries. However, if you want Spring to
|
|
convert data returned in your <literal>ModelAndView</literal> into
|
|
instances of <literal>JRDataSource</literal> then you need to specify
|
|
which of the parameters in your <literal>ModelAndView</literal> Spring
|
|
should convert. To do this, configure the list of parameter names using
|
|
the <literal>subReportDataKeys</literal> property of your chosen
|
|
view class:</para>
|
|
|
|
<programlisting language="xml"><property name="subReportDataKeys" value="SubReportData"/></programlisting>
|
|
|
|
<para>Here, the key you supply <emphasis role="bold">must</emphasis>
|
|
correspond to both the key used in your <literal>ModelAndView</literal>
|
|
and the key used in your report design file.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-jasper-reports-exporter-parameters">
|
|
<title>Configuring Exporter Parameters</title>
|
|
|
|
<para>If you have special requirements for exporter configuration --
|
|
perhaps you want a specific page size for your PDF report -- you can
|
|
configure these exporter parameters declaratively in your Spring
|
|
configuration file using the <literal>exporterParameters</literal>
|
|
property of the view class. The <literal>exporterParameters</literal>
|
|
property is typed as a <interfacename>Map</interfacename>. In your
|
|
configuration the key of an entry should be the fully-qualified name of
|
|
a static field that contains the exporter parameter definition, and the
|
|
value of an entry should be the value you want to assign to the
|
|
parameter. An example of this is shown below:</para>
|
|
|
|
<programlisting language="xml"><bean id="htmlReport" class="org.springframework.web.servlet.view.jasperreports.JasperReportsHtmlView">
|
|
<property name="url" value="/WEB-INF/reports/simpleReport.jrxml"/>
|
|
<property name="exporterParameters">
|
|
<map>
|
|
<entry key="net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER">
|
|
<value>Footer by Spring!
|
|
&lt;/td&gt;&lt;td width="50%"&gt;&amp;nbsp; &lt;/td&gt;&lt;/tr&gt;
|
|
&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;
|
|
</value>
|
|
</entry>
|
|
</map>
|
|
</property>
|
|
</bean></programlisting>
|
|
|
|
<para>Here you can see that the
|
|
<classname>JasperReportsHtmlView</classname> is configured with an
|
|
exporter parameter for
|
|
<literal>net.sf.jasperreports.engine.export.JRHtmlExporterParameter.HTML_FOOTER</literal>
|
|
which will output a footer in the resulting HTML.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="view-feeds">
|
|
<title>Feed Views</title>
|
|
|
|
<para>Both <classname>AbstractAtomFeedView</classname> and
|
|
<classname>AbstractRssFeedView</classname> inherit from the base class
|
|
<classname>AbstractFeedView</classname> and are used to provide Atom and
|
|
RSS Feed views respectfully. They are based on java.net's <ulink
|
|
url="https://rome.dev.java.net">ROME</ulink> project and are located in
|
|
the package
|
|
<literal>org.springframework.web.servlet.view.feed</literal>.</para>
|
|
|
|
<para><classname>AbstractAtomFeedView</classname> requires you to
|
|
implement the <methodname>buildFeedEntries()</methodname> method and
|
|
optionally override the <methodname>buildFeedMetadata()</methodname> method
|
|
(the default implementation is empty), as shown below.</para>
|
|
|
|
<programlisting language="java">public class SampleContentAtomView extends AbstractAtomFeedView {
|
|
|
|
@Override
|
|
protected void buildFeedMetadata(Map<String, Object> model, Feed feed,
|
|
HttpServletRequest request) {
|
|
// implementation omitted
|
|
}
|
|
|
|
@Override
|
|
protected List<Entry> buildFeedEntries(Map<String, Object> model,
|
|
HttpServletRequest request, HttpServletResponse response)
|
|
throws Exception {
|
|
|
|
// implementation omitted
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Similar requirements apply for implementing
|
|
<classname>AbstractRssFeedView</classname>, as shown below.</para>
|
|
|
|
<programlisting language="java">public class SampleContentAtomView extends AbstractRssFeedView {
|
|
|
|
@Override
|
|
protected void buildFeedMetadata(Map<String, Object> model, Channel feed,
|
|
HttpServletRequest request) {
|
|
// implementation omitted
|
|
}
|
|
|
|
@Override
|
|
protected List<Item> buildFeedItems(Map<String, Object> model,
|
|
HttpServletRequest request, HttpServletResponse response)
|
|
throws Exception {
|
|
// implementation omitted
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The <methodname>buildFeedItems()</methodname> and
|
|
<methodname>buildFeedEntires()</methodname> methods pass in the HTTP request in case
|
|
you need to access the Locale. The HTTP response is passed in only for the
|
|
setting of cookies or other HTTP headers. The feed will automatically be
|
|
written to the response object after the method returns.</para>
|
|
|
|
<para>For an example of creating an Atom view please refer to Alef
|
|
Arendsen's SpringSource Team Blog <ulink
|
|
url="http://blog.springsource.com/2009/03/16/adding-an-atom-view-to-an-application-using-springs-rest-support/">entry</ulink>.</para>
|
|
</section>
|
|
|
|
<section id="view-xml-marshalling">
|
|
<title>XML Marshalling View</title>
|
|
|
|
<para>The <classname>MarhsallingView</classname> uses an XML
|
|
<interfacename>Marshaller</interfacename> defined in the
|
|
<classname>org.springframework.oxm</classname> package to render the
|
|
response content as XML. The object to be marshalled can be set explicitly
|
|
using <classname>MarhsallingView</classname>'s
|
|
<property>modelKey</property> bean property. Alternatively, the view will
|
|
iterate over all model properties and marshal only those types that are
|
|
supported by the <interfacename>Marshaller</interfacename>. For more
|
|
information on the functionality in the
|
|
<classname>org.springframework.oxm</classname> package refer to the
|
|
chapter <link linkend="oxm">Marshalling XML using O/X
|
|
Mappers</link>.</para>
|
|
</section>
|
|
|
|
<section id="view-json-mapping">
|
|
<title>JSON Mapping View</title>
|
|
|
|
<para>The <classname>MappingJacksonJsonView</classname> uses the Jackson
|
|
library's <classname>ObjectMapper</classname> to render the response content
|
|
as JSON. By default, the entire contents of the model map (with the exception
|
|
of framework-specific classes) will be encoded as JSON. For cases where the
|
|
contents of the map need to be filtered, users may specify a specific set of
|
|
model attributes to encode via the <literal>RenderedAttributes</literal>
|
|
property. The <literal>extractValueFromSingleKeyModel</literal> property
|
|
may also be used to have the value in single-key models extracted and
|
|
serialized directly rather than as a map of model attributes.</para>
|
|
|
|
<para>JSON mapping can be customized as needed through the use of Jackson's provided
|
|
annotations. When further control is needed, a custom
|
|
<interfacename>ObjectMapper</interfacename> can be injected through the
|
|
<literal>ObjectMapper</literal> property for cases where custom JSON
|
|
serializers/deserializers need to be provided for specific types.</para>
|
|
|
|
</section>
|
|
|
|
</chapter>
|