Spring MVC 提供了多种配置选项,用户可以根据自己的需求配置Spring MVC。现在主要是两种配置,Java和XML,目前更加推荐使用Java来配置。
启用MVC配置
使用Java配置,使用@EnableMvc注解
@Configuration
@EnableWebMvc
public class WebConfig {
}
XML配置,使用<mvc:annotation-driven>
<?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>
MVC Config API
使用Java配置可以继承WebMvcConfigure接口:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// Implement configuration methods...
}
对于xml配置可以参考Spring MVC XML schema中的<mvc:annotation-driven/>的子元素。
类型转换
默认情况下支持Number和Date的格式化,包括注解@NumberFormat和@DateTimeFormat。如果Joda-Time的库加入到了classpath,那么也会支持Joda-Time的格式化。 在Java配置中,可以通过如下方式注册自己的格式化器和转换器:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
在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 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>
校验
Bean Validateion是默认添加到classpath中,例如Hibernate Validator,LocalValidatorFactoryBean注册为全局校验器,这样就可以在controller的方法中使用@Valid和Validated了。
在Java配置中可以如下配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public Validator getValidator(); {
// ...
}
}
在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>
注意:校验器同样可以只在本地注册:
@Controller
public class MyController {
@InitBinder
protected void initBinder(WebDataBinder binder) {
binder.addValidators(new FooValidator());
}
}
拦截器
在Java配置中可以通过如下方式配置拦截器:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LocaleInterceptor());
registry.addInterceptor(new ThemeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
}
}
在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:interceptor>
<mvc:mapping path="/secure/*"/>
<bean class="org.example.SecurityInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
内容类型
Spring MVC 可以通过配置如何从request中获取媒体类型,例如通过Accept,URL 路径后缀,查询参数等。 默认情况下,首先检查URL路径后缀,json,xml,rss这种在classpath中注册过的扩展名,然后才会去检查Accept头。 在Java中可以如下配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
}
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>
消息转换
在Java配置中可以通过重写HttpMessageConverter的confiureMessageConverters()替换SpringMVC默认的消息转换器,如果只是想要扩展,则只需要重写extendMessageConverters()即可。 下面这个例子是通过自定义的ObjectMapper定制JSON和XML的消息转换。
@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.xml().build()));
}
}
在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
这个是定义ParameterizableViewController快捷方式,如果无需执行任何Java逻辑只需要返回个视图,就可以这么定义。 Java配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
XML 配置
<mvc:view-controller path="/" view-name="home"/>
视图解析器
MVC 简化了视图解析器的注册。下面这个例子是根据内容协商使用JSP和Jackson作为默认视图返回JSON:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.enableContentNegotiation(new MappingJackson2JsonView());
registry.jsp();
}
}
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>
像FreeMarker,Tiles,Groovy Markup和脚本模板都需要进行视图解析的配置,例如配置FreeMarker 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:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
<mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>
Java 配置
@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("/WEB-INF/");
return configurer;
}
}
静态资源
在下面这个例子中,请求URL路径以/resources开头,会从相对于应用根目录的/public目录和classpath的/static目录查找静态资源,同时静态资源有1年的缓存。 Java 配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public", "classpath:/static/")
.setCachePeriod(31556926);
}
}
XML 配置:
<mvc:resources mapping="/resources/**"
location="/public, classpath:/static/"
cache-period="31556926" />
资源处理支持一系列的的ResourceResolver和ResourceTransformer,他们可以组成一系列工具链优化资源处理。 VersionResourceResolver可以通过计算内容MD5提供版本号的资源处理,对一些已知的扩展名例如Javacsript,可以使用ContentVersionStrategy(计算MD5)。 Java 配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/public/")
.resourceChain(true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
}
}
XML 配置:
<mvc:resources mapping="/resources/**" location="/public/">
<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>
默认Servlet
DispatcherServlet是映射到/的,这样就相当于替换了Servlet容器默认的Servlet,但是Spring MVC仍然可以将静态资源又默认的Servlet处理。通过定义DefaultServletHttpRequestHandler映射到/**。因为这个定义会将所有的请求映射到默认Servlet,所以他匹配的优先级必须设置为最低,是最后一个才匹配的。 Java 配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
XML 配置:
<mvc:default-servlet-handler/>
重写'/'的Servlet映射需要注意的是,默认Servlet的RequestDispatcher是名字查找的。DefaultServletHttpRequestHandler在启动的时候会尝试通过一系列一直的Servlet容器(Tomcat,Jetty,GlassFish,JBoss,Resin,WebLogic,WebSphere)来检测默认Servlet。所以如自定义了默认Servlet,需要指定其名字。 Java 配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
XML 配置
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
路径匹配
主要是用来设置如何进行URL的路径匹配的,详细信息可以查看PathMatchConfigurer。 Java配置:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@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() {
//...
}
}
XML 配置:
<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"/>
高级Java配置
@EnableWebMvc导入了DelegationWebMvcConfiguration,他的作用: 1. 提供Spring MVC默认配置 2. 检测WebMvcConfigure的委托以定制配置
在高级模式中,无需使用@EnableWebMvc直接继承DelegatingWebMvcConfiguration Java配置:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
// ...
}
高级XML配置
XML配置没有高级模式,如果想要定制属性,可以通过BeanPostProcessor实现。
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
// ...
}
}