diff --git a/spring-framework-reference/src/mvc.xml b/spring-framework-reference/src/mvc.xml index 03bb51618da..e714ff45893 100644 --- a/spring-framework-reference/src/mvc.xml +++ b/spring-framework-reference/src/mvc.xml @@ -5,43 +5,36 @@ Web MVC framework
- Introduction + Introduction to Spring Web MVC framework - Spring's Web MVC framework is designed around a - DispatcherServlet that dispatches requests to - handlers, with configurable handler mappings, view resolution, locale and - theme resolution as well as support for uploading files. The default + The Spring Web model-view-controller (MVC) framework is designed + around a DispatcherServlet 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 @Controller and @RequestMapping annotations, offering a wide range of flexible handling methods. With the introduction of Spring 3.0, the @Controller mechanism also allows - you to create RESTful Web sites or application, though the + you to create RESTful Web sites and applications, through the @PathVarariable annotation and other features. <quote>Open for extension...</quote> - One of the overarching design principles in Spring Web MVC (and in - Spring in general) is the Open for extension, closed - for modification principle. + A key design principle in Spring Web MVC and in Spring in general + is the Open for extension, closed for + modification principle. - 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 - final. This means of course that you as a developer - cannot override these methods to supply your own behavior... this is - by design and has not been done arbitrarily to - annoy. + Some methods in the core classes of Spring Web MVC are marked + final. As a developer you cannot override these + methods to supply your own behavior. This has not been done arbitrarily, but + specifically with this principal in mind. - 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'. - - 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 Gah! Why can't I override this method? (if indeed - you ever do). + For an explanation of this principle, refer to Expert + Spring Web MVC and Web Flow by Seth Ladd and others; + specifically see the section "A Look At Design," on page 117 of the + first edition. Alternatively, see @@ -51,166 +44,170 @@ - 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 + You cannot add advice to final methods when you use Spring MVC. + For example, you cannot add advice to the AbstractController.handleRequest() method. Refer to for more information on AOP proxies and why you cannot add advice to final methods. - 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 + In Spring Web MVC you can use any object as a command or + form-backing object; you do not 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. + evaluated by the application, not as system errors. Thus you need not + duplicate your business objects' properties as simple, untyped strings in + your form objects simply to handle invalid submissions, or to convert the + Strings properly. Instead, it is often preferable to bind directly to your + business objects. Spring's view resolution is extremely flexible. A Controller implementation can even write - directly to the response stream. In the normal case, a + directly to the response stream. Typically, a ModelAndView instance consists of a view name and a model Map, 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 - ViewResolver implementation. The fact that - the model (the M in MVC) is based on the - Map 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 Map is simply transformed into an + corresponding objects such as a command or form, which contain reference + data. View name resolution is highly configurable, through bean names, a + properties file, or your own ViewResolver + implementation. The model (the M in MVC) is based on the + Map interface, which allows for the + complete abstraction of the view technology. You can integrate directly + JSP, Velocity, or any other rendering technology. The model + Map is simply transformed into an appropriate format, such as JSP request attributes or a Velocity template model. -
- Pluggability of other MVC implementations - - 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. - - 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 - ContextLoaderListener, and access it via its - ServletContext 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. - - 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. -
-
- Features of Spring Web MVC + Features of Spring Web MVC<!--I moved Features of Spring Web MVC before Pluggability of other MVC implementations. You want to highlight your own imp. first.--> + + - Spring's web module provides a wealth of unique web support - features, including: + Spring's web module includes many unique web support + features: - Clear separation of roles - controller, validator, command - object, form object, model object, + Clear separation of roles. Each role -- + controller, validator, command object, form object, model object, DispatcherServlet, handler mapping, view - resolver, etc. Each role can be fulfilled by a specialized + resolver, and so on -- can be fulfilled by a specialized object. - 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. + Powerful and straightforward configuration of both + framework and application classes as JavaBeans. This + configuration capability includes easy referencing across contexts, + such as from web controllers to business objects and + validators. - 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. + Adaptability, non-intrusiveness, and + flexibility. Define any controller method signature you + need, possibly using one of the parameter annotations (such as + @RequestParam, @RequestHeader, @PathVariable, and more) for a given + scenario. - 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. + Reusable business code, no need + for duplication. Use existing business objects as command + or form objects instead of mirroring them to extend a particular + framework base class. - 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. + Customizable binding and validation. Type + mismatches as application-level validation errors that keep the + offending value, localized date and number binding, and so on + instead of String-only form objects with manual parsing and + conversion to business objects. - 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. + Customizable handler mapping and view + resolution. Handler mapping and view resolution + strategies range from simple URL-based configuration, to + sophisticated, purpose-built resolution strategies. Spring is more + flexible than web MVC frameworks that mandate a particular + technique. - Flexible model transfer - model transfer via a name/value - Map supports easy integration with - any view technology. + Flexible model transfer. Model transfer + with a name/value Map supports easy + integration with any view technology. - 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. + 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, and so + on. - 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 - - - - A JSP form tag library, introduced in Spring 2.0, that makes - writing forms in JSP pages much easier. For information on the tag + 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 + linkend="spring.tld" /> - Beans whose lifecycle is scoped to the current HTTP request or - HTTP Session. This is not a specific - feature of Spring MVC itself, but rather of the - WebApplicationContext container(s) - that Spring MVC uses. These bean scopes are described in detail in - the section entitled + 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 + + + + + Beans whose lifecycle is scoped to the current HTTP + request or HTTP Session. + This is not a specific feature of Spring MVC itself, but rather of + the WebApplicationContext + container(s) that Spring MVC uses. These bean scopes are described + in
+ +
+ Pluggability of other MVC implementations + + Non-Spring MVC implementations are preferable for some projects. + Many teams expect to leverage their existing investment in skills and + tools. A large body of knowledge and experience exist for the Struts + framework. If you can abide Struts' architectural flaws, it can be a + viable choice for the web layer; the same applies to WebWork and other + web MVC frameworks. + + If you do not 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 through its + ContextLoaderListener, and access it through + its + ServletContext attribute (or Spring's + respective helper method) from within a Struts or WebWork action. No + "plug-ins" are involved, so no dedicated integration is necessary. From + the web layer's point of view, you simply use Spring as a library, with + the root application context instance as the entry point. + + Your registered beans and Spring's services can be at your + fingertips even without Spring's Web MVC. Spring does not compete with + Struts or WebWork in this scenario. It simply addresses the many areas + that the pure web MVC frameworks do not, from bean configuration to data + access and transaction handling. So you can 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. +
@@ -218,11 +215,11 @@ 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 DispatcherServlet - 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. + to controllers and offers other functionality that facilitates the + development of web applications. Spring's + DispatcherServlet 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. The request processing workflow of the Spring Web MVC DispatcherServlet is illustrated in the following @@ -244,15 +241,15 @@ (high level) - The DispatcherServlet is - an actual Servlet (it inherits from the + The DispatcherServlet is an actual + Servlet (it inherits from the HttpServlet base class), and as such is declared in - the web.xml of your web application. Requests that you - want the DispatcherServlet to handle will have to - be mapped using a URL mapping in the same web.xml file. - This is standard J2EE servlet configuration; an example of such a - DispatcherServlet declaration and mapping can be - found below. + the web.xml of your web application. You need to map + requests that you want the DispatcherServlet to + handle, by using a URL mapping in the same web.xml + file. This is standard J2EE servlet configuration; the following example + shows such a DispatcherServlet declaration and + mapping: <web-app> @@ -269,24 +266,23 @@ </web-app> - In the example above, all requests ending with - .form will be handled by the - 'example' DispatcherServlet. - 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 - DispatcherServlet itself) now need to be - configured. + In the preceding example, all requests ending with + .form will be handled by the example + DispatcherServlet. This is only the first step in + setting up Spring Web MVC. You + now need to configure the various beans used by the Spring Web MVC + framework (over and above the DispatcherServlet + itself). - As detailed in the section entitled , + As detailed in , ApplicationContext instances in Spring can - be scoped. In the web MVC framework, each + be scoped. In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. 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 + beans defined can be overridden in the servlet-specific scope, and + you can define new scope-specific beans local to a given servlet instance. @@ -300,18 +296,19 @@ format="GIF" /> - Context hierarchy in Spring Web MVC + Context hierarchy in Spring Web MVC - The framework will, on initialization of a - DispatcherServlet, look for a file named + Upon initialization of a DispatcherServlet, + the framework looks + for a file named [servlet-name]-servlet.xml in the WEB-INF 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). + the beans defined there, overriding the definitions of any beans defined + with the same name in the global scope. Consider the following DispatcherServlet - servlet configuration (in the 'web.xml' file.) + servlet configuration (in the web.xml file): <web-app> @@ -328,13 +325,14 @@ </web-app> - With the above servlet configuration in place, you will need to have - a file called '/WEB-INF/golfing-servlet.xml' in your application; - this file will contain all of your Spring Web - MVC-specific components (beans). The exact location of this - configuration file can be changed via a servlet initialization parameter - (see below for details). + With the above servlet configuration in place, you + will need to have a file called /WEB-INF/golfing-servlet.xml in your application; + this file will contain all of your Spring Web MVC-specific components + (beans). You can change the exact location of this configuration file + through a servlet initialization parameter (see below for details). + + The WebApplicationContext is an extension of the plain ApplicationContext @@ -346,20 +344,16 @@ WebApplicationContext is bound in the ServletContext, and by using static methods on the RequestContextUtils class you can always - lookup the WebApplicationContext in case - you need access to it. + look up the WebApplicationContext if you + need access to it. - The Spring DispatcherServlet 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 - WebApplicationContext, 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 - DispatcherServlet. For most of the beans, sensible - defaults are provided so you don't (initially) have to worry about - configuring them. + The Spring DispatcherServlet uses special + beans to process requests and render the appropriate views. These beans + are part of Spring Framework. You can configure them in the + WebApplicationContext, just as you + configure any other bean. However, for most beans, sensible defaults are + provided so you initially do not need to configure them. These + beans are described in the following table. Special beans in the @@ -380,32 +374,31 @@ <tbody> <row> - <entry>Controllers</entry> + <entry><link linkend="mvc-controller">controllers</link></entry> - <entry><link linkend="mvc-controller">Controllers</link> are the - components that form the <literal>'C'</literal> part of the - MVC.</entry> + <entry>Form the <literal>C</literal> part of the MVC.<!--Need info about controller function as with others in this list.Reader knows what C stands for.--></entry> </row> <row> - <entry>Handler mappings</entry> + <entry><link linkend="mvc-handlermapping">handler + mappings</link></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> + <entry>Handle the execution of a list of pre-processors and + post-processors and controllers that will be executed if they + match certain criteria (for example, a matching URL specified with + the controller).</entry> </row> <row> - <entry>View resolvers</entry> + <entry><link linkend="mvc-viewresolver">view + resolvers</link></entry> - <entry><link linkend="mvc-viewresolver">View resolvers</link> are - components capable of resolving view names to views</entry> + <entry>Resolves view names to views.<!--If it's capable of resolving, just say *resolves*. Like above, handler mappings are capable of handling the execution, but you just say *handle the execution*--></entry> </row> <row> - <entry>Locale resolver</entry> + <entry> <link linkend="mvc-localeresolver">locale + resolver</link></entry> <entry>A <link linkend="mvc-localeresolver">locale resolver</link> is a component capable of resolving the locale a client is using, @@ -423,90 +416,90 @@ <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> + <entry>Contains functionality to process file uploads from HTML + forms.<!--Here and next one, why not just say processes file uploads, maps executions instead of *contains functionality to*?--></entry> </row> <row> - <entry>Handler exception resolver(s)</entry> + <entry><link linkend="mvc-exceptionhandlers">handler exception + resolvers</link></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> + <entry> Contains 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> + <para>After you set up a <classname>DispatcherServlet</classname>, and a + request comes in for that specific + <classname>DispatcherServlet</classname>, the + <classname>DispatcherServlet</classname> starts processing the request as + follows:</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 + searched for and bound in the request as an attribute that the + controller and other elements in the process can use. <!--Use to do *what*? Also revise to indicate *what* searches for the WebApplicationContext -->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> + <para>The locale resolver is bound to the request to enable elements + in the process to resolve the locale to use when processing the + request (rendering the view, preparing data, and so on). If you do not + need locale resolving, you do not need it.</para> + <!--Reword 'if you don't need local resolving, you dont need to use it '. Are you saying locale resolving is optional? If you don't configure it, will this step occur?--> </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> + as views determine which theme to use. If you do not use themes, you + can ignore it.</para> + <!-- MLP perhaps say that there are not side effect to this binding.etc... Clarify *ignore it*. Does this step still occur if you don't use themes? --><!--And what if you DO use themes, what do you do and when? Same question re locale resolving.--> </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> + <para>If you specify a multipart file resolver, 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 <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> + postprocessors, and controllers) is executed in order to prepare a + model or 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> + returned, (may be due to a preprocessor or postprocessor + intercepting the request, perhaps for security reasons), no view is + rendered, because the request could already have been fulfilled.</para> + <!--fulfilled how and by what?--> </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>Handler exception resolvers that are declared in the + <interfacename>WebApplicationContext</interfacename> pick up exceptions + that are thrown during processing of the request. Using these exception + resolvers allows you to define custom behaviors to address + exceptions.</para> - <para>The Spring <classname>DispatcherServlet</classname> also has support - for returning the <emphasis>last-modification-date</emphasis>, as + <para>The Spring <classname>DispatcherServlet</classname> also supports + the return of 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> + <classname>DispatcherServlet</classname> looks up an appropriate handler + mapping and tests whether the handler that is found + implements the + </emphasis><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 @@ -514,8 +507,8 @@ <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> + servlet initialization parameters. See the following table.</para> + <!--Reword above sentence to specify whether configuring parameters in table configures last-modification-date, or are they further --><!--customization for some other purpose? If so, need to explain how you config last-modification-date--> <table id="mvc-disp-servlet-init-params-tbl"> <title><classname>DispatcherServlet</classname> initialization @@ -539,28 +532,27 @@ <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> + <interfacename>WebApplicationContext</interfacename>, which + instantiates the context used by this servlet. By default, the + <classname>XmlWebApplicationContext</classname> is 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> + <entry>String that is passed to the context instance (specified by + <literal>contextClass</literal>) to indicate where context(s) can + be found. The string consists potentially of multiple strings + (using a comma as a delimiter) to support multiple contexts. In + case of multiple context locations with beans that are defined + twice, the latest location takes precedence.</entry> + <!-- MLP review --> </row> <row> <entry><literal>namespace</literal></entry> - <entry>the namespace of the + <entry>Namespace of the <interfacename>WebApplicationContext</interfacename>. Defaults to <literal>[servlet-name]-servlet</literal>.</entry> </row> @@ -570,44 +562,37 @@ </section> <section id="mvc-controller"> - <title>Controllers + Implementing Controllers - The notion of a controller is part of the MVC design pattern (more - specifically, it is the 'C' 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. + Controllers provide access to the application behavior that you + typically define through a service interface. Controllers + interpret user input and transform it into a model that is represented to + the user by the view. Spring implements a controller in a very abstract + way, which enables you to create a wide variety of controllers.Spring 2.5 introduced an annotation-based programming model for MVC - controllers, using annotations such as + controllers that uses annotations such as @RequestMapping, @RequestParam, - @ModelAttribute, etc. This annotation + @ModelAttribute, and so on. 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. + direct dependencies on Servlet or Portlet APIs, although you can easily + configure access to Servlet or Portlet facilities. The Spring distribution ships with the - PetClinic 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 - PetClinic application in the - 'samples/petclinic' directory. + PetClinic sample, a web application that leverages + the annotation support described in this section, in the context of + simple form processing. The PetClinic application + resides in the samples/petclinic directory. - For a further sample application that builds on annotation-based - Web MVC, check out imagedb. The focus in that - sample is on stateless multi-action controllers, including the - processing of multipart file uploads. You can find the - imagedb application in the - 'samples/imagedb' directory. + + + @Controller public class HelloWorldController { @@ -621,16 +606,15 @@ public class HelloWorldController { }As you can see, the @Controller and - @RequestMapping annotations allow for - flexible method names and signatures. In this particular example the - method has no parameters and returns a - ModelAndView, but various other (and better) - strategies exist, as will be explained later in this section. - ModelAndView, + @RequestMapping annotations allow flexible + method names and signatures. In this particular example the method has no + parameters and returns a ModelAndView, but various + other (and better) strategies exist, as + are explained later in this section. ModelAndView, @Controller, and @RequestMapping form the basis for the - Spring MVC implementation. This section document these annotations and how - they are most commonly used in a Servlet environment. + Spring MVC implementation. This section documents these annotations and + how they are most commonly used in a Servlet environment.
Defining a controller with @@ -638,28 +622,27 @@ public class HelloWorldController { <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> + <emphasis>controller</emphasis>. Spring does not require you to extend + any controller base class or reference the Servlet API. However, you can + still reference Servlet-specific features if you need to do so.</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 + <para>The <interfacename>@Controller</interfacename> annotation acts as + a stereotype for the annotated class, indicating its role. The + dispatcher scans such annotated classes for mapped methods and detects <interfacename>@RequestMapping</interfacename> annotations (see the next section).</para> - <para>Annotated controller beans may be defined explicitly, using a + <para>You can define annotated controller beans 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> + <!-- MLP Bev.changed to 'also supports autodetection --> + <para>To enable autodetection of such annotated controllers, you add + component scanning to your configuration. Use the + <emphasis>spring-context</emphasis> schema as shown in the following XML + snippet:</para> <programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" @@ -683,14 +666,14 @@ public class HelloWorldController { <title>Mapping requests with <interfacename>@RequestMapping</interfacename> - The @RequestMapping annotation is - used to map URLs like /appointments 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. + You use the @RequestMapping + annotation to map URLs such as /appointments onto + an entire class or a particular handler method. You can use it to + annotate both a class and a 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. The following example shows a controller from the PetClinic sample application that uses this annotation: @@ -734,30 +717,28 @@ public class AppointmentsController { } } - In the example, above, we see that the - @RequestMapping 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 - /appointments path. Next, we see that the + In the example, the @RequestMapping + 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 are + relative to the /appointments path. The get() method has a further @RequestMapping refinement: it only accepts GET requests, meaning that an HTTP GET for - /appointments will result in this method being - invoked. The post() has a similar refinement, - and the getNewForm() combines the definition of - HTTP method and path into one, so that GET requests for + /appointments invokes this method. The + post() has a similar refinement, and the + getNewForm() combines the definition of HTTP + method and path into one, so that GET requests for appointments/new are handled by that method. The getForDay() method shows another usage of @RequestMapping: URI templates. - We will discuss these in the next section - . + (See the next + section ). A @RequestMapping 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 + not relative. The following example from the PetClinic sample + application shows a multi-action controller using @RequestMapping: @Controller @@ -784,36 +765,35 @@ public class ClinicController {
URI Templates - To easily access (parts of) a request URL in your handling - methods, Spring MVC allows for the use of URI - templates in the + To access parts of a request URL in your handling methods, use + the URI templates in the @RequestMapping path value. URI Templates 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 proposed - RFC for URI Templates defines how an URI is parameterized. + RFC for URI Templates defines how a URI is parameterized. For example, the URI Template http://www.example.com/users/{userid} - contains the variable 'userid'. If we assign the variable the - value "fred", then 'expanding' the URI Template gives. + contains the variable userid. If we + assign the variable the value fred, the URI Template yields: http://www.example.com/users/fred - When processing a request the URI can be compared to an - expected URI Template in order to extract a collection of + During the processing of a request, the URI can be compared to + an expected URI Template in order to extract a collection of variables. - The @PathVariable method - parameter annotation is used to indicate that a method parameter - should be bound to the value of a URI template variable. + You use the @PathVariable method + parameter annotation to indicate that a method parameter should be + bound to the value of a URI template variable. The following code snippet shows the use of a single @PathVariable in a controller @@ -828,35 +808,37 @@ public String findOwner(@PathVariable String ow The URI Template "/owners/{ownerId}" - 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 String + specifies the variable name ownerId. When the + controller handles this request, the value of + ownerId is set to 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 String ownerId. + 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: + name of the URI Template variable name in the @PathVariable annotation + in order to bind the resovled value of the variable name to a + method parameter. For example: @RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable("ownerId") String ownerId, Model model) { // implementation omitted } - - 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 + + so you can also use a controller method with the following + signature: @RequestMapping(value="/owners/{ownerId}", method=RequestMethod.GET) public String findOwner(@PathVariable("ownerId") String theOwner, Model model) { // implementation omitted } - Multiple @PathVariable annotations can be used to bind to - multiple URI Template variables as shown below: + You can use multiple @PathVariable annotations to bind to + multiple URI Template variables: @RequestMapping(value="/owners/{ownerId}/pets/{petId}", method=RequestMethod.GET) public String findPet(@PathVariable String ownerId, any simple type such as int, long, Date... Spring automatically converts to the appropriate type and throws a TypeMismatchException if the type is - not correct. You can further customizing this conversion process by - customizing the data binder, see .
@@ -902,9 +884,9 @@ public class RelativePathUriTemplateController { In addition to URI templates, the @RequestMapping annotation also - supports Ant-style path patterns (e.g. + supports Ant-style path patterns (for example, /myPath/*.do). A combination of URI templates and - Ant-style globs is also supported (e.g. + Ant-style globs is also supported (for example, /owners/*/pets/{petId}). The handler method names are taken into account for narrowing if @@ -912,18 +894,18 @@ public class RelativePathUriTemplateController { org.springframework.web.servlet.mvc.multiaction.MethodNameResolver (by default an org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver). - 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. + This only applies if annotation mappings 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. 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. + found are dispatched to it. If you have multiple such default methods, + then the method name is taken into account for choosing between + them. - Path mappings can be narrowed through parameter conditions: a + You can narrow path mappings 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: @Controller @@ -937,9 +919,9 @@ public class RelativePathUriTemplateController { } "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 not supposed to be present - in the request. + value). Finally, + "!myParam" style expressions indicate that the specified parameter is + not supposed to be present in the request. Similarly, path mappings can be narrowed down through header conditions: @Controller @@ -952,24 +934,23 @@ public class RelativePathUriTemplateController { // implementation omitted } } - In the above example, the addPet - will only be invoked when the Content-Type is in the - text/* range, for instance - text/xml. +
In the above example, the addPet is + only invoked when the content-type is in the text/* + range, for example, text/xml.
Supported handler method arguments and return types - Handler methods which are annotated with - @RequestMapping 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): + Handler methods that are annotated with + @RequestMapping can 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): - Request and/or response objects (Servlet API). You may - choose any specific request/response type, e.g. + Request and/or response objects (Servlet API). Choose any + specific request/response type, for example, ServletRequest / HttpServletRequest. @@ -977,13 +958,13 @@ public class RelativePathUriTemplateController { Session object (Servlet API): of type HttpSession. An argument of this - type will enforce the presence of a corresponding session. As a - consequence, such an argument will never be + type enforces the presence of a corresponding session. As a + consequence, such an argument is never null. - Note that session access may not be thread-safe, in - particular in a Servlet environment: Consider switching the + Session access may not be thread-safe, in particular in + a Servlet environment: Consider switching the AnnotationMethodHandlerAdapter's "synchronizeOnSession" flag to "true" if multiple requests are allowed to access a session concurrently. @@ -1001,49 +982,49 @@ public class RelativePathUriTemplateController { java.util.Locale for the current - request locale (determined by the most specific locale resolver - available, i.e. the configured + request locale, determined by the most specific locale resolver + available, in effect, the configured LocaleResolver in a Servlet - environment). + environment. java.io.InputStream / java.io.Reader for access to the - request's content. This will be the raw InputStream/Reader as + request's content. This value is the raw InputStream/Reader as exposed by the Servlet API. java.io.OutputStream / java.io.Writer for generating the - response's content. This will be the raw OutputStream/Writer as + response's content. This value is the raw OutputStream/Writer as exposed by the Servlet API. @PathVariabe annotated parameters - for access to URI template variables, see . @RequestParam annotated parameters for access to specific Servlet request parameters. Parameter - values will be converted to the declared method argument type. - See . + values are converted to the declared method argument type. See + . @RequestHeader annotated parameters for access to specific Servlet request HTTP headers. Parameter - values will be converted to the declared method argument + values are converted to the declared method argument type. @RequestBody annotated parameters - for access to the request HTTP body. Parameter values will be + for access to the request HTTP body. Parameter values are converted to the declared method argument type using HttpMessageConverters. See . @@ -1053,39 +1034,40 @@ public class RelativePathUriTemplateController { java.util.Map / org.springframework.ui.Model / org.springframework.ui.ModelMap for - enriching the implicit model that will be exposed to the web + enriching the implicit model that is exposed to the web view. - Command/form objects to bind parameters to: as bean - properties or fields, with customizable type conversion, - depending on @InitBinder methods and/or - the HandlerAdapter configuration - see the - "webBindingInitializer" property on + Command or form objects to bind parameters to: as bean + properties or fields, with + customizable type conversion, depending on + @InitBinder methods and/or the + HandlerAdapter configuration. See the + webBindingInitializer property on AnnotationMethodHandlerAdapter. 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 - ModelAttribute annotation for declaring a - specific model attribute name. + exposed as model attributes by default., using the non-qualified + command class name in property notation. For + example, "orderAddress" for type "mypackage.OrderAddress". + Specify a parameter-level ModelAttribute + annotation for declaring a specific model attribute name. org.springframework.validation.Errors / org.springframework.validation.BindingResult - validation results for a preceding command/form object (the - immediate preceding argument). + validation results for a preceding command or form object (the + immediately preceding argument). org.springframework.web.bind.support.SessionStatus - status handle for marking form processing as complete - (triggering the cleanup of session attributes that have been + status handle for marking form processing as complete, which + triggers the cleanup of session attributes that have been indicated by the @SessionAttributes - annotation at the handler type level). + annotation at the handler type level. @@ -1122,13 +1104,12 @@ public class RelativePathUriTemplateController { @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a - Model argument (see - above). + Model argument (see above). - A String value which is interpreted - as view name, with the model implicitly determined through + A String value that is interpreted + as the view name, with the model implicitly determined through command objects and @ModelAttribute annotated reference data accessor methods. The handler method may also programmatically enrich the model by declaring a @@ -1150,22 +1131,21 @@ public class RelativePathUriTemplateController { If the method is annotated with - @ResponseBody, the return type - will be written to the response HTTP body. The return value will - be converted to the declared method argument type using + @ResponseBody, the return type is + written to the response HTTP body. The return value will be + converted to the declared method argument type using HttpMessageConverters. See . - Any other return type will be considered as single model + Any other return type is considered as single model attribute to be exposed to the view, using the attribute name specified through @ModelAttribute 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 - @ModelAttribute annotated reference data - accessor methods. + type class name). The model is implicitly enriched with command + objects and the results of @ModelAttribute + annotated reference data accessor methods.
@@ -1174,9 +1154,8 @@ public class RelativePathUriTemplateController { Binding request parameters to method parameters with <classname>@RequestParam</classname> - The @RequestParam annotation is used to - bind request parameters to a method parameter in your - controller. + Use the @RequestParam annotation to bind + request parameters to a method parameter in your controller.The following code snippet shows the usage: @@ -1210,59 +1189,58 @@ public class EditPetForm { annotationThe @RequestBody method parameter - annotation is used to indicate that a method parameter should be bound - to the value of the HTTP request body. For example, + annotation indicates that a method parameter should be bound to the + value of the HTTP request body. For example:@RequestMapping(value = "/something", method = RequestMethod.PUT) public void handle(@RequestBody String body, Writer writer) throws IOException { writer.write(body); } - The conversion of the request body to the method argument is - done using a HttpMessageConverter. + You convert the request body to the method argument by using a + HttpMessageConverter. HttpMessageConverter is responsible for converting from the HTTP request message to an object and converting from an object to the HTTP response body. DispatcherServlet supports annotation based processing using the DefaultAnnotationHandlerMapping and - AnnotationMethodHandlerAdapter. In Spring 3 the - AnnotationMethodHandlerAdapter has been - extended to support the @RequestBody and has - several HttpMessageConverters - registered by default, these are: + AnnotationMethodHandlerAdapter. In Spring 3.0 + the AnnotationMethodHandlerAdapter is extended + to support the @RequestBody and has the + following HttpMessageConverters + registered by default: - ByteArrayHttpMessageConverter - - converts byte arrays + ByteArrayHttpMessageConverter + converts byte arrays. - StringHttpMessageConverter - converts - strings + StringHttpMessageConverter converts + strings. - FormHttpMessageConverter - converts - form data to/from a MultiValueMap<String, String> + FormHttpMessageConverter converts + form data to/from a MultiValueMap<String, String>. - SourceHttpMessageConverter - converts - to/from a javax.xml.transform.Source + SourceHttpMessageConverter converts + to/from a javax.xml.transform.Source. - MarshallingHttpMessageConverter - + MarshallingHttpMessageConverter converts to/from an object using the org.springframework.oxm package. - More information on these converters can be found in the section - Message - Converters. + For more information on these converters, see Message Converters.The MarshallingHttpMessageConverter requires a Marshaller and @@ -1298,11 +1276,12 @@ public void handle(@RequestBody String body, Writer writer) throws IOException { Mapping the response body with the @ResponseBody annotation - Similar to @RequestBody, there is - the @ResponseBody 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, + The @ResponseBody annotation is + similar to @RequestBody. 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: @RequestMapping(value = "/something", method = RequestMethod.PUT) @ResponseBody @@ -1310,15 +1289,14 @@ public String helloWorld() { return "Hello World"; } - The example above will result in the text Hello + The example will result in the text Hello World being written to the HTTP response stream. - Just like @RequestBody, the - conversion of the returned object to response body is done using a - HttpMessageConverter. More information - on these converters can be found in the previous section, or in the - section Message - Converters. + As with @RequestBody, Spring converts + the returned object to a response body by using a + HttpMessageConverter. For more + information on these converters, see the previous section and Message Converters.
@@ -1326,23 +1304,22 @@ public String helloWorld() { @ModelAttribute @ModelAttribute has two usage scenarios - in controllers. When placed on a method parameter, - @ModelAttribute is used to map a model + in controllers. When you map it to a + method parameter, @ModelAttribute maps a model attribute to the specific, annotated method parameter (see the processSubmit() method below). This is how the controller gets a reference to the object holding the data entered in the form. - @ModelAttribute is also used at the - method level to provide reference data for the - model (see the populatePetTypes() method below). - For this usage the method signature can contain the same types as - documented above for the @RequestMapping - annotation. + You can also use the @ModelAttribute at + the method level to provide reference data for + the model (see the populatePetTypes() method, as in + the following example. For this usage the method signature can contain + the same types as documented previously for the + @RequestMapping annotation. - Note: - @ModelAttribute annotated methods will be + @ModelAttribute annotated methods are executed before the chosen @RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific @@ -1386,7 +1363,7 @@ public class EditPetForm {
- Specifying attributes to store in a Session with + <title>Specifying attributes to store in a session with <classname>@SessionAttributes</classname> The type-level @SessionAttributes @@ -1470,9 +1447,9 @@ Keep-Alive 300 Customizing <classname>WebDataBinder</classname> initialization - To customize request parameter binding with PropertyEditors, - etc. via Spring's WebDataBinder, you can either - use @InitBinder-annotated methods + To customize request parameter binding with PropertyEditors + through Spring's WebDataBinder, you can use + either @InitBinder-annotated methods within your controller or externalize your configuration by providing a custom WebBindingInitializer. @@ -1483,9 +1460,9 @@ Keep-Alive 300 Annotating controller methods with @InitBinder allows you to configure web data binding directly within your controller class. - @InitBinder identifies methods which - initialize the WebDataBinder which will be - used for populating command and form object arguments of annotated + @InitBinder identifies methods that + initialize the WebDataBinder, which will be + used to populate command and form object arguments of annotated handler methods. Such init-binder methods support all arguments that @@ -1499,7 +1476,7 @@ Keep-Alive 300 context-specific editors. The following example demonstrates the use of - @InitBinder for configuring a + @InitBinder to configure a CustomDateEditor for all java.util.Date form properties. @@ -1550,72 +1527,76 @@ public class MyFormController {
Handler mappings - In previous versions of Spring MVC, users were required to define + In previous versions of Spring, users were required to define HandlerMappings in the web application context to map incoming web requests to appropriate handlers. With the - introduction of Spring 2.5, the DispatcherServlet - enables the DefaultAnnotationHandlerMapping, which - looks for @RequestMapping annotations on + introduction of Spring 2.5, the + DispatcherServlet enables the + DefaultAnnotationHandlerMapping, which looks for + @RequestMapping annotations on @Controllers. Typically, you do not need to override this default mapping, except when overriding the properties. These properties are: - interceptors: the list of interceptors to - use. HandlerInterceptors are discussed - in . + interceptors: List of interceptors to use. + HandlerInterceptors are discussed in + . - defaultHandler: the default handler to use, - when this handler mapping does not result in a matching - handler. + defaultHandler: Default handler to use, when + this handler mapping does not result in a matching handler. - order: based on the value of the order + order: Based on the value of the order property (see the org.springframework.core.Ordered - interface), Spring will sort all handler mappings available in the - context and apply the first matching handler. + interface), Spring sorts all handler mappings available in the context + and applies the first matching handler. - alwaysUseFullPath: if this property is set to - true, Spring will use the full path within the - current servlet context to find an appropriate handler. If this - property is set to false (the default), the path - within the current servlet mapping will be used. For example, if a - servlet is mapped using /testing/* and the + alwaysUseFullPath: If + true, Spring uses the full path within the current + servlet context to find an appropriate handler. If + false (the default), the path within the current + servlet mapping is used. For example, if a servlet is mapped using + /testing/* and the alwaysUseFullPath property is set to true, - /testing/viewPage.html would be used, whereas if - the property is set to false, /viewPage.html would - be used. + /testing/viewPage.html is used, whereas if the + property is set to false, /viewPage.html is + used. - urlDecode: the default value for this - property is true, as of Spring 2.5. If you prefer - to compare encoded paths, switch this flag to - false. However, note that the + urlDecode: Defaults to + true, as of Spring 2.5. If + you prefer to compare encoded paths, switch this flag to + false. However, the HttpServletRequest always exposes the servlet path in decoded form. Be aware that the servlet path will not match when compared with encoded paths. - lazyInitHandlers: allows for lazy - initialization of singleton handlers (prototype - handlers are always lazily initialized). Default value is + lazyInitHandlers: Allows lazy initialization + of singleton handlers (prototype handlers are + always lazy-initialized). The default value is false. - (Note: the last three properties are only available to + + The + alwaysUseFullPath,urlDecode, and + lazyInitHandlers properties are only available to subclasses of - org.springframework.web.servlet.handler.AbstractUrlHandlerMapping). + org.springframework.web.servlet.handler.AbstractUrlHandlerMapping. + - The following example shows how to override the default mapping, and + The following example shows how to override the default mapping and add an interceptor: <beans> @@ -1629,22 +1610,22 @@ public class MyFormController {
Intercepting requests - the - <interfacename>HandlerInterceptor</interfacename> interface + HandlerInterceptor interface - 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. + Spring's handler mapping mechanism includes handler interceptors, + which are useful when you want to apply specific functionality to + certain requests, for example, checking for a principal. Interceptors located in the handler mapping must implement HandlerInterceptor from the org.springframework.web.servlet package. This - interface defines three methods, one that will be called - before the actual handler will be executed, one - that will be called after the handler is executed, - and one that is called after the complete request has - finished. These three methods should provide enough - flexibility to do all kinds of pre- and post-processing. + interface defines three methods: one is called + before the actual handler is executed; one is + called after the handler is executed; and one is + called after the complete request has finished. + These + three methods should provide enough flexibility to do all kinds of + preprocessing and postprocessing. The preHandle(..) method returns a boolean value. You can use this method to break or continue the processing of @@ -1713,30 +1694,30 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { } } - Any request coming in, will be intercepted by the - TimeBasedAccessInterceptor, 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. + Any request coming in is intercepted by the + TimeBasedAccessInterceptor. If the current time + is outside office hours, the user is redirected to a static HTML file + that says, for example, you can only access the website during office + hours. - As you can see, Spring has an adapter class (the cunningly named - HandlerInterceptorAdapter) to make it easier to + As you can see, the Spring adapter class + HandlerInterceptorAdapter makes it easier to extend the HandlerInterceptor interface.
- Views and resolving them + Resolving views 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 has details of - how to integrate and use a number of disparate view technologies. + for example. See for a discussion of how to + integrate and use a number of disparate view technologies. - The two interfaces which are important to the way Spring handles + The two interfaces that are important to the way Spring handles views are ViewResolver and View. The ViewResolver provides a mapping between @@ -1745,15 +1726,15 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { over to one of the view technologies.
- Resolving views - the <interfacename>ViewResolver</interfacename> - interface + Resolving views with the + <interfacename>ViewResolver</interfacename> interface - As discussed in the section entitled , all controllers in the Spring Web MVC - framework return a ModelAndView 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. + As discussed in , all controllers + in the Spring Web MVC framework return a + ModelAndView 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. This table lists most of them; a + couple of examples follow.
View resolvers @@ -1775,15 +1756,15 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { AbstractCachingViewResolver - 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. + Abstract view resolver that caches views. Often views + need preparation before they can be used; extending this view + resolver provides caching. XmlViewResolver - An implementation of + Implementation of ViewResolver that accepts a configuration file written in XML with the same DTD as Spring's XML bean factories. The default configuration file is @@ -1793,11 +1774,11 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { ResourceBundleViewResolver - An implementation of + Implementation of ViewResolver that uses bean definitions in a ResourceBundle, - specified by the bundle basename. The bundle is typically - defined in a properties file, located in the classpath. The + specified by the bundle base name. Typically you define the + bundle in a properties file, located in the classpath. The default file name is views.properties. @@ -1805,7 +1786,7 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { UrlBasedViewResolver - A simple implementation of the + Simple implementation of the ViewResolver interface that effects the direct resolution of symbolic view names to URLs, without an explicit mapping definition. This is appropriate if @@ -1817,12 +1798,13 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { InternalResourceViewResolver - A convenience subclass of + Convenience subclass of UrlBasedViewResolver that supports - InternalResourceView (i.e. Servlets and - JSPs), and subclasses such as JstlView - and TilesView. The view class for all - views generated by this resolver can be specified via + InternalResourceView (in effect, Servlets + and JSPs), and subclasses such as + JstlView and + TilesView. You can specify the view class + for all views generated by this resolver by using setViewClass(..). See the Javadocs for the UrlBasedViewResolver class for details. @@ -1832,18 +1814,18 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { VelocityViewResolver / FreeMarkerViewResolver - A convenience subclass of + Convenience subclass of UrlBasedViewResolver that supports - VelocityView (i.e. Velocity templates) or - FreeMarkerView respectively and custom - subclasses of them. + VelocityView (in effect, Velocity + templates) or FreeMarkerView + ,respectively, and custom subclasses of them. ContentNegotiatingViewResolver - An implementation of the - ViewResolver interface that that + Implementation of the + ViewResolver interface that resolves a view based on the request file name or Accept header. See . @@ -1852,8 +1834,8 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
- As an example, when using JSP for a view technology you can use - the UrlBasedViewResolver. This view resolver + As an example, with JSP as a view technology, you can use the + UrlBasedViewResolver. This view resolver translates a view name to a URL and hands the request over to the RequestDispatcher to render the view. @@ -1865,12 +1847,13 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { </bean> When returning test as a viewname, this view - resolver will hand the request over to the + resolver forwards the request to the RequestDispatcher that will send the request to /WEB-INF/jsp/test.jsp. - When mixing different view technologies in a web application, you - can use the ResourceBundleViewResolver: + When you combine different view technologies in a web application, + you can use the + ResourceBundleViewResolver: <bean id="viewResolver" class="org.springframework.web.servlet.view.ResourceBundleViewResolver"> @@ -1884,37 +1867,38 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { property [viewname].class as the view class and the value of the property [viewname].url 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. + the properties file sort of extend. This + way you can specify a default view class, for example. - A note on caching - subclasses of - AbstractCachingViewResolver 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 - cache property to false. - 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 removeFromCache(String viewName, - Locale loc) method. + + Subclasses of AbstractCachingViewResolver + cache view instances that they resolve. Caching improves performance + of certain view technologies. It's possible to turn off the cache, by + setting the cache property to + false. Furthermore, if you must refresh a certain + view at runtime (for example when a Velocity template is modified), + you can use the removeFromCache(String viewName, Locale + loc) method. +
Chaining ViewResolvers - 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 order property to specify an - order. Remember, the higher the order property, the later the view - resolver will be positioned in the chain. + Spring supports multiple view resolvers. Thus you can chain + resolvers and, for example, override specific views in certain + circumstances. You chain view resolvers by adding more than one resolver + to your application context and, if necessary, by setting the + order property to specify an order. Remember, the + higher the order property, the later the view resolver is positioned in + the chain. In the following example, the chain of view resolvers consists of - two resolvers, a InternalResourceViewResolver - (which is always automatically positioned as the last resolver in the - chain) and an XmlViewResolver for specifying - Excel views (which are not supported by the - InternalResourceViewResolver): + two resolvers, a InternalResourceViewResolver, + which is always automatically positioned as the last resolver in the + chain, and an XmlViewResolver for specifying + Excel views. Excel views are not supported by the + InternalResourceViewResolver. <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> @@ -1933,43 +1917,43 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { <bean name="report" class="org.springframework.example.ReportExcelView"/> </beans> - 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 Exception. + If a specific view resolver does not result in a view, Spring + examines the context for other view resolvers. If additional view + resolvers exist, Spring continues to inspect them. If + they do not, it throws an Exception. - You have to keep something else in mind - the contract of a view - resolver mentions that a view resolver can 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 - InternalResourceViewResolver uses the - RequestDispatcher 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 VelocityViewResolver 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 + The contract of a view resolver specifies that a view resolver + can return null to indicate the view could not be + found. Not all view resolvers do this, however, because in some cases, + the resolver simply cannot detect whether or not the view exists. For + example, the InternalResourceViewResolver uses + the RequestDispatcher internally, and dispatching + is the only way to figure out if a JSP exists, but this action can only + execute once. The same holds for the + VelocityViewResolver and some others. Check the + Javadoc for the view resolver to see whether it reports non-existing + views. Thus, putting an InternalResourceViewResolver in the chain in a - place other than the last, will result in the chain not being fully - inspected, since the InternalResourceViewResolver - will always return a view! + place other than the last, results in the chain not being fully + inspected, because the + InternalResourceViewResolver will + always return a view!
- Redirecting to views + Redirecting to views<!--Revise to say what you are redirecting to views. OR are you redirecting views? In that case heading should be Redirecting views.--> - As has been mentioned, a controller normally returns a logical + As mentioned previously, a controller typically 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 - InternalResourceViewResolver / - InternalResourceView which will ultimately end up - issuing an internal forward or include, via the Servlet API's + technology. For view technologies such as JSPs that are processed + through the Servlet or JSP engine, this resolution is usually handled + through InternalResourceViewResolver / + InternalResourceView, which + issues an internal forward or include, through the Servlet API's RequestDispatcher.forward(..) or RequestDispatcher.include(). For other view - technologies, such as Velocity, XSLT, etc., the view itself produces the - content on the response stream. + technologies, such as Velocity, XSLT, and so on, the view itself + produces the content on the response stream. It is sometimes desirable to issue an HTTP redirect back to the client, before the view is rendered. This is desirable for example when @@ -1987,8 +1971,8 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { result of a POST, but rather of a GET, so there is no way the user can accidentally re-POST the same data by doing a refresh. The refresh - would just force a GET of the result page, not a - resend of the initial POST data. + forces a GET of the result page, not a resend of the + initial POST data.
<classname>RedirectView</classname> @@ -1996,23 +1980,25 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { 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 RedirectView. In this case, - DispatcherServlet 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. + DispatcherServlet does not use the normal view + resolution mechanism. Rather because it has been given the (redirect) + view already, the DispatcherServlet simply + instructs the view to do its work. - The RedirectView simply ends up issuing - an HttpServletResponse.sendRedirect() 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 + The RedirectView issues an + HttpServletResponse.sendRedirect() call, which + comes back to the client browser as an HTTP redirect. All + model attributes are 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 + convertible to Strings), which can be readily converted to a string-form HTTP query parameter. - If using RedirectView 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. + If you use RedirectView and the view is + created by the controller itself, it is recommended that you configure + 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. The + next section discusses this process.
@@ -2024,21 +2010,21 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { 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 + handled. In general it should operate only in terms of view names that have been injected into it. - The special redirect: prefix allows this to - be achieved. If a view name is returned which has the prefix + The special redirect: prefix allows you to + accomplish this. If a view name is returned that has the prefix redirect:, then UrlBasedViewResolver (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. + subclasses) recognize this as a special indication that a redirect is + needed. The rest of the view name will be treated as the redirect + URL. The net effect is the same as if the controller had returned a RedirectView, but now the controller itself can - deal just in terms of logical view names. A logical view name such as - redirect:/my/response/controller.html will redirect - relative to the current servlet context, while a name such as + simply operate in terms of logical view names. A logical view name + such as redirect:/my/response/controller.html will + redirect relative to the current servlet context, while a name such as redirect:http://myhost.com/some/arbitrary/path.html 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 @@ -2047,26 +2033,26 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter {
- The <literal>forward:</literal> prefix + The <literal>forward:</literal> prefix<!--Can you revise this heading to say what you're using the forward prefix to accomplish?--> It is also possible to use a special forward: - prefix for view names that will ultimately be resolved by + prefix for view names that are ultimately resolved by UrlBasedViewResolver and subclasses. All this does is create an InternalResourceView (which ultimately does a RequestDispatcher.forward()) around the rest of the view name, which is considered a URL. - Therefore, there is never any use in using this prefix when using + Therefore, this prefix is not useful with InternalResourceViewResolver / - InternalResourceView 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.) + InternalResourceView (for JSPs for example). + But the prefix can be helpful when you are primarily using another + view technology, but still want to force a forward of a resource to be + handled by the Servlet/JSP engine. (Note that you may also chain + multiple view resolvers, instead.) As with the redirect: 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. + controller does not detect that anything special is happening in terms + of handling the response.
@@ -2076,22 +2062,27 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { The ContentNegotiatingViewResolver 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. + client. Two strategies exist for a client to request a representation + from the server: - 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 + + + Use a distinct URI for each resource, + typically by using a different file extension in the URI. For + example, the URI http://www.example.com/users/fred.pdf requests a PDF - representation of the user fred while - http://www.example.com/users/fred.xml requests an XML - representation. + representation of the user fred, and + http://www.example.com/users/fred.xml requests an + XML representation. + + - The second strategy is for the client to use the same URI to - locate the resource but set the Accept HTTP request - header to list the media - types that it understands. For example, a HTTP request for + + + Use the same URI for the client to locate the resource, but + set the Accept HTTP request header to list the + media + types that it understands. For example, an HTTP request for http://www.example.com/users/fred with an Accept header set to application/pdf requests a PDF representation of the user fred while @@ -2100,11 +2091,13 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { requests an XML representation. This strategy is known as content negotiation. + + 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 + it in a web browser, in HTML. For example, in Firefox, it is fixed + to Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 @@ -2113,35 +2106,35 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { for each representation. - To support multiple representations of a resource Spring provides + To support multiple representations of a resource, Spring provides the ContentNegotiatingViewResolver to resolve a view based on the file extension or Accept header of the HTTP request. ContentNegotiatingViewResolver does not perform the view resolution itself, but instead delegates to a - list of view resolvers set using the bean property - ViewResolvers. + list of view resolvers that you specify through the bean property + ViewResolvers. The ContentNegotiatingViewResolver selects an appropriate View to handle the request by - comparing the request media type(s) with the media type (a.k.a. + comparing the request media type(s) with the media type (also known as Content-Type) supported by the View associated with each of its ViewResolvers. The first View in the list that has a compatible - Content-Type is used to return the representation to - the client. The Accept header may include wild cards, - for example 'text/*', in which case a View whose - Context-Type was 'text/xml' is a compatible match. + Content-Type returns the representation to the + client. The Accept header may include wildcards, for + example text/*, in which case a View whose + Context-Type was text/xml is a compatible match. - To support the resolution of a view based on a file extension, - ContentNegotiatingViewResolver's bean property - MediaTypes is used to specify a mapping of file + To support the resolution of a view based on a file extension, you + use the ContentNegotiatingViewResolver bean + property MediaTypes 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 - ContentNegotiatingViewResolver.. + ContentNegotiatingViewResolver. Here is an example configuration of a - ContentNegotiatingViewResolver + ContentNegotiatingViewResolver: <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"> <property name="mediaTypes"> @@ -2168,31 +2161,31 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { the translation of view names and JSP pages while the BeanNameViewResolver returns a view based on the name of a bean. (See "Resolving views - the ViewResolver - interface" for more details on how Spring looks up and - instantiates a view.) In this example, the content - bean is a class that inherits from - AbstractAtomFeedView which returns an Atom RSS - feed. For more information on creating an Atom Feed representation see - the section 'Atom Views'. + linkend="mvc-viewresolver-resolver">Resolving views with the + ViewResolver interface" for more details on how Spring looks up + and instantiates a view.) In this example, the + content bean is a class that inherits from + AbstractAtomFeedView, which returns an Atom RSS + feed. For more information on creating an Atom Feed representation, see + the section Atom Views. - 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 InternalResourceViewResolver 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 - BeanNameViewResolver that maps to the + In this configuration, if a request is made with an .html + extension, the view resolver looks for a view that matches the text/html + media type. The InternalResourceViewResolver + provides the matching view for text/html. If the request is made with + the file extension .atom, the view resolver looks for a view that + matches the application/atom+xml media type. This view is provided by + the BeanNameViewResolver that maps to the SampleContentAtomView 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. + is content. Alternatively, client requests can 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. If ContentNegotiatingViewResolver's list - of ViewResolvers is not configured explicitly, then it will - automatically use any ViewResolvers defined in the application - context. + of ViewResolvers is not configured explicitly, then it automatically + uses any ViewResolvers defined in the application context. The corresponding controller code that returns an Atom RSS feed @@ -2317,8 +2310,8 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { / - Using this parameter, you can limit the visibility of the - cookie to a certain part of your site. When cookiePath is + Limits 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. @@ -2332,19 +2325,24 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { The SessionLocaleResolver allows you to retrieve locales from the session that might be associated with the - user's request. + user's request.
<classname>LocaleChangeInterceptor</classname> - You can build in changing of locales using the - LocaleChangeInterceptor. This interceptor needs - to be added to one of the handler mappings (see ). It will detect a parameter in the - request and change the locale (it calls setLocale() - on the LocaleResolver that also exists in - the context). + You can build in changing of locales by adding the + LocaleChangeInterceptor to one of the handler + mappings (see ). It will detect a + parameter in the request and change the locale. It calls + setLocale() on the + LocaleResolver that also exists in the + context. The following example shows that calls to all + *.view resources containing a parameter named + siteLanguage will now change the locale. So, for + example, a request for the following URL, + http://www.sf.net/home.view?siteLanguage=nl will + change the site language to Dutch. <bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"> @@ -2365,12 +2363,6 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { <value>/**/*.view=someController</value> </property> </bean> - - All calls to all *.view resources containing a - parameter named siteLanguage will now change the - locale. So a request for the following URL, - http://www.sf.net/home.view?siteLanguage=nl will - change the site language to Dutch.
@@ -2378,47 +2370,45 @@ public class TimeBasedAccessInterceptor extends HandlerInterceptorAdapter { Using themes
- Introduction + Overview of themes - The theme 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 - themed. A theme is basically a collection of static - resources affecting the visual style of the application, typically style - sheets and images. + You can apply Spring Web MVC framework themes to set the overall look-and-feel + of your application, thereby enhancing user experience. A theme is a + collection of static resources, typically style sheets and images, that + affect the visual style of the application.
Defining themes - When you want to use themes in your web application you'll have to - set up a - org.springframework.ui.context.ThemeSource. - The WebApplicationContext interface - extends ThemeSource but delegates its + To use themes in your web application, you must set up an implementation of the + org.springframework.ui.context.ThemeSource interface. + The WebApplicationContext interface extends + ThemeSource but delegates its responsibilities to a dedicated implementation. By default the delegate - will be a + will be an org.springframework.ui.context.support.ResourceBundleThemeSource - that loads properties files from the root of the classpath. If you want - to use a custom ThemeSource - implementation or if you need to configure the basename prefix of the + implementation that loads properties files from the root of the + classpath. To use a custom ThemeSource + implementation or to configure the base name prefix of the ResourceBundleThemeSource, 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. + bean in the application context with the reserved name + themeSource. The web application context + automatically detects that bean and starts using it. When using the ResourceBundleThemeSource, a - theme is defined in a simple properties file. The properties file lists - the resources that make up the theme. Here is an example: + theme is defined in a simple properties file. The + properties file lists the resources that make up the theme. Here is an + example: styleSheet=/themes/cool/style.css background=/themes/cool/img/coolBg.jpg - 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 spring:theme custom tag, which is very - similar to the spring:message tag. The following JSP - fragment uses the theme defined above to customize the look and + The keys of the properties are the names that refer to the themed + elements from view code. For a JSP, you typically do this using the + spring:theme custom tag, which is very similar to the + spring:message tag. The following JSP fragment uses + the theme defined in the previous example to customize the look and feel: <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> @@ -2432,29 +2422,29 @@ background=/themes/cool/img/coolBg.jpg </html> By default, the ResourceBundleThemeSource - 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 + uses an empty base name prefix. As a result, the properties files are + loaded from the root of the classpath, so you would put the cool.properties theme definition in a directory at - the root of the classpath, e.g. in /WEB-INF/classes. - Note that the ResourceBundleThemeSource uses the - standard Java resource bundle loading mechanism, allowing for full - internationalization of themes. For instance, we could have a + the root of the classpath, for example, in + /WEB-INF/classes. The + ResourceBundleThemeSource uses the standard Java + resource bundle loading mechanism, allowing for full + internationalization of themes. For example, we could have a /WEB-INF/classes/cool_nl.properties that references a - special background image, e.g. with Dutch text on it. + special background image with Dutch text on it.
Theme resolvers - Now that we have our themes defined, the only thing left to do is - decide which theme to use. The DispatcherServlet - will look for a bean named "themeResolver" to find out which - ThemeResolver implementation to use. A - theme resolver works in much the same way as a - LocaleResolver. 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: + After you define themes, as in the preceding section, you decide + which theme to use. The DispatcherServlet will + look for a bean named themeResolver to find out + which ThemeResolver implementation to + use. A theme resolver works in much the same way as a + LocaleResolver. It detects the theme to + use for a particular request and can also alter the request's theme. The + following theme resolvers are provided by Spring: <interfacename>ThemeResolver</interfacename> @@ -2477,14 +2467,14 @@ background=/themes/cool/img/coolBg.jpg</programlisting> <row> <entry><classname>FixedThemeResolver</classname></entry> - <entry>Selects a fixed theme, set using the "defaultThemeName" - property.</entry> + <entry>Selects a fixed theme, set using the + <classname>defaultThemeName</classname> property.</entry> </row> <row> <entry><classname>SessionThemeResolver</classname></entry> - <entry>The theme is maintained in the users HTTP session. It + <entry>The theme is maintained in the user's HTTP session. It only needs to be set once for each session, but is not persisted between sessions.</entry> </row> @@ -2500,8 +2490,8 @@ background=/themes/cool/img/coolBg.jpg</programlisting> </table> <para>Spring also provides a - <classname>ThemeChangeInterceptor</classname>, which allows changing the - theme on every request by including a simple request parameter.</para> + <classname>ThemeChangeInterceptor</classname>, which allows theme + changes on every request with a simple request parameter.<!--Do you need more info or an example re preceding sentence?--></para> </section> </section> @@ -2511,27 +2501,26 @@ background=/themes/cool/img/coolBg.jpg</programlisting> <section id="mvc-multipart-introduction"> <title>Introduction - Spring has built-in multipart support to handle fileuploads in web - applications. The design for the multipart support is done with - pluggable MultipartResolver objects, - defined in the org.springframework.web.multipart - package. Out of the box, Spring provides a + Spring's built-in multipart support handles file uploads in web + applications. You enable this multipart support with pluggable + MultipartResolver objects, defined in the + org.springframework.web.multipart package. Out + of the box, Spring provides a MultipartResolver for use with Commons FileUpload (). How + url="http://jakarta.apache.org/commons/fileupload">). How uploading files is supported will be described in the rest of this chapter. - 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 MultipartResolver 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. + By default, Spring does no multipart handling, because some + developers want to handle multiparts themselves. You enable Spring + multipart handling by adding a multipart resolver to the web + application's context. Each request is inspected to see if it contains a + multipart. If no multipart is found, the request continues as expected. + If a multipart is found in the request, the + MultipartResolver that has been declared in your + context is used. After that, the multipart attribute in your request is + treated like any other attribute.
@@ -2548,7 +2537,7 @@ background=/themes/cool/img/coolBg.jpg <property name="maxUploadSize" value="100000"/> </bean> - This is an example using the + This example uses the CosMultipartResolver: <bean id="multipartResolver" class="org.springframework.web.multipart.cos.CosMultipartResolver"> @@ -2564,13 +2553,11 @@ background=/themes/cool/img/coolBg.jpg CosMultipartResolver, use cos.jar. - 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 - DispatcherServlet 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 - HttpServletRequest into a - MultipartHttpServletRequest that has support for + When the Spring DispatcherServlet detects a + multi-part request, it activates the resolver that has been declared in + your context and hands over the request. The resolver then wraps the + current HttpServletRequest into a + MultipartHttpServletRequest that supports multipart file uploads. Using the MultipartHttpServletRequest you can get information about the multiparts contained by this request and actually @@ -2580,11 +2567,11 @@ background=/themes/cool/img/coolBg.jpg
Handling a file upload in a form - After the MultipartResolver 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: + After the MultipartResolver completes its + job, the request is processed like any other. To use it, + you create a form with an upload field (see immediately below) that will + allow the user to upload a form, then let Spring bind the file onto your + form (backing object). <html> <head> @@ -2600,26 +2587,23 @@ background=/themes/cool/img/coolBg.jpg </html> As you can see, we've created a field named after the property of - the bean that holds the byte[]. Furthermore we've - added the encoding attribute - (enctype="multipart/form-data") which is necessary to - let the browser know how to encode the multipart fields (do not forget - this!). + the bean that holds the byte[]. The + encoding attribute (enctype="multipart/form-data") + lets the browser know how to encode the multipart fields. - 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 - ServletRequestDatabinder. There are a couple of - editors available for handling files and setting the results on an - object. There's a StringMultipartEditor capable - of converting files to Strings (using a user-defined character set) and - there is a ByteArrayMultipartEditor which - converts files to byte arrays. They function just as the + As with any property that is not automatically convertible + to a string or primitive type, you must register a custom editor with + the ServletRequestDatabinder to be able to put + binary data in your objects. Two editors can handle files and set the + results on an object. A StringMultipartEditor can + convert files to Strings (using a user-defined character set), and a + ByteArrayMultipartEditor converts files to byte + arrays. They function just as the CustomDateEditor does. - So, to be able to upload files using a (HTML) form, declare the + So, to be able to upload files using an HTML form, declare the resolver, a url mapping to a controller that will process the bean, and - the controller itself. + the controller itself: <beans> <!-- lets use the Commons-based implementation of the MultipartResolver interface --> @@ -2643,7 +2627,7 @@ background=/themes/cool/img/coolBg.jpg </beans> After that, create the controller and the actual class to hold the - file property. + file property: public class FileUploadController extends SimpleFormController { @@ -2687,15 +2671,14 @@ public class FileUploadBean { As you can see, the FileUploadBean has a property typed byte[] 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 + controller registers a custom editor to let Spring know how to convert + the multipart objects the resolver has found to properties specified by + the bean. In this example, nothing is done with the byte[] property of the bean itself, but in practice - you can do whatever you want (save it in a database, mail it to - somebody, etc). + you can do save it in a database, mail it to somebody, and so on. - An equivalent example in which a file is bound straight to a - String-typed property on a (form backing) object might look like: + The following is an equivalent example in which a file is bound + straight to a String-typed property on a (form backing) object: public class FileUploadController extends SimpleFormController { @@ -2738,9 +2721,9 @@ public class FileUploadBean { } } - 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). + The preceding example only makes (logical) sense in the context of + uploading a plain text file. It would not work as well with an image + file upload. The third (and final) option is where one binds directly to a MultipartFile property declared on the @@ -2785,40 +2768,46 @@ public class FileUploadBean {
Handling exceptions - Spring provides HandlerExceptionResolvers to ease - the pain of unexpected exceptions occurring while your request is being - handled by a controller which matched the request. +
+ <interfacename>HandlerExceptionResolver<!--I thought HandlerExceptionResolver needed its own section.--></interfacename> + + Spring HandlerExceptionResolvers ease the pain + of unexpected exceptions that occur while your request is handled by a + controller that matched the request. HandlerExceptionResolvers somewhat resemble the exception mappings you can define in the web application descriptor web.xml. However, they provide a more flexible way to - handle exceptions. They provide information about what handler was + handle exceptions. They provide information about which 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). + of handling exception gives you more options for responding + appropriately before the request is forwarded to another URL (the same + end result as when you use the servlet specific exception + mappings). Besides implementing the HandlerExceptionResolver interface, which - is only a matter of implementing the resolveException(Exception, - Handler) method and returning a - ModelAndView, you may also use the + is only a matter of implementing the + resolveException(Exception, Handler) method and + returning a ModelAndView, you may also use the SimpleMappingExceptionResolver. 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 + exception mapping feature from the Servlet API, but it is also possible + to implement more finely grained mappings of exceptions from different handlers. +
- <interfacename>@ExceptionResolver</interfacename> + <interfacename>@ExceptionHandler<!--Changed this from @ExceptionResolver because text and example say @ExceptionHandler.--></interfacename> - As an alternative to implementing the - HandlerExceptionResolver, you can use the - @ExceptionHandler. The - @ExceptionHandler 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 + An alternative to the + HandlerExceptionResolver interface is the + @ExceptionHandler annotation. You use the + @ExceptionHandler method annotation within a + controller to specify which method is invoked when an exception of a + specific type is thrown during the execution of controller methods. For + example: @Controller public class SimpleController { @@ -2849,13 +2838,13 @@ public class SimpleController { environments and the PortletRequest in Portlet environments. The return type can be a String, which is interpreted as a view name or a - ModelAndView object. Please refer to the API + ModelAndView object. Refer to the API documentation for more details.
- Convention over configuration + Convention over configuration support For a lot of projects, sticking to established conventions and having reasonable defaults is just what they (the projects) need... this @@ -2868,11 +2857,11 @@ public class SimpleController { lend a degree of (always good-to-have) consistency across a codebase should you choose to move forward with it into production. - This convention over configuration support address the three core - areas of MVC - namely, the models, views, and controllers. + Convention-over-configuration support addresses the three core areas + of MVC -- models, views, and controllers.
- The Controller - + <title>The Controller <classname>ControllerClassNameHandlerMapping</classname> The ControllerClassNameHandlerMapping class @@ -2881,9 +2870,9 @@ public class SimpleController { Controller instances that are to handle those requests. - An example; consider the following (simplistic) - Controller implementation. Take especial - notice of the name of the class. + Consider the following simple + Controller implementation. Take special + notice of the name of the class. public class ViewShoppingCartController implements Controller { @@ -2904,81 +2893,75 @@ public class SimpleController { The ControllerClassNameHandlerMapping finds all of the various handler (or Controller) beans defined in its - application context and strips 'Controller' off the - name to define its handler mappings. + application context and strips Controller off the + name to define its handler mappings. Thus, + ViewShoppingCartController maps to the + /viewshoppingcart* request URL. Let's look at some more examples so that the central idea becomes - immediately familiar. + immediately familiar. (Notice all lowercase in the URLs, in contrast to + camel-cased Controller class + names.) WelcomeController maps to the - '/welcome*' request URL + /welcome* request URL HomeController maps to the - '/home*' request URL + /home* request URL IndexController maps to the - '/index*' request URL + /index* request URL RegisterController maps to the - '/register*' request URL - - - - DisplayShoppingCartController maps to - the '/displayshoppingcart*' request URL - - (Notice the casing - all lowercase - in the case of - camel-cased Controller class - names.) + /register* request URL In the case of MultiActionController - handler classes, the mappings generated are (ever so slightly) more - complex, but hopefully no less understandable. Some examples (all of the - Controller names in this next bit are - assumed to be MultiActionController - implementations). + handler classes, the mappings generated are slightly more complex. The + Controller names in the following + examples are assumed to be MultiActionController + implementations: AdminController maps to the - '/admin/*' - request URL + /admin/* request + URL CatalogController maps to the - '/catalog/*' + /catalog/* request URL - If you follow the pretty standard convention of naming your + If you follow the convention of naming your Controller implementations as - xxxController, then - the ControllerClassNameHandlerMapping will save - you the tedium of having to firstly define and then having to maintain a - potentially looooong + xxxController, the + ControllerClassNameHandlerMapping saves you the + tedium of defining and maintaining a potentially + looooong SimpleUrlHandlerMapping (or suchlike). The ControllerClassNameHandlerMapping class extends the AbstractHandlerMapping base class so you can define HandlerInterceptor - instances and everything else just like you would with many other + instances and everything else just as you would with many other HandlerMapping implementations.
- The Model - <classname>ModelMap</classname> + <title>The Model <classname>ModelMap</classname> (<classname>ModelAndView</classname>) The ModelMap class is essentially a @@ -2988,7 +2971,7 @@ public class SimpleController { convention. Consider the following Controller implementation; notice that objects are added to the ModelAndView without any - associated name being specified. + associated name specified. public class DisplayShoppingCartController implements Controller { @@ -3012,52 +2995,52 @@ public class SimpleController { 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 User, 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 + class name of the object's class. The following examples are names that + are generated for scalar objects put into a ModelMap instance. An x.y.User instance added will have - the name 'user' generated + the name user generated. An x.y.Registration instance added will - have the name 'registration' generated + have the name registration generated. An x.y.Foo instance added will have the - name 'foo' generated + name foo generated. A java.util.HashMap instance added will - have the name 'hashMap' generated (you'll - probably want to be explicit about the name in this case because - 'hashMap' is less than intuitive). + have the name hashMap generated. You probably + want to be explicit about the name in this case because + hashMap is less than intuitive. Adding null will result in an IllegalArgumentException being thrown. If the - object (or objects) that you are adding could potentially be + object (or objects) that you are adding could be null, then you will also want to be explicit - about the name). + about the name. What, no automatic pluralisation? - Spring Web MVC's convention over configuration support does not - support automatic pluralisation. That is to say, you cannot add a + Spring Web MVC's convention-over-configuration support does not + support automatic pluralisation. That is, you cannot add a List of Person objects to a ModelAndView and have the - generated name be 'people'. + generated name be people. - This decision was taken after some debate, with the + This decision was made after some debate, with the Principle of Least Surprise winning out in the end. @@ -3066,38 +3049,38 @@ public class SimpleController { Set, List 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 - 'List' appended to the name. Some examples will make + List appended to the name. Some examples will make the semantics of name generation for collections clearer... An x.y.User[] array with one or more x.y.User elements added will have the name - 'userList' generated + userList generated. An x.y.Foo[] array with one or more x.y.User elements added will have the name - 'fooList' generated + fooList generated. A java.util.ArrayList with one or more x.y.User elements added will have the name - 'userList' generated + userList generated. A java.util.HashSet with one or more x.y.Foo elements added will have the name - 'fooList' generated + fooList generated. An empty java.util.ArrayList will not be added at all - (i.e. the addObject(..) call will + (in effect, the addObject(..) call will essentially be a no-op). @@ -3108,15 +3091,13 @@ public class SimpleController { RequestToViewNameTranslator The RequestToViewNameTranslator - interface is responsible for determining a logical - View name when no such logical view name - is explicitly supplied. It has just one implementation, the rather - cunningly named + interface determines a logical View name + when no such logical view name is explicitly supplied. It has just one + implementation, the DefaultRequestToViewNameTranslator class. The DefaultRequestToViewNameTranslator maps - request URLs to logical view names in a fashion that is probably best - explained by recourse to an example. + request URLs to logical view names, as with this example: public class RegistrationController implements Controller { @@ -3155,35 +3136,34 @@ public class SimpleController { Notice how in the implementation of the handleRequest(..) method no View or logical view name is ever set on - the ModelAndView that is returned. It is the - DefaultRequestToViewNameTranslator that will be - tasked with generating a logical view name from the - URL of the request. In the case of the above - RegistrationController, which is being used in + the ModelAndView that is returned. The + DefaultRequestToViewNameTranslator is tasked with + generating a logical view name from the URL of the + request. In the case of the above + RegistrationController, which is used in conjunction with the ControllerClassNameHandlerMapping, a request URL - of 'http://localhost/registration.html' will result - in a logical view name of 'registration' being - generated by the - DefaultRequestToViewNameTranslator. This logical - view name will then be resolved into the - '/WEB-INF/jsp/registration.jsp' view by the + of http://localhost/registration.html results in a + logical view name of registration being generated by + the DefaultRequestToViewNameTranslator. This + logical view name is then resolved into the + /WEB-INF/jsp/registration.jsp view by the InternalResourceViewResolver bean. - You don't even need to define a + You do not need to define a DefaultRequestToViewNameTranslator bean - explicitly. If you are okay with the default settings of the - DefaultRequestToViewNameTranslator, then you - can rely on the fact that the Spring Web MVC - DispatcherServlet will actually instantiate an - instance of this class if one is not explicitly configured. + explicitly. If you like the default settings of the + DefaultRequestToViewNameTranslator, you can + rely on the Spring Web MVC DispatcherServlet to + instantiate an instance of this class if one is not explicitly + configured. Of course, if you need to change the default settings, then you do need to configure your own DefaultRequestToViewNameTranslator bean - explicitly. Please do consult the quite comprehensive Javadoc for the + explicitly. Consult the comprehensive Javadoc for the DefaultRequestToViewNameTranslator class for details of the various properties that can be configured.
@@ -3199,24 +3179,23 @@ public class SimpleController { Last-Modified header. When a server returns a representation with an ETag header, the client can use this header in subsequent GETs, in an If-None-Match header. If the - content has not changed, the server will return 304: Not + content has not changed, the server returns 304: Not Modified. Support for ETags is provided by the servlet filter - ShallowEtagHeaderFilter. Since it is a plain - Servlet Filter, and thus can be used in combination with any web - framework. The ShallowEtagHeaderFilter filter - creates so-called shallow ETags (as opposed to deep ETags, more about that - later). The way it works is quite simple: the filter simply caches the - content of the rendered JSP (or other content), generates an MD5 hash over - that, and returns that as an ETag header in the response. The next time a - client sends a request for the same resource, it uses that hash as the - If-None-Match value. The filter notices this, renders - the view again, and compares the two hashes. If they are equal, a - 304 is returned. It is important to note that this - filter will not save processing power, as the view is still rendered. The - only thing it saves is bandwidth, as the rendered response is not sent - back over the wire. + ShallowEtagHeaderFilter. It is a plain Servlet + Filter, and thus can be used in combination with any web framework. The + ShallowEtagHeaderFilter filter creates so-called + shallow ETags (as opposed to deep ETags, more about that later).The + filter caches the content of the rendered JSP (or other content), + generates an MD5 hash over that, and returns that as an ETag header in the + response. The next time a client sends a request for the same resource, it + uses that hash as the If-None-Match value. The filter + detects this, renders the view again, and compares the two hashes. If they + are equal, a 304 is returned. This filter will not save + processing power, as the view is still rendered. The only thing it saves + is bandwidth, as the rendered response is not sent back over the + wire. You configure the ShallowEtagHeaderFilter in web.xml: @@ -3233,26 +3212,26 @@ public class SimpleController {
- Further Resources + More Spring Web MVC Resources - Find below links and pointers to further resources about Spring Web - MVC. + See the following links and pointers for more resources about Spring + Web MVC: 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 'docs' directory of the Spring + available in the docs directory of the Spring distribution. An online version can also be found on the Spring Framework website. - The book entitled Expert Spring Web MVC and Web - Flow by Seth Ladd and others (published by Apress) is an - excellent hardcopy source of Spring Web MVC goodness. + Expert Spring Web MVC and Web Flow by Seth Ladd + and others (published by Apress) is an excellent hard copy source of + Spring Web MVC goodness.