2570 lines
110 KiB
XML
2570 lines
110 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/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>
|
|
|
|
<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.jar</filename> as well in the distribution
|
|
itself. 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.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 with type 'text' using the
|
|
bound value. For an example of this tag, see <xref
|
|
linkend="view-jsp-formtaglib-formtag" />.</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>
|
|
</section>
|
|
|
|
<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. <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>
|
|
|
|
<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 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>
|
|
</section>
|
|
|
|
<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 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 methods, 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>
|
|
</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>
|
|
|
|
<para><itemizedlist spacing="compact">
|
|
<listitem>
|
|
<para><literal>Tiles version 2.0.4 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></para>
|
|
|
|
<para>These dependencies are all available in the Spring
|
|
distribution.</para>
|
|
</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>
|
|
</section>
|
|
|
|
<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 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 both be used as view technologies within Spring MVC
|
|
applications. The languages are quite similar and serve similar needs and
|
|
so are considered together in this section. For semantic and syntactic
|
|
differences between the two languages, see the <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> needs also to be
|
|
available for Velocity. Typically they are included in the
|
|
<literal>WEB-INF/lib</literal> folder where they are guaranteed to be
|
|
found by a J2EE server and added to the classpath for your application.
|
|
It is of course assumed that you already have the <filename
|
|
class="libraryfile">spring.jar</filename> in your <filename
|
|
class="directory">'WEB-INF/lib'</filename> directory too! The latest
|
|
stable Velocity, FreeMarker and Commons Collections jars are supplied
|
|
with the Spring framework and can be copied from the relevant <filename
|
|
class="libraryfile">/lib/</filename> sub-directories. 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/2.5.x/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.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">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 the section entitled <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 J2EE 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.jar. Both are included
|
|
in the main Spring distribution.</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>Firstly, 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.. <programlisting>home.class=xslt.HomePage
|
|
home.stylesheetLocation=/WEB-INF/xsl/home.xslt
|
|
home.root=words
|
|
|
|
xl.class=excel.HomePage
|
|
|
|
pdf.class=pdf.HomePage</programlisting> <emphasis>If you want to start with a
|
|
template spreadsheet 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></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.. <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>
|
|
|
|
<para>And this a view generating the same Excel file, now using
|
|
JExcelApi: <programlisting language="java">package excel;
|
|
|
|
// imports omitted for brevity
|
|
|
|
public class HomePage extends AbstractExcelView {
|
|
|
|
protected void buildExcelDocument(Map model,
|
|
WritableWorkbook wb,
|
|
HttpServletRequest request,
|
|
HttpServletResponse response)
|
|
throws Exception {
|
|
|
|
WritableSheet sheet = wb.createSheet("Spring");
|
|
|
|
sheet.addCell(new Label(0, 0, "Spring-Excel test");
|
|
|
|
List words = (List)model.get("wordList");
|
|
for (int i = -; i < words.size(); i++) {
|
|
sheet.addCell(new Label(2+i, 0, (String)words.get(i));
|
|
}
|
|
}
|
|
}
|
|
</programlisting></para>
|
|
|
|
<para>Note the differences between the APIs. We've found that the
|
|
JExcelApi is somewhat more intuitive and furthermore, JExcelApi has a
|
|
bit better image-handling capabilities. There have been memory
|
|
problems with large Excel file 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.. <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> Once again, amend the controller to return the
|
|
<literal>pdf</literal> view with a <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 output into 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 into 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. 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 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 lookup the actual view implementation class and uses
|
|
the format key to lookup up the mapping key. From a coding perspective
|
|
you add an entry to your model with the formay 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 be 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 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 then 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 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 th report
|
|
design file, and the entry is the URL of the report file. Spring will
|
|
load this report file, compiling it if necessary, and will pass 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 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 the your chosen
|
|
view class: <programlisting language="xml"><property name="subReportDataKeys"
|
|
value="SubReportData"/></programlisting> Here, the key you supply MUST
|
|
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, then 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 <interfacename>Map</interfacename> and 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 being 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> 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 a Atom view please refer to Alef
|
|
Arendsen's SpringSource TeamBlog <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>
|
|
<title>XML Marshalling View</title>
|
|
|
|
<para>The <classname>MarhsallingView</classname> uses a 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 marhsall 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>
|
|
</chapter>
|