Document MVC Java config side-by-side with the MVC namespace.

This commit is contained in:
Rossen Stoyanchev 2011-11-22 23:25:12 +00:00
parent b2ae3dbb47
commit 6eba6f2059
2 changed files with 589 additions and 259 deletions

View File

@ -26,7 +26,7 @@ Changes in version 3.1 RC2 (2011-11-15)
* support UriComponentsBuilder as @Controller method argument * support UriComponentsBuilder as @Controller method argument
* MockHttpServletRequest and MockHttpServletResponse now keep contentType field and Content-Type header in sync * MockHttpServletRequest and MockHttpServletResponse now keep contentType field and Content-Type header in sync
* fixed issue with cache ignoring prototype-scoped controllers in RequestMappingHandlerAdapter * fixed issue with cache ignoring prototype-scoped controllers in RequestMappingHandlerAdapter
* update Spring MVC configuration section to include MVC Java config and the MVC namespace
Changes in version 3.1 RC1 (2011-10-11) Changes in version 3.1 RC1 (2011-10-11)
--------------------------------------- ---------------------------------------

View File

@ -248,7 +248,7 @@
the <literal>web.xml</literal> of your web application. You need to map the <literal>web.xml</literal> of your web application. You need to map
requests that you want the <classname>DispatcherServlet</classname> to requests that you want the <classname>DispatcherServlet</classname> to
handle, by using a URL mapping in the same <literal>web.xml</literal> handle, by using a URL mapping in the same <literal>web.xml</literal>
file. This is standard J2EE Servlet configuration; the following example file. This is standard Java EE Servlet configuration; the following example
shows such a <classname>DispatcherServlet</classname> declaration and shows such a <classname>DispatcherServlet</classname> declaration and
mapping:</para> mapping:</para>
@ -301,8 +301,7 @@
</mediaobject></para> </mediaobject></para>
<para>Upon initialization of a <classname>DispatcherServlet</classname>, <para>Upon initialization of a <classname>DispatcherServlet</classname>,
the framework <!--Spring MVC or Spring Framework?--><emphasis><emphasis>looks Spring MVC looks for a file named <emphasis>
for a file named</emphasis>
<literal>[servlet-name]-servlet.xml</literal></emphasis> in the <literal>[servlet-name]-servlet.xml</literal></emphasis> in the
<literal>WEB-INF</literal> directory of your web application and creates <literal>WEB-INF</literal> directory of your web application and creates
the beans defined there, overriding the definitions of any beans defined the beans defined there, overriding the definitions of any beans defined
@ -349,16 +348,22 @@
look up the <interfacename>WebApplicationContext</interfacename> if you look up the <interfacename>WebApplicationContext</interfacename> if you
need access to it.</para> need access to it.</para>
<section id="mvc-servlet-special-bean-types">
<title>Special Bean Types In the <interfacename>WebApplicationContext</interfacename></title>
<para>The Spring <classname>DispatcherServlet</classname> uses special <para>The Spring <classname>DispatcherServlet</classname> uses special
beans to process requests and render the appropriate views. These beans beans to process requests and render the appropriate views. These beans
are part of Spring Framework. You can configure them in the are part of Spring MVC. You can choose which special beans to use
<interfacename>WebApplicationContext</interfacename>, just as you by simply configuring one or more of them in the
configure any other bean. However, for most beans, sensible defaults are <interfacename>WebApplicationContext</interfacename>.
provided so you initially do not need to configure them. <!--Which beans have defaults? What do you mean you *initially* don't need to configure them? What determines whether you need to and --><!--when, if not *initially*? In table below, indicate which are defaults, which have to be configured.-->These However, you don't need to do that initially since Spring MVC
beans are described in the following table.</para> maintains a list of default beans to use if you don't configure any.
More on that in the next section. First see the table below
listing the special bean types the
<classname>DispatcherServlet</classname> relies on.</para>
<table id="mvc-webappctx-special-beans-tbl"> <table id="mvc-webappctx-special-beans-tbl">
<title>Special beans in the <title>Special bean types in the
<interfacename>WebApplicationContext</interfacename></title> <interfacename>WebApplicationContext</interfacename></title>
<tgroup cols="2"> <tgroup cols="2">
@ -376,63 +381,119 @@
<tbody> <tbody>
<row> <row>
<entry><link linkend="mvc-controller">controllers</link></entry> <entry><link linkend="mvc-handlermapping">HandlerMapping</link></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> <entry>Maps incoming requests to handlers and a list of
pre- and post-processors (handler interceptors) based on some
criteria the details of which vary by <interfacename>HandlerMapping</interfacename>
implementation. The most popular implementation supports
annotated controllers but other implementations exists as well.</entry>
</row> </row>
<row> <row>
<entry><link linkend="mvc-handlermapping">handler <entry>HandlerAdapter</entry>
mappings</link></entry>
<entry>Handle the execution of a list of pre-processors and <entry>Helps the <interfacename>DispatcherServlet</interfacename> to
post-processors and controllers that will be executed if they invoke a handler mapped to a request regardless of the handler
match certain criteria (for example, a matching URL specified with is actually invoked. For example, invoking an annotated controller
the controller).</entry> requires resolving various annotations. Thus the main purpose
of a <interfacename>HandlerAdapter</interfacename> is to shield the
<classname>DispatcherServlet</classname> from such details.</entry>
</row> </row>
<row> <row>
<entry><link linkend="mvc-viewresolver">view <entry><link linkend="mvc-exceptionhandlers">HandlerExceptionResolver</link></entry>
resolvers</link></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> <entry>Maps exceptions to views also allowing for more
complex exception handling code.</entry>
</row> </row>
<row> <row>
<entry><link linkend="mvc-localeresolver">locale <entry><link linkend="mvc-viewresolver">ViewResolver</link></entry>
resolver</link></entry>
<entry>A <link linkend="mvc-localeresolver">locale resolver</link> <entry>Resolves logical String-based view names to actual
is a component capable of resolving the locale a client is using, <interface>View</interface> types.</entry>
</row>
<row>
<entry><link linkend="mvc-localeresolver">LocaleResolver</link></entry>
<entry>Resolves the locale a client is using,
in order to be able to offer internationalized views</entry> in order to be able to offer internationalized views</entry>
</row> </row>
<row> <row>
<entry>Theme resolver</entry> <entry><link linkend="mvc-themeresolver">ThemeResolver</link></entry>
<entry>A <link linkend="mvc-themeresolver">theme resolver</link> <entry>Resolves themes your web application can use, for
is capable of resolving themes your web application can use, for
example, to offer personalized layouts</entry> example, to offer personalized layouts</entry>
</row> </row>
<row> <row>
<entry>multipart file resolver</entry> <entry><link linkend="mvc-multipart">MultipartResolver</link></entry>
<entry>Contains functionality to process file uploads from HTML <entry>Parses multi-part requests for example to support processing
forms.<!--Here and next one, why not just say processes file uploads, maps executions instead of *contains functionality to*?--></entry> file uploads from HTML forms.</entry>
</row> </row>
<row> <row>
<entry><link linkend="mvc-exceptionhandlers">handler exception <entry><link linkend="mvc-flash-attributes">FlashMapManager</link></entry>
resolvers</link></entry>
<entry>Contains functionality to map exceptions to views or <entry>Stores and retrieves the "input" and the "output"
implement other more complex exception handling code.</entry> <classname>FlashMap</classname> that can be used to pass attributes
from one request to another, usually across a redirect.</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
</table> </table>
</section>
<section id="mvc-servlet-config">
<title>Default DispatcherServlet Configuration</title>
<para>As mentioned in the previous section for each special bean
the <classname>DispatcherServlet</classname> maintains a list
of implementations to use by default. This information is
kept in the file <filename>DispatcherServlet.properties</filename>
in the package <classname>org.springframework.web.servlet</classname>.
</para>
<para>All special beans have some reasonable defaults of
their own. Sooner or later though you'll need to customize
one or more of the properties these beans provide.
For example it's quite common to configure
an <classname>InternalResourceViewResolver</classname>
settings its <literal>prefix</literal> property to
the parent location of view files.</para>
<para>Regardless of the details, the important concept
to understand here is that once
you configure a special bean such as an
<classname>InternalResourceViewResolver</classname>
in your <classname>WebApplicationContext</classname>, you
effectively override the list of default implementations
that would have been used otherwise for that special bean
type. For example if you configure an
<classname>InternalResourceViewResolver</classname>,
the default list of <interfacename>ViewResolver</interfacename>
implementations is ignored.
</para>
<para>In <xref linkend="mvc-config"/> you'll learn about
other options for configuring Spring MVC including
MVC Java config and the MVC XML namespace both of which provide
a simple starting point and assume little knowledge of
how Spring MVC works. Regardless of how you choose to
configure your application, the concepts explained in this
section are fundamental should be of help to you.
</para>
</section>
<section id="mvc-servlet-sequence">
<title>DispatcherServlet Processing Sequence</title>
<para>After you set up a <classname>DispatcherServlet</classname>, and a <para>After you set up a <classname>DispatcherServlet</classname>, and a
request comes in for that specific request comes in for that specific
<classname>DispatcherServlet</classname>, the <classname>DispatcherServlet</classname>, the
@ -499,6 +560,8 @@
resolvers allows you to define custom behaviors to address resolvers allows you to define custom behaviors to address
exceptions.</para> exceptions.</para>
</section>
<para>The Spring <classname>DispatcherServlet</classname> also supports <para>The Spring <classname>DispatcherServlet</classname> also supports
the return of the <emphasis>last-modification-date</emphasis>, as the return of the <emphasis>last-modification-date</emphasis>, as
specified by the Servlet API. The process of determining the last specified by the Servlet API. The process of determining the last
@ -1062,7 +1125,7 @@ public class RelativePathUriTemplateController {
<note> <note>
<para>Session access may not be thread-safe, in particular in <para>Session access may not be thread-safe, in particular in
a Servlet environment. Consider setting the a Servlet environment. Consider setting the
<classname>AnnotationMethodHandlerAdapter</classname>'s <classname>RequestMappingHandlerAdapter</classname>'s
"synchronizeOnSession" flag to "true" if multiple requests are "synchronizeOnSession" flag to "true" if multiple requests are
allowed to access a session concurrently.</para> allowed to access a session concurrently.</para>
</note> </note>
@ -3973,45 +4036,90 @@ public class SimpleController {
<section id="mvc-config"> <section id="mvc-config">
<title>Configuring Spring MVC</title> <title>Configuring Spring MVC</title>
<para>Spring 3 introduces a <literal>mvc</literal> XML configuration <para><xref linkend="mvc-servlet-special-bean-types"/> and
namespace that simplifies the setup of Spring MVC inside your web <xref linkend="mvc-servlet-config"/> explained about
application. Instead of registering low-level beans such as Spring MVC's special beans and the default implementations
AnnotationMethodHandlerAdapter, you can simply use the namespace and its used by the <classname>DispatcherServlet</classname>.
higher-level constructs. This is generally preferred unless you require In this section you'll learn about two additional ways of
finer-grained control of the configuration at the bean level.</para> configuring Spring MVC. Namely the MVC Java config and
the MVC XML namespace.
</para>
<para>The mvc namespace consists of three tags: mvc:annotation-driven, <para>The MVC Java config and the MVC namespace provide
mvc:interceptors, and mvc:view-controller. Each of these tags is similar default configuration that overrides
documented below and in the <ulink the <classname>DispatcherServlet</classname> defaults.
url="http://static.springsource.org/schema/mvc/spring-mvc-3.0.xsd">XML The goal is to spare most applications from having to
schema</ulink>.</para> having to create the same configuration and also to
provide higher-level constructs for configuring
Spring MVC that serve as a simple starting point and
require little or no prior knowledge of the underlying
configuration.</para>
<section id="mvc-annotation-driven"> <para>You can choose either the MVC Java config or the
<title>mvc:annotation-driven</title> MVC namespace depending on your preference. Also as you
will see further below, with the MVC Java config it is
easier to see the underlying configuration as well as
to make fine-grained customizations directly to the
created Spring MVC beans.
But let's start from the beginning.
</para>
<para>This tag registers the RequestMappingHandlerMapping and <section id="mvc-config-enable">
RequestMappingHandlerAdapter beans that are required for Spring MVC to <title>Enabling MVC Java Config or the MVC XML Namespace</title>
dispatch requests to @Controllers. The tag configures those two beans
with sensible defaults based on what is present in your classpath. The <para>To enable MVC Java config add the annotation
defaults are: <orderedlist> <interfacename>@EnableWebMvc</interfacename> to one of your
<interfacename>@Configuration</interfacename> classes:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig {
}</programlisting>
<para>To achieve the same in XML use the <literal>mvc:annotation-driven</literal> element:</para>
<programlisting language="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd"&gt;
&lt;mvc:annotation-driven /&gt;
&lt;beans&gt;</programlisting>
<para>The above registers a
<classname>RequestMappingHandlerMapping</classname>, a
<classname>RequestMappingHandlerAdapter</classname>, and an
<classname>ExceptionHandlerExceptionResolver</classname> (among others)
in support of processing requests with annotated controller methods using
annotations such as <interfacename>@RequestMapping </interfacename>,
<interfacename>@ExceptionHandler</interfacename>, and others.</para>
<para>It also enables the following:
<orderedlist>
<listitem> <listitem>
<para>Support for Spring 3's Type <link <para>Spring 3 style type conversion through a <link
linkend="core-convert">ConversionService</link> in addition to linkend="core-convert">ConversionService</link> instance
JavaBeans PropertyEditors during Data Binding. A ConversionService in addition to the JavaBeans PropertyEditors used for Data Binding.</para>
instance produced by the
<classname>org.springframework.format.support.FormattingConversionServiceFactoryBean</classname>
is used by default. This can be overridden by setting the
<literal>conversion-service</literal> attribute.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Support for <link linkend="format">formatting</link> Number <para>Support for <link linkend="format">formatting</link> Number
fields using the @NumberFormat annotation</para> fields using the <interfacename>@NumberFormat</interfacename>
annotation through the
<interfacename>ConversionService</interfacename>.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>Support for <link linkend="format">formatting</link> Date, <para>Support for <link linkend="format">formatting</link> Date,
Calendar, Long, and Joda Time fields using the @DateTimeFormat Calendar, Long, and Joda Time fields using the
<interfacename>@DateTimeFormat</interfacename>
annotation, if Joda Time 1.3 or higher is present on the annotation, if Joda Time 1.3 or higher is present on the
classpath.</para> classpath.</para>
</listitem> </listitem>
@ -4019,14 +4127,17 @@ public class SimpleController {
<listitem> <listitem>
<para>Support for <link <para>Support for <link
linkend="validation-mvc-jsr303">validating</link> @Controller linkend="validation-mvc-jsr303">validating</link> @Controller
inputs with @Valid, if a JSR-303 Provider is present on the inputs with <interfacename>@Valid</interfacename>,
classpath. The validation system can be explicitly configured by if a JSR-303 Provider is present on the classpath.</para>
setting the <literal>validator</literal> attribute.</para>
</listitem> </listitem>
<listitem> <listitem>
<para>HttpMessageConverter support for @RequestBody method <para>HttpMessageConverter support for
parameters and @ResponseBody method return values.</para> <interfacename>@RequestBody</interfacename> method
parameters and <interfacename>@ResponseBody</interfacename>
method return values from
<interfacename>@RequestMapping</interfacename> or
<interfacename>@ExceptionHandler</interfacename> methods.</para>
<para>This is the complete list of HttpMessageConverters set up by <para>This is the complete list of HttpMessageConverters set up by
mvc:annotation-driven: <itemizedlist> mvc:annotation-driven: <itemizedlist>
@ -4085,76 +4196,130 @@ public class SimpleController {
</listitem> </listitem>
</itemizedlist></para> </itemizedlist></para>
<note>
<para>You can provide your own HttpMessageConverters through the
mvc:message-converters sub-element of mvc:annotation-driven.
Message converters you provide will take precedence over the
ones registered by default.</para>
</note>
</listitem> </listitem>
</orderedlist> A typical usage is shown below: <programlisting </orderedlist>
language="xml"> </para>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"&gt;
&lt;!-- JSR-303 support will be detected on classpath and enabled automatically --&gt;
&lt;mvc:annotation-driven/&gt;
&lt;/beans&gt;</programlisting></para>
</section> </section>
<section id="mvc-interceptors"> <section id="mvc-config-customize">
<title>mvc:interceptors</title> <title>Customizing the Provided Configuration</title>
<para>This tag allows you to register custom HandlerInterceptors or <para>To customize the default configuration in Java you simply
WebRequestInterceptors that should be applied to all HandlerMapping implement the <interfacename>WebMvcConfigurer</interfacename>
beans. You can also restrict the URL paths that specific interceptors interface or more likely extend the class
apply to.</para> <classname>WebMvcConfigurerAdapter</classname> and override
the methods you need. Below is an example of some of the available
methods to override. See <interfacename>WebMvcConifgurer</interfacename> for
a list of all methods and the Javadoc for further details:</para>
<para>An example of registering an interceptor applied to all URL <programlisting language="java">@EnableWebMvc
paths:</para> @Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
protected void addFormatters(FormatterRegistry registry) {
// Add formatters and/or converters
}
@Override
public void configureMessageConverters(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters) {
// Configure the list of HttpMessageConverters to use
}
}</programlisting>
<para>To customize the default configuration of
<literal>&lt;mvc:annotation-driven /&gt;</literal> check what
attributes and sub-elements it supports. You can view the
<ulink url="http://static.springsource.org/schema/mvc/spring-mvc-3.1.xsd">Spring MVC XML schema</ulink>
or use the code completion feature of your IDE to discover
what attributes and sub-elements are available.
The sample below shows a subset of what is available:</para>
<programlisting language="xml">&lt;mvc:annotation-driven conversion-service="conversionService"&gt;
&lt;mvc:message-converters&gt;
&lt;bean class="org.example.MyHttpMessageConverter"/&gt;
&lt;bean class="org.example.MyOtherHttpMessageConverter"/&gt;
&lt;/mvc:message-converters&gt;
&lt;/mvc:annotation-driven&gt;
&lt;bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"&gt;
&lt;property name="formatters"&gt;
&lt;list&gt;
&lt;bean class="org.example.MyFormatter"/&gt;
&lt;bean class="org.example.MyOtherFormatter"/&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;</programlisting>
</section>
<section id="mvc-config-interceptors">
<title>Configuring Interceptors</title>
<para>You can configure <interfacename>HandlerInterceptors</interfacename>
or <interfacename>WebRequestInterceptors</interfacename> to be applied
to all incoming requests or restricted to specific URL path patterns.</para>
<para>An example of registering interceptors in Java:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocalInterceptor());
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}</programlisting>
<para>And in XML use the <literal>&lt;mvc:interceptors&gt;</literal> element:</para>
<programlisting language="xml">&lt;mvc:interceptors&gt; <programlisting language="xml">&lt;mvc:interceptors&gt;
&lt;bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&gt; &lt;bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor" /&gt;
&lt;/mvc:interceptors&gt;</programlisting>
<para>An example of registering an interceptor limited to a specific URL
path:</para>
<programlisting language="xml">&lt;mvc:interceptors&gt;
&lt;mvc:interceptor&gt; &lt;mvc:interceptor&gt;
&lt;mapping path="/secure/*"/&gt; &lt;mapping path="/secure/*"/&gt;
&lt;bean class="org.example.SecurityInterceptor" /&gt; &lt;bean class="org.example.SecurityInterceptor" /&gt;
&lt;/mvc:interceptor&gt; &lt;/mvc:interceptor&gt;
&lt;/mvc:interceptors&gt;</programlisting> &lt;/mvc:interceptors&gt;
</programlisting>
</section> </section>
<section id="mvc-view-controller"> <section id="mvc-config-view-controller">
<title>mvc:view-controller</title> <title>Configuring View Controllers</title>
<para>This tag is a shortcut for defining a <para>This is a shortcut for defining a
<classname>ParameterizableViewController</classname> that immediately <classname>ParameterizableViewController</classname> that immediately
forwards to a view when invoked. Use it in static cases when there is no forwards to a view when invoked. Use it in static cases when there is no
Java Controller logic to execute before the view generates the Java controller logic to execute before the view generates the
response.</para> response.</para>
<para>An example of view-controller that forwards to a home page is <para>An example of forwarding a request for <literal>"/"</literal>
shown below:</para> to a view called <literal>"home"</literal> in Java:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}</programlisting>
<para>And the same in XML use the <literal>&lt;mvc:view-controller&gt;</literal> element:</para>
<programlisting language="xml">&lt;mvc:view-controller path="/" view-name="home"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:view-controller path="/" view-name="home"/&gt;</programlisting>
</section> </section>
<section id="mvc-static-resources"> <section id="mvc-config-static-resources">
<title>mvc:resources</title> <title>Configuring Serving of Resources</title>
<para>This tag allows static resource requests following a particular <para>This option allows static resource requests following a particular
URL pattern to be served by a URL pattern to be served by a
<classname>ResourceHttpRequestHandler</classname> from any of a list of <classname>ResourceHttpRequestHandler</classname> from any of a list of
<classname>Resource</classname> locations. This provides a convenient <classname>Resource</classname> locations. This provides a convenient
@ -4169,8 +4334,20 @@ public class SimpleController {
unnecessary overhead for resources that are already cached by the unnecessary overhead for resources that are already cached by the
client. For example, to serve resource requests with a URL pattern of client. For example, to serve resource requests with a URL pattern of
<code>/resources/**</code> from a <code>public-resources</code> <code>/resources/**</code> from a <code>public-resources</code>
directory within the web application root, the tag would be used as directory within the web application root you would use:</para>
follows:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
}</programlisting>
<para>And the same in XML:</para>
<programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/public-resources/"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/public-resources/"/&gt;</programlisting>
@ -4178,6 +4355,19 @@ public class SimpleController {
maximum use of the browser cache and a reduction in HTTP requests made maximum use of the browser cache and a reduction in HTTP requests made
by the browser:</para> by the browser:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
}
}</programlisting>
<para>And in XML:</para>
<programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/&gt;</programlisting>
<para>The <code>mapping</code> attribute must be an Ant pattern that can <para>The <code>mapping</code> attribute must be an Ant pattern that can
@ -4189,7 +4379,21 @@ public class SimpleController {
given request. For example, to enable the serving of resources from both given request. For example, to enable the serving of resources from both
the web application root and from a known path of the web application root and from a known path of
<code>/META-INF/public-web-resources/</code> in any jar on the <code>/META-INF/public-web-resources/</code> in any jar on the
classpath, the tag would be specified as:</para> classpath use:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
}
}</programlisting>
<para>And in XML:</para>
<programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/&gt;</programlisting>
@ -4213,8 +4417,7 @@ public class SimpleController {
would be to manage the version of the application in a properties file, would be to manage the version of the application in a properties file,
such as:</para> such as:</para>
<programlisting> <programlisting>application.version=1.0.0</programlisting>
application.version=1.0.0</programlisting>
<para>and then to make the properties file's values accessible to SpEL <para>and then to make the properties file's values accessible to SpEL
as a bean using the <code>util:properties</code> tag:</para> as a bean using the <code>util:properties</code> tag:</para>
@ -4226,6 +4429,25 @@ application.version=1.0.0</programlisting>
<programlisting language="xml">&lt;mvc:resources mapping="/resources-#{applicationProps['application.version']}/**" location="/public-resources/"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:resources mapping="/resources-#{applicationProps['application.version']}/**" location="/public-resources/"/&gt;</programlisting>
<para>In Java, you can use the <interfacename>@PropertySouce</interfacename>
annotation and then inject the <classname>Environment</classname>
abstraction for access to all defined properties:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
@PropertySource("/WEB-INF/spring/application.properties")
public class WebConfig extends WebMvcConfigurerAdapter {
@Inject Environment env;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources-" + env.getProperty("application.version") + "/**")
.addResourceLocations("/public-resources/");
}
}</programlisting>
<para>and finally, to request the resource with the proper URL, we can <para>and finally, to request the resource with the proper URL, we can
take advantage of the Spring JSP tags:</para> take advantage of the Spring JSP tags:</para>
@ -4257,8 +4479,20 @@ application.version=1.0.0</programlisting>
of the <code>DefaultServletHttpRequestHandler</code>, which is of the <code>DefaultServletHttpRequestHandler</code>, which is
<code>Integer.MAX_VALUE</code>.</para> <code>Integer.MAX_VALUE</code>.</para>
<para>To enable the feature using the default setup, simply include the <para>To enable the feature using the default setup use:</para>
tag in the form:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}</programlisting>
<para>Or in XML:</para>
<programlisting language="xml">&lt;mvc:default-servlet-handler/&gt;</programlisting> <programlisting language="xml">&lt;mvc:default-servlet-handler/&gt;</programlisting>
@ -4274,15 +4508,26 @@ application.version=1.0.0</programlisting>
the default Servlet name is unknown, then the default Servlet's name the default Servlet name is unknown, then the default Servlet's name
must be explicitly provided as in the following example:</para> must be explicitly provided as in the following example:</para>
<programlisting language="java">@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}</programlisting>
<para>Or in XML:</para>
<programlisting language="xml">&lt;mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/&gt;</programlisting> <programlisting language="xml">&lt;mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/&gt;</programlisting>
</section> </section>
</section>
<section id="mvc-resources"> <section id="mvc-resources">
<title>More Spring Web MVC Resources</title> <title>More Spring Web MVC Resources</title>
<para>See the following links and pointers for more resources about Spring <para>See the following links and pointers for more resources about Spring Web MVC:</para>
Web MVC:</para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
@ -4299,4 +4544,89 @@ application.version=1.0.0</programlisting>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
</section> </section>
<section id="mvc-config-advanced-java">
<title>Advanced Customizations with MVC Java Config</title>
<para>As you can see from the above examples, MVC Java config and
the MVC namespace provide higher level constructs that do not
require deep knowledge of the underlying beans created for you.
Instead it helps you to focus on your application needs.
However, at some point you may need more fine-grained control
or you may simply wish to understand the underlying configuration.</para>
<para>The first step towards more fine-grained control is to see the
underlying beans created for you. In MVC Java config you can
see the Javadoc and the <interfacename>@Bean</interfacename>
methods in <classname>WebMvcConfigurationSupport</classname>.
The configuration in this class is automatically imported
through the <interfacename>@EnableWebMvc</interfacename> annotation.
In fact if you open <interfacename>@EnableWebMvc</interfacename> you can
see the <interfacename>@Import</interfacename> statement.</para>
<para>The next step towards more fine-grained control is to
customize a property on one of the beans created in
<classname>WebMvcConfigurationSupport</classname> or perhaps
to provide your own instance. This requires two things --
remove the <interfacename>@EnableWebMvc</interfacename>
annotation in order to prevent the import and then
extend directly from <classname>WebMvcConfigurationSupport</classname>.
Here is an example:
</para>
<programlisting language="java">@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Override
public void addInterceptors(InterceptorRegistry registry){
// ...
}
@Override
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// Create or let "super" create the adapter
// Then customize one of its properties
}
}</programlisting>
<para>Note that modifying beans in this way does not prevent
you from using any of the higher-level constructs shown earlier in
this section. </para>
</section>
<section id="mvc-config-advanced-xml">
<title>Advanced Customizations with the MVC Namespace</title>
<para>Fine-grained control over the configuration created for
you is a bit harder with the MVC namespace.</para>
<para>If you do need to do that, rather than replicating the
configuration it provides, consider configuring a
<interfacename>BeanPostProcessor</interfacename> that detects
the bean you want to customize by type and then modifying its
properties as necessary. For example:</para>
<programlisting language="java">@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
// Modify properties of the adapter
}
}
}</programlisting>
<para>Note that <classname>MyPostProcessor</classname> needs to be
included in an <interfacename>&lt;component scan /&gt;</interfacename>
in order for it to be detected or if you prefer you can declare it
explicitly with an XML bean declaration.</para>
</section>
</section>
</chapter> </chapter>