spring-framework/spring-framework-reference/src/mvc.xml

3217 lines
145 KiB
XML
Raw Normal View History

<?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="mvc">
<title>Web MVC framework</title>
<section id="mvc-introduction">
<title>Introduction</title>
<para>Spring's Web MVC framework is designed around a
<classname>DispatcherServlet</classname> that dispatches requests to
handlers, with configurable handler mappings, view resolution, locale and
theme resolution as well as support for uploading files. The default
handler is based on the <interfacename>@Controller</interfacename> and
<interfacename>@RequestMapping</interfacename> annotations, offering a
wide range of flexible handling methods. With the introduction of Spring
3.0, the <interfacename>@Controller</interfacename> mechanism also allows
your to create RESTful Web sites or application, though the
<interfacename>@PathVarariable</interfacename> annotation and other
features.</para>
<sidebar id="mvc-open-for-extension">
<title><quote>Open for extension...</quote></title>
<para>One of the overarching design principles in Spring Web MVC (and in
Spring in general) is the <quote><emphasis>Open for extension, closed
for modification</emphasis></quote> principle.</para>
<para>The reason that this principle is being mentioned here is because
a number of methods in the core classes in Spring Web MVC are marked
<literal>final</literal>. This means of course that you as a developer
cannot override these methods to supply your own behavior... this is
<emphasis>by design</emphasis> and has not been done arbitrarily to
annoy.</para>
<para>The book 'Expert Spring Web MVC and Web Flow' by Seth Ladd and
others explains this principle and the reasons for adhering to it in
some depth on page 117 (first edition) in the section entitled 'A Look
At Design'.</para>
<para>If you don't have access to the aforementioned book, then the
following article may be of interest the next time you find yourself
going <quote>Gah! Why can't I override this method?</quote> (if indeed
you ever do).</para>
<orderedlist>
<listitem>
<para><ulink
url="http://www.objectmentor.com/resources/articles/ocp.pdf">Bob
Martin, The Open-Closed Principle (PDF)</ulink></para>
</listitem>
</orderedlist>
<para>Note that you cannot add advice to final methods using Spring MVC.
This means it won't be possible to add advice to for example the
<literal>AbstractController.handleRequest()</literal> method. Refer to
<xref linkend="aop-understanding-aop-proxies" /> for more information on
AOP proxies and why you cannot add advice to final methods.</para>
</sidebar>
<para>Spring Web MVC allows you to use any object as a command or form
backing object - there is no need to implement a framework-specific
interface or base class. Spring's data binding is highly flexible: for
example, it treats type mismatches as validation errors that can be
evaluated by the application, not as system errors. All this means that
you don't need to duplicate your business objects' properties as simple,
untyped strings in your form objects just to be able to handle invalid
submissions, or to convert the Strings properly. Instead, it is often
preferable to bind directly to your business objects.</para>
<para>Spring's view resolution is extremely flexible. A
<interfacename>Controller</interfacename> implementation can even write
directly to the response stream. In the normal case, a
<classname>ModelAndView</classname> instance consists of a view name and a
model <interfacename>Map</interfacename>, which contains bean names and
corresponding objects (like a command or form, containing reference data).
View name resolution is highly configurable, either via bean names, via a
properties file, or via your own
<interfacename>ViewResolver</interfacename> implementation. The fact that
the model (the M in MVC) is based on the
<interfacename>Map</interfacename> interface allows for the complete
abstraction of the view technology. Any renderer can be integrated
directly, whether JSP, Velocity, or any other rendering technology. The
model <interfacename>Map</interfacename> is simply transformed into an
appropriate format, such as JSP request attributes or a Velocity template
model.</para>
<section id="mvc-introduction-pluggability">
<title>Pluggability of other MVC implementations</title>
<para>There are several reasons why some projects will prefer to use
other MVC implementations. Many teams expect to leverage their existing
investment in skills and tools. In addition, there is a large body of
knowledge and experience available for the Struts framework. Thus, if
you can live with Struts' architectural flaws, it can still be a viable
choice for the web layer; the same applies to WebWork and other web MVC
frameworks.</para>
<para>If you don't want to use Spring's web MVC, but intend to leverage
other solutions that Spring offers, you can integrate the web MVC
framework of your choice with Spring easily. Simply start up a Spring
root application context via its
<classname>ContextLoaderListener</classname>, and access it via its
<interfacename>ServletContext</interfacename> attribute (or Spring's
respective helper method) from within a Struts or WebWork action. Note
that there aren't any "plug-ins" involved, so no dedicated integration
is necessary. From the web layer's point of view, you'll simply use
Spring as a library, with the root application context instance as the
entry point.</para>
<para>All your registered beans and all of Spring's services can be at
your fingertips even without Spring's Web MVC. Spring doesn't compete
with Struts or WebWork in this scenario, it just addresses the many
areas that the pure web MVC frameworks don't, from bean configuration to
data access and transaction handling. So you are able to enrich your
application with a Spring middle tier and/or data access tier, even if
you just want to use, for example, the transaction abstraction with JDBC
or Hibernate.</para>
</section>
<section id="mvc-features">
<title>Features of Spring Web MVC</title>
<xi:include href="swf-sidebar.xml"
xmlns:xi="http://www.w3.org/2001/XInclude" />
<para>Spring's web module provides a wealth of unique web support
features, including:</para>
<itemizedlist>
<listitem>
<para>Clear separation of roles - controller, validator, command
object, form object, model object,
<classname>DispatcherServlet</classname>, handler mapping, view
resolver, etc. Each role can be fulfilled by a specialized
object.</para>
</listitem>
<listitem>
<para>Powerful and straightforward configuration of both framework
and application classes as JavaBeans, including easy referencing
across contexts, such as from web controllers to business objects
and validators.</para>
</listitem>
<listitem>
<para>Adaptability, non-intrusiveness, and flexibility. Define
whatever controller method signature you need, possibly using one of
the parameter annotations (such as @RequestParam, @RequestHeader,
@PathVariable, and more) for a given scenario.</para>
</listitem>
<listitem>
<para>Reusable business code - no need for duplication. You can use
existing business objects as command or form objects instead of
mirroring them in order to extend a particular framework base
class.</para>
</listitem>
<listitem>
<para>Customizable binding and validation - type mismatches as
application-level validation errors that keep the offending value,
localized date and number binding, etc instead of String-only form
objects with manual parsing and conversion to business
objects.</para>
</listitem>
<listitem>
<para>Customizable handler mapping and view resolution - handler
mapping and view resolution strategies range from simple URL-based
configuration, to sophisticated, purpose-built resolution
strategies. This is more flexible than some web MVC frameworks which
mandate a particular technique.</para>
</listitem>
<listitem>
<para>Flexible model transfer - model transfer via a name/value
<interfacename>Map</interfacename> supports easy integration with
any view technology.</para>
</listitem>
<listitem>
<para>Customizable locale and theme resolution, support for JSPs
with or without Spring tag library, support for JSTL, support for
Velocity without the need for extra bridges, etc.</para>
</listitem>
<listitem>
<para>A simple yet powerful JSP tag library known as the Spring tag
library that provides support for features such as data binding and
themes. The custom tags allow for maximum flexibility in terms of
markup code. For information on the tag library descriptor, see the
appendix entitled <xref linkend="spring.tld" /></para>
</listitem>
<listitem>
<para>A JSP form tag library, introduced in Spring 2.0, that makes
writing forms in JSP pages much easier. For information on the tag
library descriptor, see the appendix entitled <xref
linkend="spring-form.tld" /></para>
</listitem>
<listitem>
<para>Beans whose lifecycle is scoped to the current HTTP request or
HTTP <interfacename>Session</interfacename>. This is not a specific
feature of Spring MVC itself, but rather of the
<interfacename>WebApplicationContext</interfacename> container(s)
that Spring MVC uses. These bean scopes are described in detail in
the section entitled <xref
linkend="beans-factory-scopes-other" /></para>
</listitem>
</itemizedlist>
</section>
</section>
<section id="mvc-servlet">
<title>The <classname>DispatcherServlet</classname></title>
<para>Spring's web MVC framework is, like many other web MVC frameworks,
request-driven, designed around a central servlet that dispatches requests
to controllers and offers other functionality facilitating the development
of web applications. Spring's <classname>DispatcherServlet</classname>
however, does more than just that. It is completely integrated with the
Spring IoC container and as such allows you to use every other feature
that Spring has.</para>
<para>The request processing workflow of the Spring Web MVC
<classname>DispatcherServlet</classname> is illustrated in the following
diagram. The pattern-savvy reader will recognize that the
<classname>DispatcherServlet</classname> is an expression of the
<quote>Front Controller</quote> design pattern (this is a pattern that
Spring Web MVC shares with many other leading web frameworks).</para>
<para><mediaobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/mvc.png" format="PNG" />
</imageobject>
<imageobject role="html">
<imagedata align="center" fileref="images/mvc.png" format="PNG" />
</imageobject>
<caption><para>The requesting processing workflow in Spring Web MVC
(high level)</para></caption>
</mediaobject></para>
<para>The <classname>DispatcherServlet</classname> <emphasis>is</emphasis>
an actual <interfacename>Servlet</interfacename> (it inherits from the
<classname>HttpServlet</classname> base class), and as such is declared in
the <literal>web.xml</literal> of your web application. Requests that you
want the <classname>DispatcherServlet</classname> to handle will have to
be mapped using a URL mapping in the same <literal>web.xml</literal> file.
This is standard J2EE servlet configuration; an example of such a
<classname>DispatcherServlet</classname> declaration and mapping can be
found below.</para>
<programlisting language="xml">&lt;web-app&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;example&lt;/servlet-name&gt;
&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;example&lt;/servlet-name&gt;
&lt;url-pattern&gt;*.form&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;/web-app&gt;</programlisting>
<para>In the example above, all requests ending with
<literal>.form</literal> will be handled by the
<literal>'example'</literal> <classname>DispatcherServlet</classname>.
This is only the first step in setting up Spring Web MVC... the various
beans used by the Spring Web MVC framework (over and above the
<classname>DispatcherServlet</classname> itself) now need to be
configured.</para>
<para>As detailed in the section entitled <xref
linkend="context-introduction" />,
<interfacename>ApplicationContext</interfacename> instances in Spring can
be scoped. In the web MVC framework, each
<classname>DispatcherServlet</classname> has its own
<interfacename>WebApplicationContext</interfacename>, which inherits all
the beans already defined in the root
<interfacename>WebApplicationContext</interfacename>. These inherited
beans defined can be overridden in the servlet-specific scope, and new
scope-specific beans can be defined local to a given servlet
instance.</para>
<para><mediaobject>
<imageobject role="fo">
<imagedata align="center" fileref="images/mvc-contexts.gif"
format="GIF" />
</imageobject>
<imageobject role="html">
<imagedata align="center" fileref="images/mvc-contexts.gif"
format="GIF" />
</imageobject>
<caption><para>Context hierarchy in Spring Web MVC</para></caption>
</mediaobject></para>
<para>The framework will, on initialization of a
<classname>DispatcherServlet</classname>, <emphasis>look for a file named
<literal>[servlet-name]-servlet.xml</literal></emphasis> in the
<literal>WEB-INF</literal> directory of your web application and create
the beans defined there (overriding the definitions of any beans defined
with the same name in the global scope).</para>
<para>Consider the following <classname>DispatcherServlet</classname>
servlet configuration (in the <literal>'web.xml'</literal> file.)</para>
<programlisting language="xml">&lt;web-app&gt;
&lt;servlet&gt;
&lt;servlet-name&gt;<emphasis role="bold">golfing</emphasis>&lt;/servlet-name&gt;
&lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
&lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
&lt;/servlet&gt;
&lt;servlet-mapping&gt;
&lt;servlet-name&gt;<emphasis role="bold">golfing</emphasis>&lt;/servlet-name&gt;
&lt;url-pattern&gt;/golfing/*&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;
&lt;/web-app&gt;</programlisting>
<para>With the above servlet configuration in place, you will need to have
a file called <literal>'/WEB-INF/<emphasis
role="bold">golfing</emphasis>-servlet.xml'</literal> in your application;
this file will contain all of your <emphasis>Spring Web
MVC-specific</emphasis> components (beans). The exact location of this
configuration file can be changed via a servlet initialization parameter
(see below for details).</para>
<para>The <interfacename>WebApplicationContext</interfacename> is an
extension of the plain <interfacename>ApplicationContext</interfacename>
that has some extra features necessary for web applications. It differs
from a normal <interfacename>ApplicationContext</interfacename> in that it
is capable of resolving themes (see <xref linkend="mvc-themeresolver" />),
and that it knows which servlet it is associated with (by having a link to
the <interfacename>ServletContext</interfacename>). The
<interfacename>WebApplicationContext</interfacename> is bound in the
<interfacename>ServletContext</interfacename>, and by using static methods
on the <classname>RequestContextUtils</classname> class you can always
lookup the <interfacename>WebApplicationContext</interfacename> in case
you need access to it.</para>
<para>The Spring <classname>DispatcherServlet</classname> has a couple of
special beans it uses in order to be able to process requests and render
the appropriate views. These beans are included in the Spring framework
and can be configured in the
<interfacename>WebApplicationContext</interfacename>, just as any other
bean would be configured. Each of those beans is described in more detail
below. Right now, we'll just mention them, just to let you know they exist
and to enable us to go on talking about the
<classname>DispatcherServlet</classname>. For most of the beans, sensible
defaults are provided so you don't (initially) have to worry about
configuring them.</para>
<table id="mvc-webappctx-special-beans-tbl">
<title>Special beans in the
<interfacename>WebApplicationContext</interfacename></title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="4*" />
<thead>
<row>
<entry>Bean type</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry>Controllers</entry>
<entry><link linkend="mvc-controller">Controllers</link> are the
components that form the <literal>'C'</literal> part of the
MVC.</entry>
</row>
<row>
<entry>Handler mappings</entry>
<entry><link linkend="mvc-handlermapping">Handler mappings</link>
handle the execution of a list of pre- and post-processors and
controllers that will be executed if they match certain criteria
(for instance a matching URL specified with the
controller)</entry>
</row>
<row>
<entry>View resolvers</entry>
<entry><link linkend="mvc-viewresolver">View resolvers</link> are
components capable of resolving view names to views</entry>
</row>
<row>
<entry>Locale resolver</entry>
<entry>A <link linkend="mvc-localeresolver">locale resolver</link>
is a component capable of resolving the locale a client is using,
in order to be able to offer internationalized views</entry>
</row>
<row>
<entry>Theme resolver</entry>
<entry>A <link linkend="mvc-themeresolver">theme resolver</link>
is capable of resolving themes your web application can use, for
example, to offer personalized layouts</entry>
</row>
<row>
<entry>multipart file resolver</entry>
<entry>A <link linkend="mvc-multipart">multipart file
resolver</link> offers the functionality to process file uploads
from HTML forms</entry>
</row>
<row>
<entry>Handler exception resolver(s)</entry>
<entry><link linkend="mvc-exceptionhandlers">Handler exception
resolvers</link> offer functionality to map exceptions to views or
implement other more complex exception handling code</entry>
</row>
</tbody>
</tgroup>
</table>
<para>When a <classname>DispatcherServlet</classname> is set up for use
and a request comes in for that specific
<classname>DispatcherServlet</classname>, said
<classname>DispatcherServlet</classname> starts processing the request.
The list below describes the complete process a request goes through when
handled by a <classname>DispatcherServlet</classname>:</para>
<orderedlist>
<listitem>
<para>The <interfacename>WebApplicationContext</interfacename> is
searched for and bound in the request as an attribute in order for the
controller and other elements in the process to use. It is bound by
default under the key
<literal>DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE</literal>.</para>
</listitem>
<listitem>
<para>The locale resolver is bound to the request to let elements in
the process resolve the locale to use when processing the request
(rendering the view, preparing data, etc.) If you don't use the
resolver, it won't affect anything, so if you don't need locale
resolving, you don't have to use it.</para>
</listitem>
<listitem>
<para>The theme resolver is bound to the request to let elements such
as views determine which theme to use. The theme resolver does not
affect anything if you don't use it, so if you don't need themes you
can just ignore it.</para>
</listitem>
<listitem>
<para>If a multipart resolver is specified, the request is inspected
for multiparts; if multiparts are found, the request is wrapped in a
<classname>MultipartHttpServletRequest</classname> for further
processing by other elements in the process. (See the section entitled
<xref linkend="mvc-multipart-resolver" /> for further information
about multipart handling).</para>
</listitem>
<listitem>
<para>An appropriate handler is searched for. If a handler is found,
the execution chain associated with the handler (preprocessors,
postprocessors, and controllers) will be executed in order to prepare
a model (for rendering).</para>
</listitem>
<listitem>
<para>If a model is returned, the view is rendered. If no model is
returned (which could be due to a pre- or postprocessor intercepting
the request, for example, for security reasons), no view is rendered,
since the request could already have been fulfilled.</para>
</listitem>
</orderedlist>
<para>Exceptions that are thrown during processing of the request get
picked up by any of the handler exception resolvers that are declared in
the <interfacename>WebApplicationContext</interfacename>. Using these
exception resolvers allows you to define custom behaviors in case such
exceptions get thrown.</para>
<para>The Spring <classname>DispatcherServlet</classname> also has support
for returning the <emphasis>last-modification-date</emphasis>, as
specified by the Servlet API. The process of determining the last
modification date for a specific request is straightforward: the
<classname>DispatcherServlet</classname> will first lookup an appropriate
handler mapping and test if the handler that is found <emphasis>implements
the interface <interfacename>LastModified</interfacename></emphasis>
interface. If so, the value of the <literal>long
getLastModified(request)</literal> method of the
<interfacename>LastModified</interfacename> interface is returned to the
client.</para>
<para>You can customize Spring's <classname>DispatcherServlet</classname>
by adding context parameters in the <literal>web.xml</literal> file or
servlet initialization parameters. The possibilities are listed
below.</para>
<table id="mvc-disp-servlet-init-params-tbl">
<title><classname>DispatcherServlet</classname> initialization
parameters</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="4*" />
<thead>
<row>
<entry>Parameter</entry>
<entry>Explanation</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>contextClass</literal></entry>
<entry>Class that implements
<interfacename>WebApplicationContext</interfacename>, which will
be used to instantiate the context used by this servlet. If this
parameter isn't specified, the
<classname>XmlWebApplicationContext</classname> will be
used.</entry>
</row>
<row>
<entry><literal>contextConfigLocation</literal></entry>
<entry>String which is passed to the context instance (specified
by <literal>contextClass</literal>) to indicate where context(s)
can be found. The string is potentially split up into multiple
strings (using a comma as a delimiter) to support multiple
contexts (in case of multiple context locations, of beans that are
defined twice, the latest takes precedence).</entry>
</row>
<row>
<entry><literal>namespace</literal></entry>
<entry>the namespace of the
<interfacename>WebApplicationContext</interfacename>. Defaults to
<literal>[servlet-name]-servlet</literal>.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="mvc-controller">
<title>Controllers</title>
<para>The notion of a controller is part of the MVC design pattern (more
specifically, it is the <emphasis>'C'</emphasis> in MVC). Controllers
provide access to the application behavior which is typically defined by a
service interface. Controllers interpret user input and transform such
input into a sensible model which will be represented to the user by the
view. Spring has implemented the notion of a controller in a very abstract
way enabling a wide variety of different kinds of controllers to be
created.</para>
<para>Spring 2.5 introduced an annotation-based programming model for MVC
controllers, using annotations such as
<interfacename>@RequestMapping</interfacename>,
<interfacename>@RequestParam</interfacename>,
<interfacename>@ModelAttribute</interfacename>, etc. This annotation
support is available for both Servlet MVC and Portlet MVC. Controllers
implemented in this style do not have to extend specific base classes or
implement specific interfaces. Furthermore, they do not usually have
direct dependencies on Servlet or Portlet API's, although they can easily
get access to Servlet or Portlet facilities if desired.</para>
<tip>
<para>The Spring distribution ships with the
<emphasis>PetClinic</emphasis> sample, which is a web application that
takes advantage of the annotation support described in this section, in
the context of simple form processing. You can find the
<emphasis>PetClinic</emphasis> application in the
<literal>'samples/petclinic'</literal> directory.</para>
<para>For a further sample application that builds on annotation-based
Web MVC, check out <emphasis>imagedb</emphasis>. The focus in that
sample is on stateless multi-action controllers, including the
processing of multipart file uploads. You can find the
<emphasis>imagedb</emphasis> application in the
<literal>'samples/imagedb'</literal> directory.</para>
</tip>
<programlisting language="java">@Controller
public class HelloWorldController {
@RequestMapping("/helloWorld")
public ModelAndView helloWorld() {
ModelAndView mac = new ModelAndView();
mav.setViewName("helloWorld");
mav.addObject("message", "Hello World!");
return mav;
}
}</programlisting>
<para>As you can see, the <interfacename>@Controller</interfacename> and
<interfacename>@RequestMapping</interfacename> annotations allow for
flexible method names and signatures. In this particular example the
method has no parameters and returns a
<classname>ModelAndView</classname>, but various other (and better)
strategies exist, as will be explained later in this section.
<classname>ModelAndView</classname>,
<interfacename>@Controller</interfacename>, and
<interfacename>@RequestMapping</interfacename> form the basis for the
Spring MVC implementation. This section document these annotations and how
they are most commonly used in a Servlet environment.</para>
<section id="mvc-ann-controller">
<title>Defining a controller with
<interfacename>@Controller</interfacename></title>
<para>The <interfacename>@Controller</interfacename> annotation
indicates that a particular class serves the role of a
<emphasis>controller</emphasis>. There is no need to extend any
controller base class or reference the Servlet API. You are of course
still able to reference Servlet-specific features if you need to.</para>
<para>The basic purpose of the
<interfacename>@Controller</interfacename> annotation is to act as a
stereotype for the annotated class, indicating its role. The dispatcher
will scan such annotated classes for mapped methods, detecting
<interfacename>@RequestMapping</interfacename> annotations (see the next
section).</para>
<para>Annotated controller beans may be defined explicitly, using a
standard Spring bean definition in the dispatcher's context. However,
the <interfacename>@Controller</interfacename> stereotype also allows
for autodetection, aligned with Spring general support for detecting
component classes in the classpath and auto-registering bean definitions
for them.</para>
<para>To enable autodetection of such annotated controllers, you have to
add component scanning to your configuration. This is easily achieved by
using the <emphasis>spring-context</emphasis> schema as shown in the
following XML snippet:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd"&gt;
&lt;context:component-scan base-package="org.springframework.samples.petclinic.web"/&gt;
<lineannotation>// ...</lineannotation>
&lt;/beans&gt;</programlisting>
</section>
<section id="mvc-ann-requestmapping">
<title>Mapping requests with
<interfacename>@RequestMapping</interfacename></title>
<para>The <interfacename>@RequestMapping</interfacename> annotation is
used to map URLs like <filename>/appointments</filename> onto an entire
class or a particular handler method. It can be used to annotate both a
class or method, Typically the class-level annotation maps a specific
request path (or path pattern) onto a form controller, with additional
method-level annotations 'narrowing' the primary mapping for a specific
HTTP method request method ("GET"/"POST") or specific HTTP request
parameters.</para>
<para>The following example shows a controller from the PetClinic sample
application that uses this annotation:</para>
<programlisting language="java">@Controller
<emphasis role="bold">@RequestMapping("/appointments")</emphasis>
public class AppointmentsController {
private AppointmentBook appointmentBook;
@Autowired
public AppointmentsController(AppointmentBook appointmentBook) {
this.appointmentBook = appointmentBook;
}
<emphasis role="bold">@RequestMapping(method = RequestMethod.GET)</emphasis>
public Appointments get() {
return appointmentBook.getAppointmentsForToday();
}
<emphasis role="bold">@RequestMapping(value="/{day}", method = RequestMethod.GET)</emphasis>
public void getForDay(@PathVariable Date day, ExternalContext context) {
Appointments appts = appointmentBook.getAppointmentsForDay(day);
context.getModel().addAttribute(appts);
context.selectView("appointments");
if (context.isAjaxRequest()) {
//could activate a ViewHelper for component associated with main
context.renderFragment("main");
}
}
<emphasis role="bold">@RequestMapping(value="/new", method = RequestMethod.GET)</emphasis>
public AppointmentForm getNewForm() {
return new AppointmentForm();
}
<emphasis role="bold">@RequestMapping(method = RequestMethod.POST)</emphasis>
public String post(AppointmentForm form) {
appointmentBook.createAppointment(form);
return "redirect:/appointments";
}
}</programlisting>
<para>In the example, above, we see that the
<interfacename>@RequestMapping</interfacename> is used in a number of
places. The first usage is on the type (class) level, which indicates
that all handling methods on this controller will be relative to the
<filename>/appointments</filename> path. Next, we see that the
<methodname>get()</methodname> method has a further
<interfacename>@RequestMapping</interfacename> refinement: it only
accepts GET requests, meaning that an HTTP GET for
<filename>/appointments</filename> will result in this method being
invoked. The <methodname>post()</methodname> has a similar refinement,
and the <methodname>getNewForm()</methodname> combines the definition of
HTTP method and path into one, so that GET requests for
<filename>appointments/new</filename> are handled by that method.</para>
<para>The <methodname>getForDay()</methodname> method shows another
usage of <interfacename>@RequestMapping</interfacename>: URI templates.
We will discuss these in <link
linkend="mvc-ann-requestmapping-uri-templates">the next section
</link>.</para>
<para>A <interfacename>@RequestMapping</interfacename> on the class
level is not required. Without it, all paths are simply absolute, and
not relative. The following is an example of a multi-action controller
from the PetClinic sample application using
<classname>@RequestMapping</classname>:</para>
<programlisting language="java">@Controller
public class ClinicController {
private final Clinic clinic;
@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}
<emphasis role="bold">@RequestMapping("/")</emphasis>
public void welcomeHandler() {
}
<emphasis role="bold">@RequestMapping("/vets")</emphasis>
public ModelMap vetsHandler() {
return new ModelMap(this.clinic.getVets());
}
}</programlisting>
<section id="mvc-ann-requestmapping-uri-templates">
<title>URI Templates</title>
<para>To easily access (parts of) a request URL in your handling
methods, Spring MVC allows for the use of <emphasis>URI
templates</emphasis> in the
<interfacename>@RequestMapping</interfacename> path value.</para>
<sidebar id="mvc-uri-templates">
<title>URI Templates</title>
<para>A URI Template is a URI-like string, containing one or more
variable names. When these variables are substituted for values, the
template becomes a URI The <ulink
url="http://bitworking.org/projects/URI-Templates/">proposed
RFC</ulink> for URI Templates defines how an URI is parameterized.
For example, the URI Template</para>
<programlisting>http://www.example.com/users/{userid}</programlisting>
<para>contains the variable 'userid'. If we assign the variable the
value "fred", then 'expanding' the URI Template gives.</para>
<programlisting>http://www.example.com/users/fred</programlisting>
<para>When processing a request the URI can be compared to an
expected URI Template in order to extract a collection of
variables.</para>
</sidebar>
<para>The <interfacename>@PathVariable</interfacename> method
parameter annotation is used to indicate that a method parameter
should be bound to the value of a URI template variable.</para>
<para>The following code snippet shows the use of a single
<interfacename>@PathVariable</interfacename> in a controller
method:</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis> String ownerId, Model model) {
Owner owner = ownerService.findOwner(ownerId);
model.addAttribute("owner", owner);
return "displayOwner";
}
</programlisting>
<para>The URI Template "<literal>/owners/{ownerId}</literal>"
specifies the variable name ownerId. When the controller handles this
request, the value of ownerId is set the value in the request URI. For
example, when a request comes in for /owners/fred, the value 'fred' is
bound to the method parameter <literal>String
ownerId</literal>.</para>
<para>The matching of method parameter names to URI Template variable
names can only be done if your code is compiled with debugging
enabled. If you do have not debugging enabled, you must specify the
name of the URI Template variable name to bind to in the @PathVariable
annotation. For example:</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String ownerId, Model model) {
// implementation omitted
}
</programlisting>
<para>The name of the method parameter does not matter in this case,
so you may also use a controller method with the signature shown
below</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET)
public String findOwner(<emphasis role="bold">@PathVariable</emphasis>("ownerId") String theOwner, Model model) {
// implementation omitted
}</programlisting>
<para>Multiple @PathVariable annotations can be used to bind to
multiple URI Template variables as shown below:</para>
<programlisting language="java">@RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET)
public String findPet(<emphasis role="bold">@PathVariable</emphasis> String ownerId, <emphasis
role="bold">@PathVariable</emphasis> String petId, Model model) {
Owner owner = ownerService.findOwner(ownderId);
Pet pet = owner.getPet(petId);
model.addAttribute("pet", pet);
return "displayPet";
}
</programlisting>
<para>The following code snippet shows the use of path variables on a
relative path, so that the <methodname>findPet()</methodname> method
will be invoked for <filename>/owners/42/pets/21</filename>, for
instance.</para>
<programlisting language="java">@Controller
@RequestMapping(<emphasis role="bold">"/owners/{ownerId}"</emphasis>)
public class RelativePathUriTemplateController {
@RequestMapping(<emphasis role="bold">"/pets/{petId}"</emphasis>)
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
</programlisting>
<tip>
<para>Method parameters that are decorated with the
<interfacename>@PathVariable</interfacename> annotation can be of
<emphasis role="bold">any simple type </emphasis>such as int, long,
Date... Spring automatically converts to the appropriate type and
throws a <classname>TypeMismatchException</classname> if the type is
not correct. You can further customizing this conversion process by
customizing the data binder, see <xref
linkend="mvc-ann-webdatabinder" />.</para>
</tip>
</section>
<section id="mvc-ann-requestmapping-advanced">
<title>Advanced <interfacename>@RequestMapping</interfacename>
options</title>
<para>In addition to URI templates, the
<interfacename>@RequestMapping</interfacename> annotation also
supports Ant-style path patterns (e.g.
<filename>/myPath/*.do</filename>). A combination of URI templates and
Ant-style globs is also supported (e.g.
<filename>/owners/*/pets/{petId}</filename>).</para>
<para>The handler method names are taken into account for narrowing if
no path was specified explicitly, according to the specified
<interfacename>org.springframework.web.servlet.mvc.multiaction.MethodNameResolver</interfacename>
(by default an
<classname>org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver</classname>).
Note that this only applies in case of ambiguous annotation mappings
that do not specify a path mapping explicitly. In other words, the
method name is only used for narrowing among a set of matching
methods; it does not constitute a primary path mapping itself.</para>
<para>If you have a single default method (without explicit path
mapping), then all requests without a more specific mapped method
found will be dispatched to it. If you have multiple such default
methods, then the method name will be taken into account for choosing
between them.</para>
<para>Path mappings can be narrowed through parameter conditions: a
sequence of "myParam=myValue" style expressions, with a request only
mapped if each such parameter is found to have the given value. For
example: <programlisting language="java">@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets/{petId}", <emphasis role="bold">params="myParam=myValue"</emphasis>)
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
</programlisting> "myParam" style expressions are also supported, with such
parameters having to be present in the request (allowed to have any
value). Finally, "!myParam" style expressions indicate that the
specified parameter is <emphasis>not</emphasis> supposed to be present
in the request.</para>
<para>Similarly, path mappings can be narrowed down through header
conditions: <programlisting language="java">@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping(value = "/pets", method = RequestMethod.POST, <emphasis
role="bold">headers="content-type=text/*"</emphasis>)
public void addPet(Pet pet, @PathVariable String ownerId) {
// implementation omitted
}
}
</programlisting> In the above example, the <methodname>addPet</methodname>
will only be invoked when the Content-Type is in the
<literal>text/*</literal> range, for instance
<literal>text/xml</literal>.</para>
</section>
<section id="mvc-ann-requestmapping-arguments">
<title>Supported handler method arguments and return types</title>
<para>Handler methods which are annotated with
<classname>@RequestMapping</classname> are allowed to have very
flexible signatures. They may have arguments of the following types,
in arbitrary order (except for validation results, which need to
follow right after the corresponding command object, if desired):
<itemizedlist>
<listitem>
<para>Request and/or response objects (Servlet API). You may
choose any specific request/response type, e.g.
<interfacename>ServletRequest</interfacename> /
<interfacename>HttpServletRequest</interfacename>.</para>
</listitem>
<listitem>
<para>Session object (Servlet API): of type
<interfacename>HttpSession</interfacename>. An argument of this
type will enforce the presence of a corresponding session. As a
consequence, such an argument will never be
<literal>null</literal>.</para>
<note>
<para>Note that session access may not be thread-safe, in
particular in a Servlet environment: Consider switching the
<classname>AnnotationMethodHandlerAdapter</classname>'s
"synchronizeOnSession" flag to "true" if multiple requests are
allowed to access a session concurrently.</para>
</note>
</listitem>
<listitem>
<para><classname>org.springframework.web.context.request.WebRequest</classname>
or
<classname>org.springframework.web.context.request.NativeWebRequest</classname>.
Allows for generic request parameter access as well as
request/session attribute access, without ties to the native
Servlet/Portlet API.</para>
</listitem>
<listitem>
<para><classname>java.util.Locale</classname> for the current
request locale (determined by the most specific locale resolver
available, i.e. the configured
<interfacename>LocaleResolver</interfacename> in a Servlet
environment).</para>
</listitem>
<listitem>
<para><classname>java.io.InputStream</classname> /
<classname>java.io.Reader</classname> for access to the
request's content. This will be the raw InputStream/Reader as
exposed by the Servlet API.</para>
</listitem>
<listitem>
<para><classname>java.io.OutputStream</classname> /
<classname>java.io.Writer</classname> for generating the
response's content. This will be the raw OutputStream/Writer as
exposed by the Servlet API.</para>
</listitem>
<listitem>
<para><classname>@PathVariabe</classname> annotated parameters
for access to URI template variables, see <xref
linkend="mvc-ann-requestmapping-uri-templates" />.</para>
</listitem>
<listitem>
<para><classname>@RequestParam</classname> annotated parameters
for access to specific Servlet request parameters. Parameter
values will be converted to the declared method argument type.
See <xref linkend="mvc-ann-requestparam" />.</para>
</listitem>
<listitem>
<para><classname>@RequestHeader</classname> annotated parameters
for access to specific Servlet request HTTP headers. Parameter
values will be converted to the declared method argument
type.</para>
</listitem>
<listitem>
<para><classname>@RequestBody</classname> annotated parameters
for access to the request HTTP body. Parameter values will be
converted to the declared method argument type using
<interfacename>HttpMessageConverter</interfacename>s. See <xref
linkend="mvc-ann-requestbody" />.</para>
</listitem>
<listitem>
<para><interfacename>java.util.Map</interfacename> /
<interfacename>org.springframework.ui.Model</interfacename> /
<classname>org.springframework.ui.ModelMap</classname> for
enriching the implicit model that will be exposed to the web
view.</para>
</listitem>
<listitem>
<para>Command/form objects to bind parameters to: as bean
properties or fields, with customizable type conversion,
depending on <classname>@InitBinder</classname> methods and/or
the HandlerAdapter configuration - see the
"<literal>webBindingInitializer</literal>" property on
<classname>AnnotationMethodHandlerAdapter</classname>. Such
command objects along with their validation results will be
exposed as model attributes, by default using the non-qualified
command class name in property notation (e.g. "orderAddress" for
type "mypackage.OrderAddress"). Specify a parameter-level
<classname>ModelAttribute</classname> annotation for declaring a
specific model attribute name.</para>
</listitem>
<listitem>
<para><classname>org.springframework.validation.Errors</classname>
/
<classname>org.springframework.validation.BindingResult</classname>
validation results for a preceding command/form object (the
immediate preceding argument).</para>
</listitem>
<listitem>
<para><classname>org.springframework.web.bind.support.SessionStatus</classname>
status handle for marking form processing as complete
(triggering the cleanup of session attributes that have been
indicated by the <classname>@SessionAttributes</classname>
annotation at the handler type level).</para>
</listitem>
</itemizedlist></para>
<para>The following return types are supported for handler methods:
<itemizedlist>
<listitem>
<para>A <classname>ModelAndView</classname> object, with the
model implicitly enriched with command objects and the results
of <literal>@ModelAttribute</literal> annotated reference data
accessor methods.</para>
</listitem>
<listitem>
<para>A <interfacename>Model</interfacename> object, with the
view name implicitly determined through a
<interfacename>RequestToViewNameTranslator</interfacename> and
the model implicitly enriched with command objects and the
results of <literal>@ModelAttribute</literal> annotated
reference data accessor methods.</para>
</listitem>
<listitem>
<para>A <interfacename>Map</interfacename> object for exposing a
model, with the view name implicitly determined through a
<interfacename>RequestToViewNameTranslator</interfacename> and
the model implicitly enriched with command objects and the
results of <literal>@ModelAttribute</literal> annotated
reference data accessor methods.</para>
</listitem>
<listitem>
<para>A <interfacename>View</interfacename> object, with the
model implicitly determined through command objects and
<literal>@ModelAttribute</literal> annotated reference data
accessor methods. The handler method may also programmatically
enrich the model by declaring a
<interfacename>Model</interfacename> argument (see
above).</para>
</listitem>
<listitem>
<para>A <classname>String</classname> value which is interpreted
as view name, with the model implicitly determined through
command objects and <literal>@ModelAttribute</literal> annotated
reference data accessor methods. The handler method may also
programmatically enrich the model by declaring a
<interfacename>Model</interfacename> argument (see
above).</para>
</listitem>
<listitem>
<para><literal>void</literal> if the method handles the response
itself (by writing the response content directly, declaring an
argument of type <interfacename>ServletResponse</interfacename>
/ <interfacename>HttpServletResponse</interfacename> for that
purpose) or if the view name is supposed to be implicitly
determined through a
<interfacename>RequestToViewNameTranslator</interfacename> (not
declaring a response argument in the handler method
signature).</para>
</listitem>
<listitem>
<para>If the method is annotated with
<interfacename>@ResponseBody</interfacename>, the return type
will be written to the response HTTP body. The return value will
be converted to the declared method argument type using
<interfacename>HttpMessageConverter</interfacename>s. See <xref
linkend="mvc-ann-responsebody" />.</para>
</listitem>
<listitem>
<para>Any other return type will be considered as single model
attribute to be exposed to the view, using the attribute name
specified through <literal>@ModelAttribute</literal> at the
method level (or the default attribute name based on the return
type's class name otherwise). The model will be implicitly
enriched with command objects and the results of
<literal>@ModelAttribute</literal> annotated reference data
accessor methods.</para>
</listitem>
</itemizedlist></para>
</section>
<section id="mvc-ann-requestparam">
<title>Binding request parameters to method parameters with
<classname>@RequestParam</classname></title>
<para>The <classname>@RequestParam</classname> annotation is used to
bind request parameters to a method parameter in your
controller.</para>
<para>The following code snippet shows the usage:</para>
<programlisting language="java">@Controller
@RequestMapping("/pets")
@SessionAttributes("pet")
public class EditPetForm {
<lineannotation>// ...</lineannotation>
@RequestMapping(method = RequestMethod.GET)
public String setupForm(<emphasis role="bold">@RequestParam("petId") int petId</emphasis>, ModelMap model) {
Pet pet = this.clinic.loadPet(petId);
model.addAttribute("pet", pet);
return "petForm";
}
<lineannotation>// ...</lineannotation>
</programlisting>
<para>Parameters using this annotation are required by default, but
you can specify that a parameter is optional by setting
<interfacename>@RequestParam</interfacename>'s
<literal>required</literal> attribute to <literal>false</literal>
(e.g., <literal>@RequestParam(value="id",
required="false")</literal>).</para>
</section>
<section id="mvc-ann-requestbody">
<title>Mapping the request body with the @RequestBody
annotation</title>
<para>The <classname>@RequestBody</classname> method parameter
annotation is used to indicate that a method parameter should be bound
to the value of the HTTP request body. For example,</para>
<programlisting language="java">@RequestMapping(value = "/something", method = RequestMethod.PUT)
public void handle(@RequestBody String body, Writer writer) throws IOException {
writer.write(body);
}</programlisting>
<para>The conversion of the request body to the method argument is
done using a <interfacename>HttpMessageConverter</interfacename>.
<interfacename>HttpMessageConverter</interfacename> is responsible for
converting from the HTTP request message to an object and converting
from an object to the HTTP response body.
<classname>DispatcherServlet</classname> supports annotation based
processing using the
<classname>DefaultAnnotationHandlerMapping</classname> and
<classname>AnnotationMethodHandlerAdapter</classname>. In Spring 3 the
<classname>AnnotationMethodHandlerAdapter</classname> has been
extended to support the <classname>@RequestBody</classname> and has
several <interfacename>HttpMessageConverters</interfacename>
registered by default, these are</para>
<itemizedlist>
<listitem>
<para><classname>ByteArrayHttpMessageConverter</classname> -
converts byte arrays</para>
</listitem>
<listitem>
<para><classname>StringHttpMessageConverter</classname> - converts
strings</para>
</listitem>
<listitem>
<para><classname>FormHttpMessageConverter</classname> - converts
form data to/from a MultiValueMap&lt;String, String&gt;</para>
</listitem>
<listitem>
<para><classname>SourceHttpMessageConverter</classname> - converts
to/from a javax.xml.transform.Source;</para>
</listitem>
<listitem>
<para><classname>MarshallingHttpMessageConverter</classname> -
converts to/from an object using the
<classname>org.springframework.oxm</classname> package.</para>
</listitem>
</itemizedlist>
<para>More information on these converters can be found in the section
<link linkend="rest-message-conversion">Message
Converters</link>.</para>
<para>The <classname>MarshallingHttpMessageConverter</classname>
requires a <interfacename>Marshaller</interfacename> and
<interfacename>Unmarshaller</interfacename> from the
<classname>org.springframework.oxm</classname> package to be
configured on an instance of
<classname>AnnotationMethodHandlerAdapter</classname> in the
application context. For example</para>
<programlisting language="xml">&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;
&lt;property name="messageConverters"&gt;
&lt;util:list id="beanList"&gt;
&lt;ref bean="stringHttpMessageConverter"/&gt;
&lt;ref bean="marshallingHttpMessageConverter"/&gt;
&lt;/util:list&gt;
&lt;/property
&lt;/bean&gt;
&lt;bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter"/&gt;
&lt;bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter"&gt;
&lt;property name="marshaller" ref="castorMarshaller" /&gt;
&lt;property name="unmarshaller" ref="castorMarshaller" /&gt;
&lt;/bean&gt;
&lt;bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller"/&gt;
</programlisting>
</section>
<section id="mvc-ann-responsebody">
<title>Mapping the response body with the @ResponseBody
annotation</title>
<para>Similar to <interfacename>@RequestBody</interfacename>, there is
the <interfacename>@ResponseBody</interfacename> annotation. This
annotation can be put on a method and indicates that the return type
should be written straight to the HTTP response body (and not placed
in a Model, or interpreted as a view name). For example,</para>
<programlisting language="java">@RequestMapping(value = "/something", method = RequestMethod.PUT)
@ResponseBody
public String helloWorld() {
return "Hello World";
}</programlisting>
<para>The example above will result in the text <literal>Hello
World</literal> being written to the HTTP response stream.</para>
<para>Just like <interfacename>@RequestBody</interfacename>, the
conversion of the returned object to response body is done using a
<interfacename>HttpMessageConverter</interfacename>. More information
on these converters can be found in the previous section, or in the
section <link linkend="rest-message-conversion">Message
Converters</link>.</para>
</section>
<section id="mvc-ann-modelattrib">
<title>Providing a link to data from the model with
<classname>@ModelAttribute</classname></title>
<para><classname>@ModelAttribute</classname> has two usage scenarios
in controllers. When placed on a method parameter,
<classname>@ModelAttribute</classname> is used to map a model
attribute to the specific, annotated method parameter (see the
<literal>processSubmit()</literal> method below). This is how the
controller gets a reference to the object holding the data entered in
the form.</para>
<para><classname>@ModelAttribute</classname> is also used at the
method level to provide <emphasis>reference data</emphasis> for the
model (see the <literal>populatePetTypes()</literal> method below).
For this usage the method signature can contain the same types as
documented above for the <classname>@RequestMapping</classname>
annotation.</para>
<note>
<para><emphasis>Note:</emphasis>
<classname>@ModelAttribute</classname> annotated methods will be
executed <emphasis>before</emphasis> the chosen
<classname>@RequestMapping</classname> annotated handler method.
They effectively pre-populate the implicit model with specific
attributes, often loaded from a database. Such an attribute can then
already be accessed through <classname>@ModelAttribute</classname>
annotated handler method parameters in the chosen handler method,
potentially with binding and validation applied to it.</para>
</note>
<para>The following code snippet shows these two usages of this
annotation:</para>
<programlisting language="java">@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {
<lineannotation>// ...</lineannotation>
<emphasis role="bold">@ModelAttribute("types")</emphasis>
public Collection&lt;PetType&gt; populatePetTypes() {
return this.clinic.getPetTypes();
}
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(
<emphasis role="bold">@ModelAttribute("pet") Pet pet</emphasis>, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}
else {
this.clinic.storePet(pet);
status.setComplete();
return "redirect:owner.do?ownerId=" + pet.getOwner().getId();
}
}
}</programlisting>
</section>
<section id="mvc-ann-sessionattrib">
<title>Specifying attributes to store in a Session with
<classname>@SessionAttributes</classname></title>
<para>The type-level <classname>@SessionAttributes</classname>
annotation declares session attributes used by a specific handler.
This will typically list the names of model attributes which should be
transparently stored in the session or some conversational storage,
serving as form-backing beans between subsequent requests.</para>
<para>The following code snippet shows the usage of this
annotation:</para>
<programlisting language="java">@Controller
@RequestMapping("/editPet.do")
<emphasis role="bold">@SessionAttributes("pet")</emphasis>
public class EditPetForm {
<lineannotation>// ...</lineannotation>
}
</programlisting>
</section>
<section id="mvc-ann-cookievalue">
<title>Mapping cookie values with the @CookieValue annotation</title>
<para>The <interfacename>@CookieValue</interfacename> annotation
allows a method parameter to be bound to the value of an HTTP
cookie.</para>
<para>Let us consider that the following cookie has been received with
an http request:</para>
<programlisting>JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84</programlisting>
<para>The following code sample allows you to easily get the value of
the "JSESSIONID"cookie:</para>
<programlisting language="java">@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(<emphasis role="bold">@CookieValue("JSESSIONID")</emphasis> String cookie) {
//...
}</programlisting>
<para>This annotation is supported for annotated handler methods in
Servlet and Portlet environments.</para>
</section>
<section id="mvc-ann-requestheader">
<title>Mapping request header attributes with the @RequestHeader
annotation</title>
<para>The <interfacename>@RequestHeader</interfacename> annotation
allows a method parameter to be bound to a request header.</para>
<para>Here is a request header sample:</para>
<programlisting>
Host localhost:8080
Accept text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
</programlisting>
<para>The following code sample allows you to easily get the value of
the "Accept-Encoding" and "Keep-Alive" headers:</para>
<programlisting language="java">@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(<emphasis role="bold">@RequestHeader("Accept-Encoding")</emphasis> String encoding,
<emphasis role="bold">@RequestHeader("Keep-Alive")</emphasis> long keepAlive) {
//...
}</programlisting>
<para>This annotation is supported for annotated handler methods in
Servlet and Portlet environments.</para>
</section>
<section id="mvc-ann-webdatabinder">
<title>Customizing <classname>WebDataBinder</classname>
initialization</title>
<para>To customize request parameter binding with PropertyEditors,
etc. via Spring's <classname>WebDataBinder</classname>, you can either
use <interfacename>@InitBinder</interfacename>-annotated methods
within your controller or externalize your configuration by providing
a custom <interfacename>WebBindingInitializer</interfacename>.</para>
<section id="mvc-ann-initbinder">
<title>Customizing data binding with
<interfacename>@InitBinder</interfacename></title>
<para>Annotating controller methods with
<interfacename>@InitBinder</interfacename> allows you to configure
web data binding directly within your controller class.
<interfacename>@InitBinder</interfacename> identifies methods which
initialize the <classname>WebDataBinder</classname> which will be
used for populating command and form object arguments of annotated
handler methods.</para>
<para>Such init-binder methods support all arguments that
<interfacename>@RequestMapping</interfacename> supports, except for
command/form objects and corresponding validation result objects.
Init-binder methods must not have a return value. Thus, they are
usually declared as <literal>void</literal>. Typical arguments
include <classname>WebDataBinder</classname> in combination with
<interfacename>WebRequest</interfacename> or
<classname>java.util.Locale</classname>, allowing code to register
context-specific editors.</para>
<para>The following example demonstrates the use of
<interfacename>@InitBinder</interfacename> for configuring a
<classname>CustomDateEditor</classname> for all
<classname>java.util.Date</classname> form properties.</para>
<programlisting language="java">@Controller
public class MyFormController {
<emphasis role="bold">@InitBinder</emphasis>
public void initBinder(WebDataBinder binder) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
dateFormat.setLenient(false);
binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
}
<lineannotation>// ...</lineannotation>
}</programlisting>
</section>
<section id="mvc-ann-webbindinginitializer">
<title>Configuring a custom
<interfacename>WebBindingInitializer</interfacename></title>
<para>To externalize data binding initialization, you can provide a
custom implementation of the
<interfacename>WebBindingInitializer</interfacename> interface,
which you then enable by supplying a custom bean configuration for
an <classname>AnnotationMethodHandlerAdapter</classname>, thus
overriding the default configuration.</para>
<para>The following example from the PetClinic application shows a
configuration using a custom implementation of the
<interfacename>WebBindingInitializer</interfacename> interface,
<classname>org.springframework.samples.petclinic.web.ClinicBindingInitializer</classname>,
which configures PropertyEditors required by several of the
PetClinic controllers.</para>
<programlisting language="xml">&lt;bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"&gt;
&lt;property name="cacheSeconds" value="0" /&gt;
&lt;property name="webBindingInitializer"&gt;
&lt;bean class="org.springframework.samples.petclinic.web.ClinicBindingInitializer" /&gt;
&lt;/property&gt;
&lt;/bean&gt;
</programlisting>
</section>
</section>
</section>
</section>
<section id="mvc-handlermapping">
<title>Handler mappings</title>
<para>In previous versions of Spring MVC, users were required to define <interfacename>HandlerMapping</interfacename>s in
the web application context
to map incoming web requests to
appropriate handlers. With the introduction of Spring 2.5, the <classname>DispatcherServlet</classname> enables the
<classname>DefaultAnnotationHandlerMapping</classname>, which looks for
<interfacename>@RequestMapping</interfacename> annotations on <interfacename>@Controllers</interfacename>.
Typically, you do not need to override this default mapping, except when overriding the properties.
These properties are:
</para>
<itemizedlist spacing="compact">
<listitem>
<para><literal>interceptors</literal>: the list of interceptors to
use. <interfacename>HandlerInterceptor</interfacename>s are discussed
in <xref linkend="mvc-handlermapping-interceptor" />.</para>
</listitem>
<listitem>
<para><literal>defaultHandler</literal>: the default handler to use,
when this handler mapping does not result in a matching
handler.</para>
</listitem>
<listitem>
<para><literal>order</literal>: based on the value of the order
property (see the <literal>org.springframework.core.Ordered</literal>
interface), Spring will sort all handler mappings available in the
context and apply the first matching handler.</para>
</listitem>
<listitem>
<para><literal>alwaysUseFullPath</literal>: if this property is set to
<literal>true</literal>, Spring will use the full path within the
current servlet context to find an appropriate handler. If this
property is set to <literal>false</literal> (the default), the path
within the current servlet mapping will be used. For example, if a
servlet is mapped using <literal>/testing/*</literal> and the
<literal>alwaysUseFullPath</literal> property is set to true,
<literal>/testing/viewPage.html</literal> would be used, whereas if
the property is set to false, <literal>/viewPage.html</literal> would
be used.</para>
</listitem>
<listitem>
<para><literal>urlDecode</literal>: the default value for this
property is <literal>true</literal>, as of Spring 2.5. If you prefer
to compare encoded paths, switch this flag to
<literal>false</literal>. However, note that the
<interfacename>HttpServletRequest</interfacename> always exposes the
servlet path in decoded form. Be aware that the servlet path will not
match when compared with encoded paths.</para>
</listitem>
<listitem>
<para><literal>lazyInitHandlers</literal>: allows for lazy
initialization of <emphasis>singleton</emphasis> handlers (prototype
handlers are always lazily initialized). Default value is
<literal>false</literal>.</para>
</listitem>
</itemizedlist>
<para>(<emphasis>Note: the last three properties are only available to
subclasses of
<classname>org.springframework.web.servlet.handler.AbstractUrlHandlerMapping</classname></emphasis>).</para>
<para>The following example shows how to override the default mapping, and add an interceptor:</para>
<programlisting language="xml"><![CDATA[<beans>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<bean class="example.MyInterceptor"/>
</property>
</bean>
<beans>]]></programlisting>
<section id="mvc-handlermapping-interceptor">
<title>Intercepting requests - the
<interfacename>HandlerInterceptor</interfacename> interface</title>
<para>Spring's handler mapping mechanism has the notion of handler
interceptors, that can be extremely useful when you want to apply
specific functionality to certain requests, for example, checking for a
principal.</para>
<para>Interceptors located in the handler mapping must implement
<interfacename>HandlerInterceptor</interfacename> from the
<literal>org.springframework.web.servlet</literal> package. This
interface defines three methods, one that will be called
<emphasis>before</emphasis> the actual handler will be executed, one
that will be called <emphasis>after</emphasis> the handler is executed,
and one that is called <emphasis>after the complete request has
finished</emphasis>. These three methods should provide enough
flexibility to do all kinds of pre- and post-processing.</para>
<para>The <literal>preHandle(..)</literal> method returns a boolean
value. You can use this method to break or continue the processing of
the execution chain. When this method returns <literal>true</literal>,
the handler execution chain will continue, when it returns false, the
<classname>DispatcherServlet</classname> assumes the interceptor itself
has taken care of requests (and, for example, rendered an appropriate
view) and does not continue executing the other interceptors and the
actual handler in the execution chain.</para>
<para>The following example provides an interceptor that intercepts all
requests and reroutes the user to a specific page if the time is not
between 9 a.m. and 6 p.m.</para>
<programlisting language="xml">&lt;beans&gt;
&lt;bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
&lt;property name="interceptors"&gt;
&lt;list&gt;
&lt;ref bean="officeHoursInterceptor"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="mappings"&gt;
&lt;value&gt;
/*.form=editAccountFormController
/*.view=editAccountFormController
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="officeHoursInterceptor"
class="samples.TimeBasedAccessInterceptor"&gt;
&lt;property name="openingTime" value="9"/&gt;
&lt;property name="closingTime" value="18"/&gt;
&lt;/bean&gt;
&lt;beans&gt;</programlisting>
<programlisting language="java">package samples;
public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
private int openingTime;
private int closingTime;
public void setOpeningTime(int openingTime) {
this.openingTime = openingTime;
}
public void setClosingTime(int closingTime) {
this.closingTime = closingTime;
}
public boolean preHandle(
HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
Calendar cal = Calendar.getInstance();
int hour = cal.get(HOUR_OF_DAY);
if (openingTime &lt;= hour &lt; closingTime) {
return true;
} else {
response.sendRedirect("http://host.com/outsideOfficeHours.html");
return false;
}
}
}</programlisting>
<para>Any request coming in, will be intercepted by the
<classname>TimeBasedAccessInterceptor</classname>, and if the current
time is outside office hours, the user will be redirected to a static
html file, saying, for example, he can only access the website during
office hours.</para>
<para>As you can see, Spring has an adapter class (the cunningly named
<classname>HandlerInterceptorAdapter</classname>) to make it easier to
extend the <interfacename>HandlerInterceptor</interfacename>
interface.</para>
</section>
</section>
<section id="mvc-viewresolver">
<title>Views and resolving them</title>
<para>All MVC frameworks for web applications provide a way to address
views. Spring provides view resolvers, which enable you to render models
in a browser without tying you to a specific view technology. Out of the
box, Spring enables you to use JSPs, Velocity templates and XSLT views,
for example. The section entitled <xref linkend="view" /> has details of
how to integrate and use a number of disparate view technologies.</para>
<para>The two interfaces which are important to the way Spring handles
views are <interfacename>ViewResolver</interfacename> and
<interfacename>View</interfacename>. The
<interfacename>ViewResolver</interfacename> provides a mapping between
view names and actual views. The <interfacename>View</interfacename>
interface addresses the preparation of the request and hands the request
over to one of the view technologies.</para>
<section id="mvc-viewresolver-resolver">
<title>Resolving views - the <interfacename>ViewResolver</interfacename>
interface</title>
<para>As discussed in the section entitled <xref
linkend="mvc-controller" />, all controllers in the Spring Web MVC
framework return a <classname>ModelAndView</classname> instance. Views
in Spring are addressed by a view name and are resolved by a view
resolver. Spring comes with quite a few view resolvers. We'll list most
of them and then provide a couple of examples.</para>
<table id="mvc-view-resolvers-tbl">
<title>View resolvers</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="2*" />
<thead>
<row>
<entry><interfacename>ViewResolver</interfacename></entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><classname>AbstractCachingViewResolver</classname></entry>
<entry>An abstract view resolver which takes care of caching
views. Often views need preparation before they can be used,
extending this view resolver provides caching of views.</entry>
</row>
<row>
<entry><classname>XmlViewResolver</classname></entry>
<entry>An implementation of
<interfacename>ViewResolver</interfacename> that accepts a
configuration file written in XML with the same DTD as Spring's
XML bean factories. The default configuration file is
<literal>/WEB-INF/views.xml</literal>.</entry>
</row>
<row>
<entry><classname>ResourceBundleViewResolver</classname></entry>
<entry>An implementation of
<interfacename>ViewResolver</interfacename> that uses bean
definitions in a <classname>ResourceBundle</classname>,
specified by the bundle basename. The bundle is typically
defined in a properties file, located in the classpath. The
default file name is
<literal>views.properties</literal>.</entry>
</row>
<row>
<entry><classname>UrlBasedViewResolver</classname></entry>
<entry>A simple implementation of the
<interfacename>ViewResolver</interfacename> interface that
effects the direct resolution of symbolic view names to URLs,
without an explicit mapping definition. This is appropriate if
your symbolic names match the names of your view resources in a
straightforward manner, without the need for arbitrary
mappings.</entry>
</row>
<row>
<entry><classname>InternalResourceViewResolver</classname></entry>
<entry>A convenience subclass of
<classname>UrlBasedViewResolver</classname> that supports
<classname>InternalResourceView</classname> (i.e. Servlets and
JSPs), and subclasses such as <classname>JstlView</classname>
and <classname>TilesView</classname>. The view class for all
views generated by this resolver can be specified via
<literal>setViewClass(..)</literal>. See the Javadocs for the
<classname>UrlBasedViewResolver</classname> class for
details.</entry>
</row>
<row>
<entry><classname>VelocityViewResolver</classname> /
<classname>FreeMarkerViewResolver</classname></entry>
<entry>A convenience subclass of
<classname>UrlBasedViewResolver</classname> that supports
<classname>VelocityView</classname> (i.e. Velocity templates) or
<classname>FreeMarkerView</classname> respectively and custom
subclasses of them.</entry>
</row>
<row>
<entry><classname>ContentNegotiatingViewResolver</classname></entry>
<entry>An implementation of the <interfacename>ViewResolver</interfacename>
interface that that resolves a view based on the request file name or <literal>Accept</literal> header.
See <xref linkend="mvc-multiple-representations"/>.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>As an example, when using JSP for a view technology you can use
the <classname>UrlBasedViewResolver</classname>. This view resolver
translates a view name to a URL and hands the request over to the
RequestDispatcher to render the view.</para>
<programlisting language="xml">&lt;bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver"&gt;
&lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
&lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
&lt;property name="suffix" value=".jsp"/&gt;
&lt;/bean&gt;</programlisting>
<para>When returning <literal>test</literal> as a viewname, this view
resolver will hand the request over to the
<classname>RequestDispatcher</classname> that will send the request to
<literal>/WEB-INF/jsp/test.jsp</literal>.</para>
<para>When mixing different view technologies in a web application, you
can use the <classname>ResourceBundleViewResolver</classname>:</para>
<programlisting language="xml">&lt;bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver"&gt;
&lt;property name="basename" value="views"/&gt;
&lt;property name="defaultParentView" value="parentView"/&gt;
&lt;/bean&gt;</programlisting>
<para>The <classname>ResourceBundleViewResolver</classname> inspects the
<classname>ResourceBundle</classname> identified by the basename, and
for each view it is supposed to resolve, it uses the value of the
property <literal>[viewname].class</literal> as the view class and the
value of the property <literal>[viewname].url</literal> as the view url.
As you can see, you can identify a parent view, from which all views in
the properties file sort of extend. This way you can specify a default
view class, for example.</para>
<para><emphasis>A note on caching</emphasis> - subclasses of
<classname>AbstractCachingViewResolver</classname> cache view instances
they have resolved. This greatly improves performance when using certain
view technologies. It's possible to turn off the cache, by setting the
<literal>cache</literal> property to <literal>false</literal>.
Furthermore, if you have the requirement to be able to refresh a certain
view at runtime (for example when a Velocity template has been
modified), you can use the <literal>removeFromCache(String viewName,
Locale loc)</literal> method.</para>
</section>
<section id="mvc-viewresolver-chaining">
<title>Chaining ViewResolvers</title>
<para>Spring supports more than just one view resolver. This allows you
to chain resolvers and, for example, override specific views in certain
circumstances. Chaining view resolvers is pretty straightforward - just
add more than one resolver to your application context and, if
necessary, set the <literal>order</literal> property to specify an
order. Remember, the higher the order property, the later the view
resolver will be positioned in the chain.</para>
<para>In the following example, the chain of view resolvers consists of
two resolvers, a <classname>InternalResourceViewResolver</classname>
(which is always automatically positioned as the last resolver in the
chain) and an <classname>XmlViewResolver</classname> for specifying
Excel views (which are not supported by the
<classname>InternalResourceViewResolver</classname>):</para>
<programlisting language="xml">&lt;bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
&lt;property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/&gt;
&lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
&lt;property name="suffix" value=".jsp"/&gt;
&lt;/bean&gt;
&lt;bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver"&gt;
&lt;property name="order" value="1"/&gt;
&lt;property name="location" value="/WEB-INF/views.xml"/&gt;
&lt;/bean&gt;
<lineannotation>&lt;!-- in <literal>views.xml</literal> --&gt;</lineannotation>
&lt;beans&gt;
&lt;bean name="report" class="org.springframework.example.ReportExcelView"/&gt;
&lt;/beans&gt;</programlisting>
<para>If a specific view resolver does not result in a view, Spring will
inspect the context to see if other view resolvers are configured. If
there are additional view resolvers, it will continue to inspect them.
If not, it will throw an <classname>Exception</classname>.</para>
<para>You have to keep something else in mind - the contract of a view
resolver mentions that a view resolver <emphasis>can</emphasis> return
null to indicate the view could not be found. Not all view resolvers do
this however! This is because in some cases, the resolver simply cannot
detect whether or not the view exists. For example, the
<classname>InternalResourceViewResolver</classname> uses the
<classname>RequestDispatcher</classname> internally, and dispatching is
the only way to figure out if a JSP exists - this can only be done once.
The same holds for the <classname>VelocityViewResolver</classname> and
some others. Check the Javadoc for the view resolver to see if you're
dealing with a view resolver that does not report non-existing views. As
a result of this, putting an
<classname>InternalResourceViewResolver</classname> in the chain in a
place other than the last, will result in the chain not being fully
inspected, since the <classname>InternalResourceViewResolver</classname>
will <emphasis>always</emphasis> return a view!</para>
</section>
<section id="mvc-redirecting">
<title>Redirecting to views</title>
<para>As has been mentioned, a controller normally returns a logical
view name, which a view resolver resolves to a particular view
technology. For view technologies such as JSPs that are actually
processed via the Servlet/JSP engine, this is normally handled via
<classname>InternalResourceViewResolver</classname> /
<classname>InternalResourceView</classname> which will ultimately end up
issuing an internal forward or include, via the Servlet API's
<literal>RequestDispatcher.forward(..)</literal> or
<literal>RequestDispatcher.include()</literal>. For other view
technologies, such as Velocity, XSLT, etc., the view itself produces the
content on the response stream.</para>
<para>It is sometimes desirable to issue an HTTP redirect back to the
client, before the view is rendered. This is desirable for example when
one controller has been called with <literal>POST</literal>ed data, and
the response is actually a delegation to another controller (for example
on a successful form submission). In this case, a normal internal
forward will mean the other controller will also see the same
<literal>POST</literal> data, which is potentially problematic if it can
confuse it with other expected data. Another reason to do a redirect
before displaying the result is that this will eliminate the possibility
of the user doing a double submission of form data. The browser will
have sent the initial <literal>POST</literal>, will have seen a redirect
back and done a subsequent <literal>GET</literal> because of that, and
thus as far as it is concerned, the current page does not reflect the
result of a <literal>POST</literal>, but rather of a
<literal>GET</literal>, so there is no way the user can accidentally
re-<literal>POST</literal> the same data by doing a refresh. The refresh
would just force a <literal>GET</literal> of the result page, not a
resend of the initial <literal>POST</literal> data.</para>
<section id="mvc-redirecting-redirect-view">
<title><classname>RedirectView</classname></title>
<para>One way to force a redirect as the result of a controller
response is for the controller to create and return an instance of
Spring's <classname>RedirectView</classname>. In this case,
<classname>DispatcherServlet</classname> will not use the normal view
resolution mechanism, but rather as it has been given the (redirect)
view already, will just ask it to do its work.</para>
<para>The <classname>RedirectView</classname> simply ends up issuing
an <literal>HttpServletResponse.sendRedirect()</literal> call, which
will come back to the client browser as an HTTP redirect. All model
attributes are simply exposed as HTTP query parameters. This does mean
that the model must contain only objects (generally Strings or
convertible to Strings) which can be readily converted to a
string-form HTTP query parameter.</para>
<para>If using <classname>RedirectView</classname> and the view is
created by the controller itself, it is preferable for the redirect
URL to be injected into the controller so that it is not baked into
the controller but configured in the context along with the view
names.</para>
</section>
<section id="mvc-redirecting-redirect-prefix">
<title>The <literal>redirect:</literal> prefix</title>
<para>While the use of <classname>RedirectView</classname> works fine,
if the controller itself is creating the
<classname>RedirectView</classname>, there is no getting around the
fact that the controller is aware that a redirection is happening.
This is really suboptimal and couples things too tightly. The
controller should not really care about how the response gets
handled... it should generally think only in terms of view names that
have been injected into it.</para>
<para>The special <literal>redirect:</literal> prefix allows this to
be achieved. If a view name is returned which has the prefix
redirect:, then <classname>UrlBasedViewResolver</classname> (and all
subclasses) will recognize this as a special indication that a
redirect is needed. The rest of the view name will be treated as the
redirect URL.</para>
<para>The net effect is the same as if the controller had returned a
<classname>RedirectView</classname>, but now the controller itself can
deal just in terms of logical view names. A logical view name such as
<literal>redirect:/my/response/controller.html</literal> will redirect
relative to the current servlet context, while a name such as
<literal>redirect:http://myhost.com/some/arbitrary/path.html</literal>
will redirect to an absolute URL. The important thing is that as long
as this redirect view name is injected into the controller like any
other logical view name, the controller is not even aware that
redirection is happening.</para>
</section>
<section id="mvc-redirecting-forward-prefix">
<title>The <literal>forward:</literal> prefix</title>
<para>It is also possible to use a special <literal>forward:</literal>
prefix for view names that will ultimately be resolved by
<classname>UrlBasedViewResolver</classname> and subclasses. All this
does is create an <classname>InternalResourceView</classname> (which
ultimately does a <literal>RequestDispatcher.forward()</literal>)
around the rest of the view name, which is considered a URL.
Therefore, there is never any use in using this prefix when using
<classname>InternalResourceViewResolver</classname> /
<classname>InternalResourceView</classname> anyway (for JSPs for
example), but it's of potential use when you are primarily using
another view technology, but still want to force a forward to happen
to a resource to be handled by the Servlet/JSP engine. (Note that you
may also chain multiple view resolvers, instead.)</para>
<para>As with the <literal>redirect:</literal> prefix, if the view
name with the prefix is just injected into the controller, the
controller does not have to be aware that anything special is
happening in terms of handling the response.</para>
</section>
</section>
<section id="mvc-multiple-representations">
<title><classname>ContentNegotiatingViewResolver</classname></title>
<para>The <classname>ContentNegotiatingViewResolver</classname>
does not resolve views itself, but rather delegates to other
view resolvers, selecting the view that resembles the representation
requested by the client.
There are two strategies for a client to inform the server of
the representation it is interested in receiving.</para>
<para>The first strategy is to use a distinct URI for each resource.
This is typically done by using a different file extension in the URI.
For example the URI<literal>
http://www.example.com/users/fred.pdf</literal> requests a PDF
representation of the user fred while
<literal>http://www.example.com/users/fred.xml</literal> requests an XML
representation.</para>
<para>The second strategy is for the client to use the same URI to
locate the resource but set the <literal>Accept</literal> HTTP request
header to list the <ulink
url="http://en.wikipedia.org/wiki/Internet_media_type">media
types</ulink> that it understands. For example, a HTTP request for
<literal>http://www.example.com/users/fred</literal> with an
<literal>Accept</literal> header set to <literal>application/pdf
</literal>requests a PDF representation of the user fred while
<literal>http://www.example.com/users/fred</literal> with an
<literal>Accept</literal> header set to <literal>text/xml</literal>
requests an XML representation. This strategy is known as <ulink
url="http://en.wikipedia.org/wiki/Content_negotiation">content
negotiation</ulink>.</para>
<note>
<para>One issue with the Accept header is that is impossible to change
it in a web browser, in HTML. For instance, in Firefox, it's fixed
to</para>
<programlisting>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
</programlisting>
<para>For this reason it is common to see the use of a distinct URI
for each representation.</para>
</note>
<para>To support multiple representations of a resource Spring provides
the <classname>ContentNegotiatingViewResolver</classname> to resolve a
view based on the file extension or <literal>Accept</literal> header of
the HTTP request. <classname>ContentNegotiatingViewResolver</classname>
does not perform the view resolution itself, but instead delegates to a
list of view resolvers set using the bean property
<literal>ViewResolvers</literal>.</para>
<para>The <classname>ContentNegotiatingViewResolver</classname> selects
an appropriate <classname>View</classname> to handle the request by
comparing the request media type(s) with the media type (a.k.a.
<literal>Content-Type</literal>) supported by the
<classname>View</classname> associated with each of its
<classname>ViewResolvers</classname>. The first
<classname>View</classname> in the list that has a compatible
<literal>Content-Type</literal> is used to return the representation to
the client. The <literal>Accept</literal> header may include wild cards,
for example 'text/*', in which case a <classname>View</classname> whose
Context-Type was 'text/xml' is a compatible match.</para>
<para>To support the resolution of a view based on a file extension,
<classname>ContentNegotiatingViewResolver</classname>'s bean property
<literal>MediaTypes</literal> is used to specify a mapping of file
extensions to media types. For more information on the algorithm to
determine the request media type, refer to the API documentation for
<classname>ContentNegotiatingViewResolver</classname>..</para>
<para>Here is an example configuration of a
<classname>ContentNegotiatingViewResolver</classname></para>
<programlisting language="xml"><![CDATA[<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="atom" value="application/atom+xml"/>
<entry key="html" value="text/html"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
</bean>
<bean id="content" class="com.springsource.samples.rest.SampleContentAtomView"/>]]></programlisting>
<para>The <classname>InternalResourceViewResolver</classname> handles
the translation of view names and JSP pages while the
<classname>BeanNameViewResolver</classname> returns a view based on the
name of a bean. (See "<link
linkend="mvc-viewresolver-resolver">Resolving views - the ViewResolver
interface</link>" for more details on how Spring looks up and
instantiates a view.) In this example, the <literal>content</literal>
bean is a class that inherits from
<classname>AbstractAtomFeedView</classname> which returns an Atom RSS
feed. For more information on creating an Atom Feed representation see
the section 'Atom Views'.</para>
<para>In this configuration, if a request is made with a .html extension
the view resolver will look for a view that matches the text/html media
type. The <classname>InternalResourceViewResolver</classname> provides
the matching view for text/html. If the request is made with the file
extension .atom, the view resolver will look for a view that matches the
application/atom+xml media type. This view is provided by the
<classname>BeanNameViewResolver</classname> that maps to the
<classname>SampleContentAtomView</classname> if the view name returned
is 'content'. Alternatively, client requests could be made without a
file extension and setting the Accept header to the preferred media-type
and the same resolution of request to views would occur.</para>
<note>
<para>If <classname>ContentNegotiatingViewResolver</classname>'s list
of ViewResolvers is not configured explicitly, then it will
automatically use any ViewResolvers defined in the application
context.</para>
</note>
<para>The corresponding controller code that returns an Atom RSS feed
for a URI of the form <literal>http://localhost/content.atom</literal>
or <literal>http://localhost/content</literal> with an
<literal>Accept</literal> header of application/atom+xml is shown
below</para>
<programlisting language="java">@Controller
public class ContentController {
private List&lt;SampleContent&gt; contentList = new ArrayList&lt;SampleContent&gt;();
@RequestMapping(value="/content", method=RequestMethod.GET)
public ModelAndView getContent() {
ModelAndView mav = new ModelAndView();
mav.setViewName("content");
mav.addObject("sampleContentList", contentList);
return mav;
}
}</programlisting>
</section>
</section>
<section id="mvc-localeresolver">
<title>Using locales</title>
<para>Most parts of Spring's architecture support internationalization,
just as the Spring web MVC framework does.
<classname>DispatcherServlet</classname> enables you to automatically
resolve messages using the client's locale. This is done with
<interfacename>LocaleResolver</interfacename> objects.</para>
<para>When a request comes in, the
<classname>DispatcherServlet</classname> looks for a locale resolver and
if it finds one it tries to use it to set the locale. Using the
<literal>RequestContext.getLocale()</literal> method, you can always
retrieve the locale that was resolved by the locale resolver.</para>
<para>Besides the automatic locale resolution, you can also attach an
interceptor to the handler mapping (see <xref
linkend="mvc-handlermapping-interceptor" /> for more information on
handler mapping interceptors), to change the locale under specific
circumstances, based on a parameter in the request, for example.</para>
<para>Locale resolvers and interceptors are all defined in the
<literal>org.springframework.web.servlet.i18n</literal> package, and are
configured in your application context in the normal way. Here is a
selection of the locale resolvers included in Spring.</para>
<section id="mvc-localeresolver-acceptheader">
<title><classname>AcceptHeaderLocaleResolver</classname></title>
<para>This locale resolver inspects the
<literal>accept-language</literal> header in the request that was sent
by the browser of the client. Usually this header field contains the
locale of the client's operating system.</para>
</section>
<section id="mvc-localeresolver-cookie">
<title><classname>CookieLocaleResolver</classname></title>
<para>This locale resolver inspects a <classname>Cookie</classname> that
might exist on the client, to see if a locale is specified. If so, it
uses that specific locale. Using the properties of this locale resolver,
you can specify the name of the cookie, as well as the maximum age. Find
below an example of defining a
<classname>CookieLocaleResolver</classname>.</para>
<programlisting language="xml">&lt;bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver"&gt;
&lt;property name="cookieName" value="clientlanguage"/&gt;
<lineannotation>&lt;!-- in seconds. If set to <literal>-1</literal>, the cookie is not persisted (deleted when browser shuts down) --&gt;</lineannotation>
&lt;property name="cookieMaxAge" value="100000"&gt;
&lt;/bean&gt;</programlisting>
<table id="mvc-cookie-locale-resolver-props-tbl">
<title><classname>CookieLocaleResolver</classname> properties</title>
<tgroup cols="3">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c2" colwidth="1*" />
<colspec colname="c3" colwidth="3*" />
<thead>
<row>
<entry>Property</entry>
<entry>Default</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>cookieName</entry>
<entry>classname + LOCALE</entry>
<entry>The name of the cookie</entry>
</row>
<row>
<entry>cookieMaxAge</entry>
<entry>Integer.MAX_INT</entry>
<entry>The maximum time a cookie will stay persistent on the
client. If -1 is specified, the cookie will not be persisted. It
will only be available until the client shuts down his or her
browser.</entry>
</row>
<row>
<entry>cookiePath</entry>
<entry>/</entry>
<entry>Using this parameter, you can limit the visibility of the
cookie to a certain part of your site. When cookiePath is
specified, the cookie will only be visible to that path, and the
paths below it.</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section id="mvc-localeresolver-session">
<title><classname>SessionLocaleResolver</classname></title>
<para>The <classname>SessionLocaleResolver</classname> allows you to
retrieve locales from the session that might be associated with the
user's request.</para>
</section>
<section id="mvc-localeresolver-interceptor">
<title><classname>LocaleChangeInterceptor</classname></title>
<para>You can build in changing of locales using the
<classname>LocaleChangeInterceptor</classname>. This interceptor needs
to be added to one of the handler mappings (see <xref
linkend="mvc-handlermapping" />). It will detect a parameter in the
request and change the locale (it calls <literal>setLocale()</literal>
on the <interfacename>LocaleResolver</interfacename> that also exists in
the context).</para>
<programlisting language="xml">&lt;bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"&gt;
&lt;property name="paramName" value="siteLanguage"/&gt;
&lt;/bean&gt;
&lt;bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver"/&gt;
&lt;bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
&lt;property name="interceptors"&gt;
&lt;list&gt;
&lt;ref bean="localeChangeInterceptor"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="mappings"&gt;
&lt;value&gt;/**/*.view=someController&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting>
<para>All calls to all <literal>*.view</literal> resources containing a
parameter named <literal>siteLanguage</literal> will now change the
locale. So a request for the following URL,
<literal>http://www.sf.net/home.view?siteLanguage=nl</literal> will
change the site language to Dutch.</para>
</section>
</section>
<section id="mvc-themeresolver">
<title>Using themes</title>
<section id="mvc-themeresolver-introduction">
<title>Introduction</title>
<para>The <emphasis>theme</emphasis> support provided by the Spring web
MVC framework enables you to further enhance the user experience by
allowing the look and feel of your application to be
<emphasis>themed</emphasis>. A theme is basically a collection of static
resources affecting the visual style of the application, typically style
sheets and images.</para>
</section>
<section id="mvc-themeresolver-defining">
<title>Defining themes</title>
<para>When you want to use themes in your web application you'll have to
set up a
<interfacename>org.springframework.ui.context.ThemeSource</interfacename>.
The <interfacename>WebApplicationContext</interfacename> interface
extends <interfacename>ThemeSource</interfacename> but delegates its
responsibilities to a dedicated implementation. By default the delegate
will be a
<classname>org.springframework.ui.context.support.ResourceBundleThemeSource</classname>
that loads properties files from the root of the classpath. If you want
to use a custom <interfacename>ThemeSource</interfacename>
implementation or if you need to configure the basename prefix of the
<classname>ResourceBundleThemeSource</classname>, you can register a
bean in the application context with the reserved name "themeSource".
The web application context will automatically detect that bean and
start using it.</para>
<para>When using the <classname>ResourceBundleThemeSource</classname>, a
theme is defined in a simple properties file. The properties file lists
the resources that make up the theme. Here is an example:</para>
<programlisting>styleSheet=/themes/cool/style.css
background=/themes/cool/img/coolBg.jpg</programlisting>
<para>The keys of the properties are the names used to refer to the
themed elements from view code. For a JSP this would typically be done
using the <literal>spring:theme</literal> custom tag, which is very
similar to the <literal>spring:message</literal> tag. The following JSP
fragment uses the theme defined above to customize the look and
feel:</para>
<programlisting language="xml">&lt;%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%&gt;
&lt;html&gt;
&lt;head&gt;
&lt;link rel="stylesheet" href="&lt;spring:theme code="styleSheet"/&gt;" type="text/css"/&gt;
&lt;/head&gt;
&lt;body background="&lt;spring:theme code="background"/&gt;"&gt;
...
&lt;/body&gt;
&lt;/html&gt;</programlisting>
<para>By default, the <classname>ResourceBundleThemeSource</classname>
uses an empty basename prefix. As a result the properties files will be
loaded from the root of the classpath, so we'll have to put our
<literal>cool.properties</literal> theme definition in a directory at
the root of the classpath, e.g. in <literal>/WEB-INF/classes</literal>.
Note that the <classname>ResourceBundleThemeSource</classname> uses the
standard Java resource bundle loading mechanism, allowing for full
internationalization of themes. For instance, we could have a
<literal>/WEB-INF/classes/cool_nl.properties</literal> that references a
special background image, e.g. with Dutch text on it.</para>
</section>
<section id="mvc-themeresolver-resolving">
<title>Theme resolvers</title>
<para>Now that we have our themes defined, the only thing left to do is
decide which theme to use. The <classname>DispatcherServlet</classname>
will look for a bean named "themeResolver" to find out which
<interfacename>ThemeResolver</interfacename> implementation to use. A
theme resolver works in much the same way as a
<interfacename>LocaleResolver</interfacename>. It can detect the theme
that should be used for a particular request and can also alter the
request's theme. The following theme resolvers are provided by
Spring:</para>
<table id="mvc-theme-resolver-impls-tbl">
<title><interfacename>ThemeResolver</interfacename>
implementations</title>
<tgroup cols="2">
<colspec colname="c1" colwidth="1*" />
<colspec colname="c3" colwidth="3*" />
<thead>
<row>
<entry>Class</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><classname>FixedThemeResolver</classname></entry>
<entry>Selects a fixed theme, set using the "defaultThemeName"
property.</entry>
</row>
<row>
<entry><classname>SessionThemeResolver</classname></entry>
<entry>The theme is maintained in the users HTTP session. It
only needs to be set once for each session, but is not persisted
between sessions.</entry>
</row>
<row>
<entry><classname>CookieThemeResolver</classname></entry>
<entry>The selected theme is stored in a cookie on the
user-agent's machine.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>Spring also provides a
<classname>ThemeChangeInterceptor</classname>, which allows changing the
theme on every request by including a simple request parameter.</para>
</section>
</section>
<section id="mvc-multipart">
<title>Spring's multipart (fileupload) support</title>
<section id="mvc-multipart-introduction">
<title>Introduction</title>
<para>Spring has built-in multipart support to handle fileuploads in web
applications. The design for the multipart support is done with
pluggable <interfacename>MultipartResolver</interfacename> objects,
defined in the <literal>org.springframework.web.multipart</literal>
package. Out of the box, Spring provides a
<interfacename>MultipartResolver</interfacename> for use with
<emphasis>Commons FileUpload</emphasis> (<ulink
url="http://jakarta.apache.org/commons/fileupload"></ulink>). How
uploading files is supported will be described in the rest of this
chapter.</para>
<para>By default, no multipart handling will be done by Spring, as some
developers will want to handle multiparts themselves. You will have to
enable it yourself by adding a multipart resolver to the web
application's context. After you have done that, each request will be
inspected to see if it contains a multipart. If no multipart is found,
the request will continue as expected. However, if a multipart is found
in the request, the <classname>MultipartResolver</classname> that has
been declared in your context will be used. After that, the multipart
attribute in your request will be treated like any other
attribute.</para>
</section>
<section id="mvc-multipart-resolver">
<title>Using the
<interfacename>MultipartResolver</interfacename></title>
<para>The following example shows how to use the
<classname>CommonsMultipartResolver</classname>:</para>
<programlisting language="xml">&lt;bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"&gt;
<lineannotation>&lt;!-- one of the properties available; the maximum file size in bytes --&gt;</lineannotation>
&lt;property name="maxUploadSize" value="100000"/&gt;
&lt;/bean&gt;</programlisting>
<para>This is an example using the
<classname>CosMultipartResolver</classname>:</para>
<programlisting language="xml">&lt;bean id="multipartResolver" class="org.springframework.web.multipart.cos.CosMultipartResolver"&gt;
<lineannotation>&lt;!-- one of the properties available; the maximum file size in bytes --&gt;</lineannotation>
&lt;property name="maxUploadSize" value="100000"/&gt;
&lt;/bean&gt;</programlisting>
<para>Of course you also need to put the appropriate jars in your
classpath for the multipart resolver to work. In the case of the
<classname>CommonsMultipartResolver</classname>, you need to use
<literal>commons-fileupload.jar</literal>; in the case of the
<classname>CosMultipartResolver</classname>, use
<literal>cos.jar</literal>.</para>
<para>Now that you have seen how to set Spring up to handle multipart
requests, let's talk about how to actually use it. When the Spring
<classname>DispatcherServlet</classname> detects a multi-part request,
it activates the resolver that has been declared in your context and
hands over the request. What the resolver then does is wrap the current
<classname>HttpServletRequest</classname> into a
<classname>MultipartHttpServletRequest</classname> that has support for
multipart file uploads. Using the
<classname>MultipartHttpServletRequest</classname> you can get
information about the multiparts contained by this request and actually
get access to the multipart files themselves in your controllers.</para>
</section>
<section id="mvc-multipart-forms">
<title>Handling a file upload in a form</title>
<para>After the <classname>MultipartResolver</classname> has finished
doing its job, the request will be processed like any other. To use it,
you create a form with an upload field (see immediately below), then let
Spring bind the file onto your form (backing object). To actually let
the user upload a file, we have to create a (HTML) form:</para>
<programlisting language="xml">&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Upload a file please&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h1&gt;Please upload a file&lt;/h1&gt;
&lt;form method="post" action="upload.form" enctype="multipart/form-data"&gt;
&lt;input type="file" name="file"/&gt;
&lt;input type="submit"/&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</programlisting>
<para>As you can see, we've created a field named after the property of
the bean that holds the <literal>byte[]</literal>. Furthermore we've
added the encoding attribute
(<literal>enctype="multipart/form-data"</literal>) which is necessary to
let the browser know how to encode the multipart fields (do not forget
this!).</para>
<para>Just as with any other property that's not automagically
convertible to a string or primitive type, to be able to put binary data
in your objects you have to register a custom editor with the
<classname>ServletRequestDatabinder</classname>. There are a couple of
editors available for handling files and setting the results on an
object. There's a <classname>StringMultipartEditor</classname> capable
of converting files to Strings (using a user-defined character set) and
there is a <classname>ByteArrayMultipartEditor</classname> which
converts files to byte arrays. They function just as the
<classname>CustomDateEditor</classname> does.</para>
<para>So, to be able to upload files using a (HTML) form, declare the
resolver, a url mapping to a controller that will process the bean, and
the controller itself.</para>
<programlisting language="xml">&lt;beans&gt;
<lineannotation>&lt;!-- lets use the Commons-based implementation of the MultipartResolver interface --&gt;</lineannotation>
&lt;bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/&gt;
&lt;bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
&lt;property name="mappings"&gt;
&lt;value&gt;
/upload.form=fileUploadController
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="fileUploadController" class="examples.FileUploadController"&gt;
&lt;property name="commandClass" value="examples.FileUploadBean"/&gt;
&lt;property name="formView" value="fileuploadform"/&gt;
&lt;property name="successView" value="confirmation"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;</programlisting>
<para>After that, create the controller and the actual class to hold the
file property.</para>
<programlisting language="java">public class FileUploadController extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors) throws ServletException, IOException {
<lineannotation> // cast the bean</lineannotation>
FileUploadBean bean = (FileUploadBean) command;
<lineannotation> let's see if there's content there</lineannotation>
byte[] file = bean.getFile();
if (file == null) {
<lineannotation> // hmm, that's strange, the user did not upload anything</lineannotation>
}
<lineannotation> // well, let's do nothing with the bean for now and return</lineannotation>
return super.onSubmit(request, response, command, errors);
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws ServletException {
// to actually be able to convert Multipart instance to byte[]
// we have to register a custom editor
binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
// now Spring knows how to handle multipart object and convert them
}
}
public class FileUploadBean {
private byte[] file;
public void setFile(byte[] file) {
this.file = file;
}
public byte[] getFile() {
return file;
}
}</programlisting>
<para>As you can see, the <classname>FileUploadBean</classname> has a
property typed <literal>byte[]</literal> that holds the file. The
controller registers a custom editor to let Spring know how to actually
convert the multipart objects the resolver has found to properties
specified by the bean. In this example, nothing is done with the
<literal>byte[]</literal> property of the bean itself, but in practice
you can do whatever you want (save it in a database, mail it to
somebody, etc).</para>
<para>An equivalent example in which a file is bound straight to a
String-typed property on a (form backing) object might look like:</para>
<programlisting language="java">public class FileUploadController extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors) throws ServletException, IOException {
<lineannotation> // cast the bean</lineannotation>
FileUploadBean bean = (FileUploadBean) command;
<lineannotation> let's see if there's content there</lineannotation>
String file = bean.getFile();
if (file == null) {
<lineannotation> // hmm, that's strange, the user did not upload anything</lineannotation>
}
<lineannotation> // well, let's do nothing with the bean for now and return</lineannotation>
return super.onSubmit(request, response, command, errors);
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws ServletException {
// to actually be able to convert Multipart instance to a String
// we have to register a custom editor
binder.registerCustomEditor(String.class, new StringMultipartFileEditor());
// now Spring knows how to handle multipart object and convert them
}
}
public class FileUploadBean {
private String file;
public void setFile(String file) {
this.file = file;
}
public String getFile() {
return file;
}
}</programlisting>
<para>Of course, this last example only makes (logical) sense in the
context of uploading a plain text file (it wouldn't work so well in the
case of uploading an image file).</para>
<para>The third (and final) option is where one binds directly to a
<interfacename>MultipartFile</interfacename> property declared on the
(form backing) object's class. In this case one does not need to
register any custom <interfacename>PropertyEditor</interfacename>
because there is no type conversion to be performed.</para>
<programlisting language="java">public class FileUploadController extends SimpleFormController {
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response,
Object command, BindException errors) throws ServletException, IOException {
<lineannotation> // cast the bean</lineannotation>
FileUploadBean bean = (FileUploadBean) command;
<lineannotation> let's see if there's content there</lineannotation>
MultipartFile file = bean.getFile();
if (file == null) {
<lineannotation> // hmm, that's strange, the user did not upload anything</lineannotation>
}
<lineannotation> // well, let's do nothing with the bean for now and return</lineannotation>
return super.onSubmit(request, response, command, errors);
}
}
public class FileUploadBean {
private MultipartFile file;
public void setFile(MultipartFile file) {
this.file = file;
}
public MultipartFile getFile() {
return file;
}
}</programlisting>
</section>
</section>
<section id="mvc-exceptionhandlers">
<title>Handling exceptions</title>
<para>Spring provides <literal>HandlerExceptionResolvers</literal> to ease
the pain of unexpected exceptions occurring while your request is being
handled by a controller which matched the request.
<literal>HandlerExceptionResolvers</literal> somewhat resemble the
exception mappings you can define in the web application descriptor
<literal>web.xml</literal>. However, they provide a more flexible way to
handle exceptions. They provide information about what handler was
executing when the exception was thrown. Furthermore, a programmatic way
of handling exception gives you many more options for how to respond
appropriately before the request is forwarded to another URL (the same end
result as when using the servlet specific exception mappings).</para>
<para>Besides implementing the
<interfacename>HandlerExceptionResolver</interfacename> interface, which
is only a matter of implementing the <literal>resolveException(Exception,
Handler)</literal> method and returning a
<classname>ModelAndView</classname>, you may also use the
<classname>SimpleMappingExceptionResolver</classname>. This resolver
enables you to take the class name of any exception that might be thrown
and map it to a view name. This is functionally equivalent to the
exception mapping feature from the Servlet API, but it's also possible to
implement more finely grained mappings of exceptions from different
handlers.</para>
<section id="mvc-ann-exceptionhandler">
<title><interfacename>@ExceptionResolver</interfacename></title>
<para>As an alternative to implementing the <interfacename>HandlerExceptionResolver</interfacename>, you
can use the <interfacename>@ExceptionHandler</interfacename>. The <classname>@ExceptionHandler</classname> method annotation is
used within a controller to specify which method will be invoked when an
exception of a specific type is thrown during the execution of
controller methods. For example</para>
<programlisting language="java">@Controller
public class SimpleController {
// other controller method omitted
@ExceptionHandler(IOException.class)
public String handleIOException(IOException ex, HttpServletRequest request) {
return ClassUtils.getShortName(ex.getClass());
}
}</programlisting>
<para>will invoke the 'handlerIOException' method when a
<classname>java.io.IOException</classname> is thrown.</para>
<para>The <classname>@ExceptionHandler</classname> value can be set to
an array of Exception types. If an exception is thrown matches one of
the types in the list, then the method annotated with the matching
<classname>@ExceptionHandler</classname> will be invoked. If the
annotation value is not set then the exception types listed as method
arguments are used.</para>
<para>Much like standard controller methods annotated with a
<classname>@RequestMapping</classname> annotation, the method arguments
and return values of <classname>@ExceptionHandler</classname> methods
are very flexible. For example, the
<classname>HttpServletRequest</classname> can be accessed in Servlet
environments and the <classname>PortletRequest</classname> in Portlet
environments. The return type can be a <classname>String</classname>,
which is interpreted as a view name or a
<classname>ModelAndView</classname> object. Please refer to the API
documentation for more details.</para>
</section>
</section>
<section id="mvc-coc">
<title>Convention over configuration</title>
<para>For a lot of projects, sticking to established conventions and
having reasonable defaults is just what they (the projects) need... this
theme of convention-over-configuration now has explicit support in Spring
Web MVC. What this means is that if you establish a set of naming
conventions and suchlike, you can <emphasis>substantially</emphasis> cut
down on the amount of configuration that is required to set up handler
mappings, view resolvers, <classname>ModelAndView</classname> instances,
etc. This is a great boon with regards to rapid prototyping, and can also
lend a degree of (always good-to-have) consistency across a codebase
should you choose to move forward with it into production.</para>
<para>This convention over configuration support address the three core
areas of MVC - namely, the models, views, and controllers.</para>
<section id="mvc-coc-ccnhm">
<title>The Controller -
<classname>ControllerClassNameHandlerMapping</classname></title>
<para>The <classname>ControllerClassNameHandlerMapping</classname> class
is a <interfacename>HandlerMapping</interfacename> implementation that
uses a convention to determine the mapping between request URLs and the
<interfacename>Controller</interfacename> instances that are to handle
those requests.</para>
<para>An example; consider the following (simplistic)
<interfacename>Controller</interfacename> implementation. Take especial
notice of the <emphasis>name</emphasis> of the class.</para>
<programlisting language="java">public class <emphasis role="bold">ViewShoppingCartController</emphasis> implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
<lineannotation>// the implementation is not hugely important for this example...</lineannotation>
}
}</programlisting>
<para>Here is a snippet from the attendent Spring Web MVC configuration
file...</para>
<programlisting language="xml">&lt;bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/&gt;
&lt;bean id="<emphasis role="bold">viewShoppingCart</emphasis>" class="x.y.z.ViewShoppingCartController"&gt;
<lineannotation>&lt;!-- inject dependencies as required... --&gt;</lineannotation>
&lt;/bean&gt;</programlisting>
<para>The <classname>ControllerClassNameHandlerMapping</classname> finds
all of the various handler (or
<interfacename>Controller</interfacename>) beans defined in its
application context and strips <literal>'Controller'</literal> off the
name to define its handler mappings.</para>
<para>Let's look at some more examples so that the central idea becomes
immediately familiar.</para>
<itemizedlist>
<listitem>
<para><classname>WelcomeController</classname> maps to the
<literal>'/welcome*'</literal> request URL</para>
</listitem>
<listitem>
<para><classname>HomeController</classname> maps to the
<literal>'/home*'</literal> request URL</para>
</listitem>
<listitem>
<para><classname>IndexController</classname> maps to the
<literal>'/index*'</literal> request URL</para>
</listitem>
<listitem>
<para><classname>RegisterController</classname> maps to the
<literal>'/register*'</literal> request URL</para>
</listitem>
<listitem>
<para><classname>DisplayShoppingCartController</classname> maps to
the <literal>'/displayshoppingcart*'</literal> request URL</para>
<para><emphasis>(Notice the casing - all lowercase - in the case of
camel-cased <interfacename>Controller</interfacename> class
names.)</emphasis></para>
</listitem>
</itemizedlist>
<para>In the case of <classname>MultiActionController</classname>
handler classes, the mappings generated are (ever so slightly) more
complex, but hopefully no less understandable. Some examples (all of the
<interfacename>Controller</interfacename> names in this next bit are
assumed to be <classname>MultiActionController</classname>
implementations).</para>
<itemizedlist>
<listitem>
<para><classname>AdminController</classname> maps to the
<literal>'/admin<emphasis role="bold">/*</emphasis>'</literal>
request URL</para>
</listitem>
<listitem>
<para><classname>CatalogController</classname> maps to the
<literal>'/catalog<emphasis role="bold">/*</emphasis>'</literal>
request URL</para>
</listitem>
</itemizedlist>
<para>If you follow the pretty standard convention of naming your
<interfacename>Controller</interfacename> implementations as
<literal>xxx<emphasis role="bold">Controller</emphasis></literal>, then
the <classname>ControllerClassNameHandlerMapping</classname> will save
you the tedium of having to firstly define and then having to maintain a
potentially <emphasis>looooong</emphasis>
<classname>SimpleUrlHandlerMapping</classname> (or suchlike).</para>
<para>The <classname>ControllerClassNameHandlerMapping</classname> class
extends the <classname>AbstractHandlerMapping</classname> base class so
you can define <interfacename>HandlerInterceptor</interfacename>
instances and everything else just like you would with many other
<interfacename>HandlerMapping</interfacename> implementations.</para>
</section>
<section id="mvc-coc-modelmap">
<title>The Model - <classname>ModelMap</classname>
(<classname>ModelAndView</classname>)</title>
<para>The <classname>ModelMap</classname> class is essentially a
glorified <interfacename>Map</interfacename> that can make adding
objects that are to be displayed in (or on) a
<interfacename>View</interfacename> adhere to a common naming
convention. Consider the following
<interfacename>Controller</interfacename> implementation; notice that
objects are added to the <classname>ModelAndView</classname> without any
associated name being specified.</para>
<programlisting language="java">public class DisplayShoppingCartController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
List cartItems = <lineannotation>// get a <interfacename>List</interfacename> of <classname>CartItem</classname> objects</lineannotation>
User user = <lineannotation>// get the <classname>User</classname> doing the shopping</lineannotation>
ModelAndView mav = new ModelAndView("displayShoppingCart"); <lineannotation>&lt;-- the logical view name</lineannotation>
mav.addObject(cartItems); <lineannotation>&lt;-- look ma, no name, just the object</lineannotation>
mav.addObject(user); <lineannotation>&lt;-- and again ma!</lineannotation>
return mav;
}
}</programlisting>
<para>The <classname>ModelAndView</classname> class uses a
<classname>ModelMap</classname> class that is a custom
<interfacename>Map</interfacename> implementation that automatically
generates a key for an object when an object is added to it. The
strategy for determining the name for an added object is, in the case of
a scalar object such as <classname>User</classname>, to use the short
class name of the object's class. Find below some examples of the names
that are generated for scalar objects put into a
<classname>ModelMap</classname> instance.</para>
<itemizedlist>
<listitem>
<para>An <classname>x.y.User</classname> instance added will have
the name <literal>'user'</literal> generated</para>
</listitem>
<listitem>
<para>An <classname>x.y.Registration</classname> instance added will
have the name <literal>'registration'</literal> generated</para>
</listitem>
<listitem>
<para>An <classname>x.y.Foo</classname> instance added will have the
name <literal>'foo'</literal> generated</para>
</listitem>
<listitem>
<para>A <classname>java.util.HashMap</classname> instance added will
have the name <literal>'hashMap'</literal> generated (you'll
probably want to be explicit about the name in this case because
<literal>'hashMap'</literal> is less than intuitive).</para>
</listitem>
<listitem>
<para>Adding <literal>null</literal> will result in an
<classname>IllegalArgumentException</classname> being thrown. If the
object (or objects) that you are adding could potentially be
<literal>null</literal>, then you will also want to be explicit
about the name).</para>
</listitem>
</itemizedlist>
<sidebar>
<title>What, no automatic pluralisation?</title>
<para>Spring Web MVC's convention over configuration support does not
support automatic pluralisation. That is to say, you cannot add a
<interfacename>List</interfacename> of <classname>Person</classname>
objects to a <classname>ModelAndView</classname> and have the
generated name be 'people'.</para>
<para>This decision was taken after some debate, with the
<quote>Principle of Least Surprise</quote> winning out in the
end.</para>
</sidebar>
<para>The strategy for generating a name after adding a
<interfacename>Set</interfacename>, <interfacename>List</interfacename>
or array object is to peek into the collection, take the short class
name of the first object in the collection, and use that with
<literal>'List'</literal> appended to the name. Some examples will make
the semantics of name generation for collections clearer...</para>
<itemizedlist>
<listitem>
<para>An <classname>x.y.User[]</classname> array with one or more
<classname>x.y.User</classname> elements added will have the name
<literal>'userList'</literal> generated</para>
</listitem>
<listitem>
<para>An <classname>x.y.Foo[]</classname> array with one or more
<classname>x.y.User</classname> elements added will have the name
<literal>'fooList'</literal> generated</para>
</listitem>
<listitem>
<para>A <classname>java.util.ArrayList</classname> with one or more
<classname>x.y.User</classname> elements added will have the name
<literal>'userList'</literal> generated</para>
</listitem>
<listitem>
<para>A <classname>java.util.HashSet</classname> with one or more
<classname>x.y.Foo</classname> elements added will have the name
<literal>'fooList'</literal> generated</para>
</listitem>
<listitem>
<para>An <emphasis role="bold">empty</emphasis>
<classname>java.util.ArrayList</classname> will not be added at all
(i.e. the <methodname>addObject(..)</methodname> call will
essentially be a no-op).</para>
</listitem>
</itemizedlist>
</section>
<section id="mvc-coc-r2vnt">
<title>The View -
<interfacename>RequestToViewNameTranslator</interfacename></title>
<para>The <interfacename>RequestToViewNameTranslator</interfacename>
interface is responsible for determining a logical
<interfacename>View</interfacename> name when no such logical view name
is explicitly supplied. It has just one implementation, the rather
cunningly named
<classname>DefaultRequestToViewNameTranslator</classname> class.</para>
<para>The <classname>DefaultRequestToViewNameTranslator</classname> maps
request URLs to logical view names in a fashion that is probably best
explained by recourse to an example.</para>
<programlisting language="java">public class RegistrationController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
<lineannotation>// process the request...</lineannotation>
ModelAndView mav = new ModelAndView();
<lineannotation>// add <emphasis role="bold">data</emphasis> as necessary to the model...</lineannotation>
return mav;
<lineannotation>// notice that no <interfacename>View</interfacename> or logical view name has been set</lineannotation>
}
}</programlisting>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"&gt;
&lt;beans&gt;
<lineannotation>&lt;!-- this bean with the well known name generates view names for us --&gt;</lineannotation>
&lt;bean id="viewNameTranslator" class="org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator"/&gt;
&lt;bean class="x.y.RegistrationController"&gt;
<lineannotation>&lt;!-- inject dependencies as necessary --&gt;</lineannotation>
&lt;/bean&gt;
<lineannotation>&lt;!-- maps request URLs to Controller names --&gt;</lineannotation>
&lt;bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/&gt;
&lt;bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"&gt;
&lt;property name="prefix" value="/WEB-INF/jsp/"/&gt;
&lt;property name="suffix" value=".jsp"/&gt;
&lt;/bean&gt;
&lt;/beans&gt;
</programlisting>
<para>Notice how in the implementation of the
<literal>handleRequest(..)</literal> method no
<interfacename>View</interfacename> or logical view name is ever set on
the <classname>ModelAndView</classname> that is returned. It is the
<classname>DefaultRequestToViewNameTranslator</classname> that will be
tasked with generating a <emphasis>logical view name</emphasis> from the
URL of the request. In the case of the above
<classname>RegistrationController</classname>, which is being used in
conjunction with the
<classname>ControllerClassNameHandlerMapping</classname>, a request URL
of <literal>'http://localhost/registration.html'</literal> will result
in a logical view name of <literal>'registration'</literal> being
generated by the
<classname>DefaultRequestToViewNameTranslator</classname>. This logical
view name will then be resolved into the
<literal>'/WEB-INF/jsp/registration.jsp'</literal> view by the
<classname>InternalResourceViewResolver</classname> bean.</para>
<tip>
<para>You don't even need to define a
<classname>DefaultRequestToViewNameTranslator</classname> bean
explicitly. If you are okay with the default settings of the
<classname>DefaultRequestToViewNameTranslator</classname>, then you
can rely on the fact that the Spring Web MVC
<classname>DispatcherServlet</classname> will actually instantiate an
instance of this class if one is not explicitly configured.</para>
</tip>
<para>Of course, if you need to change the default settings, then you do
need to configure your own
<classname>DefaultRequestToViewNameTranslator</classname> bean
explicitly. Please do consult the quite comprehensive Javadoc for the
<classname>DefaultRequestToViewNameTranslator</classname> class for
details of the various properties that can be configured.</para>
</section>
</section>
<section id="mvc-resources">
<title>Further Resources</title>
<para>Find below links and pointers to further resources about Spring Web
MVC.</para>
<itemizedlist>
<listitem>
<para>The Spring distribution ships with a Spring Web MVC tutorial
that guides the reader through building a complete Spring Web
MVC-based application using a step-by-step approach. This tutorial is
available in the <literal>'docs'</literal> directory of the Spring
distribution. An online version can also be found on the <ulink
url="http://springframework.org/">Spring Framework
website</ulink>.</para>
</listitem>
<listitem>
<para>The book entitled <quote>Expert Spring Web MVC and Web
Flow</quote> by Seth Ladd and others (published by Apress) is an
excellent hardcopy source of Spring Web MVC goodness.</para>
</listitem>
</itemizedlist>
</section>
</chapter>