@Configuration
@EnableWebMvc
public class WebConfig {
}
Configuring Spring MVC
this section you’ll learn about two additional ways of configuring Spring MVC. Namely the MVC Java config and the MVC XML namespace.
The MVC Java config and the MVC namespace provide similar default configuration that
overrides the DispatcherServlet
defaults. The goal is to spare most applications from
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.
You can choose either the MVC Java config or the 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.
Enabling the MVC Java Config or the MVC XML Namespace
To enable MVC Java config add the annotation @EnableWebMvc
to one of your
@Configuration
classes:
To achieve the same in XML use the mvc:annotation-driven
element in your
DispatcherServlet context (or in your root context if you have no DispatcherServlet
context defined):
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
</beans>
The above registers a RequestMappingHandlerMapping
, a RequestMappingHandlerAdapter
,
and an ExceptionHandlerExceptionResolver
(among others) in support of processing
requests with annotated controller methods using annotations such as @RequestMapping
,
@ExceptionHandler
, and others.
It also enables the following:
-
Spring 3 style type conversion through a ConversionService instance in addition to the JavaBeans PropertyEditors used for Data Binding.
-
Support for formatting Number fields using the
@NumberFormat
annotation through theConversionService
. -
Support for formatting
Date
,Calendar
,Long
, and Joda Time fields using the@DateTimeFormat
annotation. -
Support for validating
@Controller
inputs with@Valid
, if a JSR-303 Provider is present on the classpath. -
HttpMessageConverter
support for@RequestBody
method parameters and@ResponseBody
method return values from@RequestMapping
or@ExceptionHandler
methods.This is the complete list of HttpMessageConverters set up by mvc:annotation-driven:
-
ByteArrayHttpMessageConverter
converts byte arrays. -
StringHttpMessageConverter
converts strings. -
ResourceHttpMessageConverter
converts to/fromorg.springframework.core.io.Resource
for all media types. -
SourceHttpMessageConverter
converts to/from ajavax.xml.transform.Source
. -
FormHttpMessageConverter
converts form data to/from aMultiValueMap<String, String>
. -
Jaxb2RootElementHttpMessageConverter
converts Java objects to/from XML — added if JAXB2 is present and Jackson 2 XML extension is not present on the classpath. -
MappingJackson2HttpMessageConverter
converts to/from JSON — added if Jackson 2 is present on the classpath. -
MappingJackson2XmlHttpMessageConverter
converts to/from XML — added if Jackson 2 XML extension is present on the classpath. -
AtomFeedHttpMessageConverter
converts Atom feeds — added if Rome is present on the classpath. -
RssChannelHttpMessageConverter
converts RSS feeds — added if Rome is present on the classpath.
-
See Message Converters for more information about how to customize these default converters.
Note
|
Jackson JSON and XML converters are created using This builder customizes Jackson’s default properties with the following ones:
It also automatically registers the following well-known modules if they are detected on the classpath:
|
Customizing the Provided Configuration
To customize the default configuration in Java you simply implement the
WebMvcConfigurer
interface or more likely extend the class WebMvcConfigurerAdapter
and override the methods you need:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// Override configuration methods...
}
To customize the default configuration of <mvc:annotation-driven/>
check what
attributes and sub-elements it supports. You can view the
Spring MVC XML schema or use the code
completion feature of your IDE to discover what attributes and sub-elements are
available.
Conversion and Formatting
By default formatters for Number
and Date
types are installed, including support for
the @NumberFormat
and @DateTimeFormat
annotations. Full support for the Joda Time
formatting library is also installed if Joda Time is present on the classpath. To
register custom formatters and converters, override the addFormatters
method:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
// Add formatters and/or converters
}
}
In the MVC namespace the same defaults apply when <mvc:annotation-driven>
is added.
To register custom formatters and converters simply supply a ConversionService
:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven conversion-service="conversionService"/>
<bean id="conversionService"
class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="org.example.MyConverter"/>
</set>
</property>
<property name="formatters">
<set>
<bean class="org.example.MyFormatter"/>
<bean class="org.example.MyAnnotationFormatterFactory"/>
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.example.MyFormatterRegistrar"/>
</set>
</property>
</bean>
</beans>
Note
|
See [format-FormatterRegistrar-SPI] and the |
Validation
Spring provides a Validator interface that can be used for validation in all layers
of an application. In Spring MVC you can configure it for use as a global Validator
instance, to be used
whenever an @Valid
or @Validated
controller method argument is encountered, and/or as a local
Validator
within a controller through an @InitBinder
method. Global and local validator
instances can be combined to provide composite validation.
Spring also supports JSR-303/JSR-349 Bean Validation
via LocalValidatorFactoryBean
which adapts the Spring org.springframework.validation.Validator
interface to the Bean Validation javax.validation.Validator
contract. This class can be
plugged into Spring MVC as a global validator as described next.
By default use of @EnableWebMvc
or <mvc:annotation-driven>
automatically registers Bean
Validation support in Spring MVC through the LocalValidatorFactoryBean
when a Bean Validation
provider such as Hibernate Validator is detected on the classpath.
Note
|
Sometimes it’s convenient to have a If you prefer to use the one from the MVC Java config, you’ll need to override the
|
Alternatively you can configure your own global Validator
instance:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public Validator getValidator(); {
// return "global" validator
}
}
and in XML:
<?xml version="1.0" encoding="UTF-8"?>
<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.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="globalValidator"/>
</beans>
To combine global with local validation, simply add one or more local validator(s):
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
With this minimal configuration any time an @Valid
or @Validated
method argument is encountered, it
will be validated by the configured validators. Any validation violations will automatically
be exposed as errors in the BindingResult
accessible as a method argument and also renderable
in Spring MVC HTML views.
Interceptors
You can configure HandlerInterceptors
or WebRequestInterceptors
to be applied to all
incoming requests or restricted to specific URL path patterns.
An example of registering interceptors in Java:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
And in XML use the <mvc:interceptors>
element:
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/admin/**"/>
<bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
Content Negotiation
You can configure how Spring MVC determines the requested media types from the request. The available options are to check the URL path for a file extension, check the "Accept" header, a specific query parameter, or to fall back on a default content type when nothing is requested. By default the path extension in the request URI is checked first and the "Accept" header is checked second.
The MVC Java config and the MVC namespace register json
, xml
, rss
, atom
by
default if corresponding dependencies are on the classpath. Additional
path extension-to-media type mappings may also be registered explicitly and that
also has the effect of whitelisting them as safe extensions for the purpose of RFD
attack detection (see [mvc-ann-requestmapping-rfd] for more detail).
Below is an example of customizing content negotiation options through the MVC Java config:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
}
In the MVC namespace, the <mvc:annotation-driven>
element has a
content-negotiation-manager
attribute, which expects a ContentNegotiationManager
that in turn can be created with a ContentNegotiationManagerFactoryBean
:
<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
<property name="mediaTypes">
<value>
json=application/json
xml=application/xml
</value>
</property>
</bean>
If not using the MVC Java config or the MVC namespace, you’ll need to create an instance
of ContentNegotiationManager
and use it to configure RequestMappingHandlerMapping
for request mapping purposes, and RequestMappingHandlerAdapter
and
ExceptionHandlerExceptionResolver
for content negotiation purposes.
Note that ContentNegotiatingViewResolver
now can also be configured with a
ContentNegotiationManager
, so you can use one shared instance throughout Spring MVC.
In more advanced cases, it may be useful to configure multiple
ContentNegotiationManager
instances that in turn may contain custom
ContentNegotiationStrategy
implementations. For example you could configure
ExceptionHandlerExceptionResolver
with a ContentNegotiationManager
that always
resolves the requested media type to "application/json"
. Or you may want to plug a
custom strategy that has some logic to select a default content type (e.g. either XML or
JSON) if no content types were requested.
View Controllers
This is a shortcut for defining a ParameterizableViewController
that immediately
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 response.
An example of forwarding a request for "/"
to a view called "home"
in Java:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
And the same in XML use the <mvc:view-controller>
element:
<mvc:view-controller path="/" view-name="home"/>
View Resolvers
The MVC config simplifies the registration of view resolvers.
The following is a Java config example that configures content negotiation view
resolution using FreeMarker HTML templates and Jackson as a default View
for
JSON rendering:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
And the same in XML:
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:jsp/>
</mvc:view-resolvers>
Note however that FreeMarker, Tiles, Groovy Markup and script templates also require configuration of the underlying view technology.
The MVC namespace provides dedicated elements. For example with FreeMarker:
<mvc:view-resolvers>
<mvc:content-negotiation>
<mvc:default-views>
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
</mvc:default-views>
</mvc:content-negotiation>
<mvc:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>
In Java config simply add the respective "Configurer" bean:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker().cache(false);
}
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/WEB-INF/");
return configurer;
}
}
Serving of Resources
This option allows static resource requests following a particular URL pattern to be
served by a ResourceHttpRequestHandler
from any of a list of Resource
locations.
This provides a convenient way to serve static resources from locations other than the
web application root, including locations on the classpath. The cache-period
property
may be used to set far future expiration headers (1 year is the recommendation of
optimization tools such as Page Speed and YSlow) so that they will be more efficiently
utilized by the client. The handler also properly evaluates the Last-Modified
header
(if present) so that a 304
status code will be returned as appropriate, avoiding
unnecessary overhead for resources that are already cached by the client. For example,
to serve resource requests with a URL pattern of /resources/**
from a
public-resources
directory within the web application root you would use:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
}
And the same in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
To serve these resources with a 1-year future expiration to ensure maximum use of the browser cache and a reduction in HTTP requests made by the browser:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
}
}
And in XML:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
For more details, see HTTP caching support for static resources.
The mapping
attribute must be an Ant pattern that can be used by
SimpleUrlHandlerMapping
, and the location
attribute must specify one or more valid
resource directory locations. Multiple resource locations may be specified using a
comma-separated list of values. The locations specified will be checked in the specified
order for the presence of the resource for any given request. For example, to enable the
serving of resources from both the web application root and from a known path of
/META-INF/public-web-resources/
in any jar on the classpath use:
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
}
}
And in XML:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>
When serving resources that may change when a new version of the application is
deployed it is recommended that you incorporate a version string into the mapping
pattern used to request the resources so that you may force clients to request the
newly deployed version of your application’s resources. Support for versioned URLs is
built into the framework and can be enabled by configuring a resource chain
on the resource handler. The chain consists of one more ResourceResolver
instances followed by one or more ResourceTransformer
instances. Together they
can provide arbitrary resolution and transformation of resources.
The built-in VersionResourceResolver
can be configured with different strategies.
For example a FixedVersionStrategy
can use a property, a date, or other as the version.
A ContentVersionStrategy
uses an MD5 hash computed from the content of the resource
(known as "fingerprinting" URLs). Note that the VersionResourceResolver
will automatically
use the resolved version strings as HTTP ETag header values when serving resources.
ContentVersionStrategy
is a good default choice to use except in cases where
it cannot be used (e.g. with JavaScript module loaders). You can configure
different version strategies against different patterns as shown below. Keep in mind
also that computing content-based versions is expensive and therefore resource chain
caching should be enabled in production.
Java config example;
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public-resources/")
.resourceChain(true).addResolver(
new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
XML example:
<mvc:resources mapping="/resources/**" location="/public-resources/">
<mvc:resource-chain>
<mvc:resource-cache/>
<mvc:resolvers>
<mvc:version-resolver>
<mvc:content-version-strategy patterns="/**"/>
</mvc:version-resolver>
</mvc:resolvers>
</mvc:resource-chain>
</mvc:resources>
In order for the above to work the application must also
render URLs with versions. The easiest way to do that is to configure the
ResourceUrlEncodingFilter
which wraps the response and overrides its encodeURL
method.
This will work in JSPs, FreeMarker, and any other view technology that calls the response
encodeURL
method. Alternatively, an application can also inject and use directly the
ResourceUrlProvider
bean, which is automatically declared with the MVC Java config and
the MVC namespace.
Webjars are also supported with WebJarsResourceResolver
, which is automatically registered
when the "org.webjars:webjars-locator"
library is on classpath. This resolver allows
the resource chain to resolve version agnostic libraries from HTTP GET requests
"GET /jquery/jquery.min.js"
will return resource "/jquery/1.2.0/jquery.min.js"
.
It also works by rewriting resource URLs in templates
<script src="/jquery/jquery.min.js"/> → <script src="/jquery/1.2.0/jquery.min.js"/>
.
Falling Back On the "Default" Servlet To Serve Resources
This allows for mapping the DispatcherServlet
to "/" (thus overriding the mapping
of the container’s default Servlet), while still allowing static resource requests to be
handled by the container’s default Servlet. It configures a
DefaultServletHttpRequestHandler
with a URL mapping of "/**" and the lowest priority
relative to other URL mappings.
This handler will forward all requests to the default Servlet. Therefore it is important
that it remains last in the order of all other URL HandlerMappings
. That will be the
case if you use <mvc:annotation-driven>
or alternatively if you are setting up your
own customized HandlerMapping
instance be sure to set its order
property to a value
lower than that of the DefaultServletHttpRequestHandler
, which is Integer.MAX_VALUE
.
To enable the feature using the default setup use:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Or in XML:
<mvc:default-servlet-handler/>
The caveat to overriding the "/" Servlet mapping is that the RequestDispatcher
for the
default Servlet must be retrieved by name rather than by path. The
DefaultServletHttpRequestHandler
will attempt to auto-detect the default Servlet for
the container at startup time, using a list of known names for most of the major Servlet
containers (including Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic, and WebSphere).
If the default Servlet has been custom configured with a different name, or if a
different Servlet container is being used where the default Servlet name is unknown,
then the default Servlet’s name must be explicitly provided as in the following example:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
Or in XML:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
Path Matching
This allows customizing various settings related to URL mapping and path matching. For details on the individual options check out the {api-spring-framework}/web/servlet/config/annotation/PathMatchConfigurer.html[PathMatchConfigurer] API.
Below is an example in Java config:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseSuffixPatternMatch(true)
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper());
}
@Bean
public UrlPathHelper urlPathHelper() {
//...
}
@Bean
public PathMatcher antPathMatcher() {
//...
}
}
And the same in XML, use the <mvc:path-matching>
element:
<mvc:annotation-driven>
<mvc:path-matching
suffix-pattern="true"
trailing-slash="false"
registered-suffixes-only="true"
path-helper="pathHelper"
path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>
Message Converters
Customization of HttpMessageConverter
can be achieved in Java config by overriding
{api-spring-framework}/web/servlet/config/annotation/WebMvcConfigurerAdapter.html#configureMessageConverters-java.util.List-[configureMessageConverters()
]
if you want to replace the default converters created by Spring MVC, or by overriding
{api-spring-framework}/web/servlet/config/annotation/WebMvcConfigurerAdapter.html#extendMessageConverters-java.util.List-[extendMessageConverters()
]
if you just want to customize them or add additional converters to the default ones.
Below is an example that adds Jackson JSON and XML converters with a customized
ObjectMapper
instead of default ones:
@Configuration
@EnableWebMvc
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(new ParameterNamesModule());
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
converters.add(new MappingJackson2XmlHttpMessageConverter(builder.xml().build()));
}
}
In this example, Jackson2ObjectMapperBuilder
is used to create a common configuration for
both MappingJackson2HttpMessageConverter
and MappingJackson2XmlHttpMessageConverter
with
indentation enabled, a customized date format and the registration of
jackson-module-parameter-names
that adds support for accessing parameter names (feature added in Java 8).
Note
|
Enabling indentation with Jackson XML support requires
|
Other interesting Jackson modules are available:
-
jackson-datatype-money: support for
javax.money
types (unofficial module) -
jackson-datatype-hibernate: support for Hibernate specific types and properties (including lazy-loading aspects)
It is also possible to do the same in XML:
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
<property name="objectMapper" ref="xmlMapper"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
p:indentOutput="true"
p:simpleDateFormat="yyyy-MM-dd"
p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>
Advanced Customizations with MVC Java Config
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.
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 javadocs and the @Bean
methods in
WebMvcConfigurationSupport
. The configuration in this class is automatically imported
through the @EnableWebMvc
annotation. In fact if you open @EnableWebMvc
you can see
the @Import
statement.
The next step towards more fine-grained control is to customize a property on one of the
beans created in WebMvcConfigurationSupport
or perhaps to provide your own instance.
This requires two things — remove the @EnableWebMvc
annotation in order to prevent
the import and then extend from DelegatingWebMvcConfiguration
, a subclass of
WebMvcConfigurationSupport
.
Here is an example:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
@Override
public void addInterceptors(InterceptorRegistry registry){
// ...
}
@Override
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
// Create or let "super" create the adapter
// Then customize one of its properties
}
}
Note
|
An application should have only one configuration extending Modifying beans in this way does not prevent you from using any of the higher-level
constructs shown earlier in this section. |
Advanced Customizations with the MVC Namespace
Fine-grained control over the configuration created for you is a bit harder with the MVC namespace.
If you do need to do that, rather than replicating the configuration it provides,
consider configuring a BeanPostProcessor
that detects the bean you want to customize
by type and then modifying its properties as necessary. For example:
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
// Modify properties of the adapter
}
}
}
Note that MyPostProcessor
needs to be included in an <component scan/>
in order for
it to be detected or if you prefer you can declare it explicitly with an XML bean
declaration.