Java MVC Configuration and MVC XML Namespace provide a default configuration suitable for most applications and a configuration API to customize it.
You do not need to understand the underlying beans produced by MVC Java Configuration and the MVC namespace.
Activating an MVC Configuration
In a Java configuration, you
can use the @EnableWebMvc
annotation to enable an MVC configuration, as shown in the following
example:
@Configuration
@EnableWebMvc
public class WebConfig {
}
@Configuration
@EnableWebMvc
class WebConfig
In the XML configuration, you can use the <mvc:annotation-driven>
element to activate the
MVC configuration, as shown in the following example:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven/>
</beans>
The following example registers a number of Spring MVC infrastructure beans and adapts to the dependencies available in the classpath (for example, payload converters for JSON, XML, etc.).
MVC Configuration API
In Java configuration, you can implement the WebMvcConfigurer
interface, as shown in the following
example:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods...
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
// Implement configuration methods...
}
In XML, you can validate <mvc:annotation-driven/>
attributes and subelements. You
can view the Spring MVC XML Schema or use
the code completion feature in your IDE to find out which attributes and subelements are available.
Type conversion
By default, formatters are installed for various number and date types, along with customization
support via @NumberFormat
and @DateTimeFormat
for fields.
To register custom formatters and converters in the Java configuration, use the following:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
// ...
}
}
To do the same in XML configuration, use the following:
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://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>
By default, Spring MVC respects the request locale when parsing and formatting date values. This is true for forms where dates are represented as strings with "input" form fields. However, for the "date" and "time" form fields, browsers use a fixed format defined in the HTML specification. For such cases, date and time formatting can be configured as follows:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registrar.registerFormatters(registry);
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addFormatters(registry: FormatterRegistry) {
val registrar = DateTimeFormatterRegistrar()
registrar.setUseIsoFormat(true)
registrar.registerFormatters(registry)
}
}
Validation
Default , if a Validation Bean is present in the classpath (for example, Hibernate Validator), the LocalValidatorFactoryBean
is registered as a global validator for use with the @Valid
annotation and the
Validated
property on arguments to controller methods.
In your Java configuration, you can configure a global Validator
instance, as shown in the following
example:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator() {
// ...
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun getValidator(): Validator {
// ...
}
}
The following example shows how to get the same configuration 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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven validator="globalValidator"/>
</beans>
Note that it is also possible to register Validator
implementations locally, as shown in the
following example:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
@Controller
class MyController {
@InitBinder
protected fun initBinder(binder: WebDataBinder) {
binder.addValidators(FooValidator())
}
}
LocalValidatorFactoryBean
was injected
somewhere, create a bean and mark it with the @Primary
annotation to avoid conflicts with what was
declared in the MVC configuration.
Interceptors
In your Java configuration, you can register interceptors to apply to incoming requests, as shown in the following example:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleChangeInterceptor());
registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addInterceptors(registry: InterceptorRegistry) {
registry.addInterceptor(LocaleChangeInterceptor())
registry.addInterceptor(ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**")
}
}
The following example shows how to get the same configuration in XML:
<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:interceptors>
Content Types
The method can be configured , which Spring MVC defines the requested media types from
the request (such as the Accept
header, URL path extension, request parameter, and others).
By
default, only the header is checked Accept
.
If you need to use URL-based content type resolution, consider using a request parameters strategy instead of path extensions.
In a Java configuration, you can configure the resolution of the requested content type, as shown in the following example:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
configurer.mediaType("xml", MediaType.APPLICATION_XML);
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureContentNegotiation(configurer: ContentNegotiationConfigurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON)
configurer.mediaType("xml", MediaType.APPLICATION_XML)
}
}
The following example shows , how to get the same configuration in XML:
<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>
Message Converters
You can configure HttpMessageConverter
in your Java configuration by overriding configureMessageConverters()
(to replace the default converters created by
Spring MVC) or by overriding extendMessageConverters()
(to customize default converters or add
additional converters to the default converters).
The following example adds XML and Jackson JSON converters with ObjectMapper
configured instead of
the standard ones:
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
@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.createXmlMapper(true).build()));
}
}
@Configuration
@EnableWebMvc
class WebConfiguration : WebMvcConfigurer {
override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
val builder = Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(ParameterNamesModule())
converters.add(MappingJackson2HttpMessageConverter(builder.build()))
converters.add(MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()))
In the previous example Jackson2ObjectMapperBuilder
is used to create a common configuration for
MappingJackson2HttpMessageConverter
and MappingJackson2XmlHttpMessageConverter
with
indentation enabled, date format configured, and module registration jackson-module-parameter-names
which
adds support for accessing parameter names (a feature added in Java 8 ).
This build tool configures the default Jackson properties as follows:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
is disabled.MapperFeature.DEFAULT_VIEW_INCLUSION
is disabled.
It also automatically registers the following known modules if found in the classpath:
jackson-datatype-joda: Support for Joda types Time.
jackson-datatype-jsr310: Support for Java 8 date and time API types.
jackson-datatype-jdk8: Supports other Java 8 types such as
Optional
.jackson-module-kotlin
: Support for Kotlin classes and data classes.
woodstox-core-asl
in addition to jackson-
dataformat-xml
.
There are other interesting Jackson modules:
jackson-datatype-money: Support for
javax.money
types (unofficial module).jackson-datatype-hibernate: Support for Hibernate-specific types and properties (including lazy loading aspects).
The following example shows how to get the same configuration 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"/>
Controller View
This is shorthand for defining a ParameterizableViewController
that,
when called, immediately jumps to the view. You can use it in static cases where there is no Java controller logic
that needs to be executed before the view generates a response.
The following Java configuration example
makes a request to /
in view called home
:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addViewControllers(registry: ViewControllerRegistry) {
registry.addViewController("/").setViewName("home")
}
}
The following example produces the same thing as the previous one, but using XML, by using the element <mvc:view-controller>
:
<mvc:view-controller path="/" view-name="home"/>
If a method with the @RequestMapping
annotation is mapped to a URL for any HTTP method, then the
view controller cannot be used to process the same URL. This is because a URL match to an annotated controller is
considered a strong enough indication of endpoint ownership that a 405 (METHOD_NOT_ALLOWED), 415
(UNSUPPORTED_MEDIA_TYPE), or similar response may be sent to the client to aid in debugging. For this reason, it is
recommended to avoid splitting URL processing into an annotated controller and a view controller.
View Resolvers
The MVC configuration makes it easy to register view resolvers.
In the following example
Java configuration configures content negotiation view resolution using JSP and Jackson as default View
for rendering in JSON format:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.enableContentNegotiation(MappingJackson2JsonView())
registry.jsp()
}
}
The following example shows how to get the same configuration 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 presentation technology configuration.
The MVC namespace provides special elements. The following example works 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 the Java configuration, you can add the corresponding Configurer
bean, as shown in the
following example :
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.freeMarker().cache(false);
}
@Bean
public FreeMarkerConfigurer freeMarkerConfigurer() {
FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
configurer.setTemplateLoaderPath("/freemarker");
return configurer;
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureViewResolvers(registry: ViewResolverRegistry) {
registry.enableContentNegotiation(MappingJackson2JsonView())
registry.freeMarker().cache(false)
}
@Bean
fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
setTemplateLoaderPath("/freemarker")
}
}
Static Resources
This option provides a convenient way to handle static resources from a list of
locations based on Resource
.
In the following example, if the request begins with
/resources
, the relative path is used to find and process static resources relative to
/public
in the web application root or in the classpath at /static
. Resources are
provided with a one-year expiration date to ensure maximum use of the browser's cache and a reduction in HTTP
requests made by the browser. Last-Modified
information is derived from
Resource#lastModified
to provide support for conditional HTTP requests with
"Last-Modified"
headers.
The following listing shows how to do this using the Java configuration:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCacheControl(CacheControl.maxAge(Duration.ofDays(365)))
}
}
The following example shows how to get the same configuration in XML:
<mvc:resources mapping="/resources/**"
location="/public, classpath:/static/"
cache-period="31556926" />
The resource handler also supports implementation chaining ResourceResolver
and ResourceTransformer
that you can use to create a toolkit for working with
optimized resources.
You can use VersionResourceResolver
to version version resource URLs based
on an MD5 hash , calculated from the content, fixed version of the application or other. ContentVersionStrategy
(MD5 hash) is a smart choice - with some notable exceptions, such as JavaScript resources used with the module
loader.
The following example shows how to use the VersionResourceResolver
in Java
configuration:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
}
}
The following example shows how to get the same configuration in XML:
<mvc:resources mapping="/resources/**" location="/public/">
<mvc:resource-chain resource-cache="true">
<mvc:resolvers>
<mvc:version-resolver>
<mvc:content-version-strategy patterns="/**"/>
</mvc:version-resolver>
</mvc:resolvers>
</mvc:resource-chain>
</mvc:resources>
You can then use ResourceUrlProvider
to rewrite the URLs and apply the full chain of resolvers
and resolvers - for example, to insert versions. The MVC configuration provides a ResourceUrlProvider
bean that can be injected into other beans. You can also make rewriting transparent using ResourceUrlEncodingFilter
for Thymeleaf, JSP, FreeMarker and others using URL tags that rely on HttpServletResponse#encodeURL
.
Note that when using EncodedResourceResolver
(for example, to process encoded resources with gzip
or brotli compression methods) and VersionResourceResolver
, you must register them in that order. This
enables content-based versions to be reliably calculated from the raw file.
WebJars are also supported using WebJarsResourceResolver
,
which is automatically registered when the org.webjars:webjars-locator-core
library is present in the
classpath. The resolver can rewrite URLs to include the jar version, and can also match incoming URLs without
versions - for example, from /jquery/jquery.min.js
to /jquery/1.2 .0/jquery.min.js
.
ResourceHandlerRegistry
provides
additional capabilities for fine-grained control, such as last-change logic and optimized resource resolution.
Default Servlet
The Spring MVC framework allows you to map DispatcherServlet
to
/
(thereby overriding the rendering of the standard container servlet), with static requests for
resources being handled by the standard container servlet. It configures the
DefaultServletHttpRequestHandler
with URL mapping /**
and the lowest priority relative to
other URL mappings.
This handler forwards all requests to the servlet default. Therefore, it must remain last
in the order of all other HandlerMappings
for the URL. This occurs when <mvc:annotation-driven>
is used. Also, if you create your own HandlerMapping
instance, be sure to set its order
property to a value less than the DefaultServletHttpRequestHandler
, which is
Integer.MAX_VALUE
.
The following example shows how to enable this feature using the default settings:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
configurer.enable()
}
}
The following example shows how to get the same configuration in XML:
<mvc:default-servlet-handler/>
The caveat to overriding the /
servlet mapping is that the RequestDispatcher
for the default servlet must be found by name , and not along the way. DefaultServletHttpRequestHandler
attempts to automatically determine the default servlet for a container at startup time, using a list of known names
for most 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 you are using a different servlet
container where the default servlet name is unknown, then you must explicitly specify the default servlet name, as
shown in the following example:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
configurer.enable("myCustomDefaultServlet")
}
}
The following example shows how to get the same configuration in XML:
<mvc:default-servlet-handler default-servlet- name="myCustomDefaultServlet"/>
Path Mapping
You can configure settings related to path mapping and URL handling . For more
information about individual options, see the javadoc at PathMatchConfigurer
.
The following example shows how to configure path matching in a Java configuration:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer
.setPatternParser(new PathPatternParser())
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
}
private PathPatternParser patternParser() {
// ...
}
}
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun configurePathMatch(configurer: PathMatchConfigurer) {
configurer
.setPatternParser(patternParser)
.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
}
fun patternParser(): PathPatternParser {
//...
}
}
The following example shows how to get the same configuration in XML:
<mvc:annotation-driven>
<mvc:path-matching
trailing-slash="false"
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"/>
Advanced Java configuration
@EnableWebMvc
imports
DelegatingWebMvcConfiguration
, which:
Pass the default Spring configuration for Spring MVC applications
Discovers and delegates
WebMvcConfigurer
implementations to configure this configuration.
In advanced mode, you can remove the @EnableWebMvc
annotation and do the extension directly from
DelegatingWebMvcConfiguration
instead of implementing WebMvcConfigurer
, as shown in the
following example:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
// ...
}
@Configuration
class WebConfig : DelegatingWebMvcConfiguration() {
// ...
}
You can save existing methods in WebConfig
, but it is now also possible to override bean
declarations from the base class, and it is still possible to have any number of other WebMvcConfigurer
implementations in the classpath.
Extended XML Configuration
Space MVC names do not provide an
extended mode. If you need to set a bean property that cannot be changed in any other way, you can use the BeanPostProcessor
lifecycle interceptor in the ApplicationContext
for Spring, as shown in the following example :
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
// ...
}
}
@Component
class MyPostProcessor : BeanPostProcessor {
override fun postProcessBeforeInitialization(bean: Any, name: String): Any {
// ...
}
}