参考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#mvc-config
本节中了解配置Spring MVC的另外两种方法:MVC Java配置和MVC XML命名空间。
MVC Java配置和MVC命名空间提供类似的默认配置,它会覆盖DispatcherServlet的默认值。目标是使大多数应用程序不必创建相同的配置,并提供更高级别的构造,用于配置Spring MVC,作为一个简单的起点,并且需要很少或根本不需要基础配置的知识。
可以根据自己的喜好选择MVC Java配置或MVC命名空间。另外,正如将在下面看到的,使用MVC Java配置,更容易看到底层配置,以及直接对创建的Spring MVC bean进行细粒度的自定义。
1. 启用MVC Java Config或MVC XML命名空间
要启用MVC Java配置,请将注解@EnableWebMvc添加到@Configuration类之一:
@Configuration
@EnableWebMvc
public class WebConfig {
}
要在XML中实现相同的功能,请在DispatcherServlet上下文中使用<mvc:annotation-driven>元素(如果未定义DispatcherServlet上下文,则在根上下文中使用):
<?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>
上面注册了RequestMappingHandlerMapping,RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver(以及其他),以支持使用带注释的控制器方法处理请求,例如@RequestMapping,@ ExceptionHandler等注解。
它还可以实现以下功能:
- 除了用于数据绑定的JavaBeans PropertyEditors之外,还通过ConversionService实例进行Spring 3样式类型转换。
- 支持通过ConversionService使用@NumberFormat注解格式化数字字段。
- 支持使用@DateTimeFormat注解格式化Date、Calendar、Long和Joda-Time字段。
- 如果类路径中存在JSR-303实现,则支持使用@Valid验证@Controller输入。
- HttpMessageConverter支持@RequestBody方法参数和@RequestMapping或@ExceptionHandler方法上@ResponseBody注释的方法的返回值。
由mvc:annotation-driven设置的HttpMessageConverters的完整列表:
- a. ByteArrayHttpMessageConverter:转换字节数组。
- b. StringHttpMessageConverter:转换字符串。
- c. ResourceHttpMessageConverter:为所有媒体类型从org.springframework.core.io.Resource转换或转换为org.springframework.core.io.Resource。
- d. SourceHttpMessageConverter:从javax.xml.transform.Source转换或转换为javax.xml.transform.Source
- e. FormHttpMessageConverter:将表单数据从MultiValueMap<String, String>转换或转换为MultiValueMap<String, String>。
- f. Jaxb2RootElementHttpMessageConverter:将Java对象转换为XML或从XML转换 - 如果存在JAXB2且类路径中不存在Jackson 2 XML扩展,则添加。
- g. MappingJackson2HttpMessageConverter:转换为JSON转换或从JSON转换 - 如果类路径中存在Jackson 2,则添加。
- h. MappingJackson2XmlHttpMessageConverter:转换为XML或从XML转换 - 如果类路径中存在Jackson 2 XML扩展,则添加。
- i. AtomFeedHttpMessageConverter:转换Atom提要 - 如果类路径中存在Rome,则添加。
- j. RssChannelHttpMessageConverter:转换RSS提要 - 如果类路径中存在Rome,则添加RSS提要。
注:
Jackson JSON和XML转换器是使用Jackson2ObjectMapperBuilder创建的ObjectMapper实例创建的,以便提供更好的默认配置。
此构建器使用以下方法自定义Jackson的默认属性:
- DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES:已禁用。
- MapperFeature.DEFAULT_VIEW_INCLUSION:已禁用。
如果在类路径中检测到它们,它还会自动注册以下模块:
- jackson-datatype-jdk7:支持Java 7类型,如java.nio.file.Path。
- jackson-datatype-joda:支持Joda-Time类型。
- jackson-datatype-jsr310:支持Java 8 Date&Time API类型。
- jackson-datatype-jdk8:支持其他Java 8类型,如Optional。
2. 自定义提供的配置
要在Java中自定义默认配置,只需实现WebMvcConfigurer接口,或者更可能扩展WebMvcConfigurerAdapter类并覆盖需要的方法:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
// 覆盖配置方法...
}
要自定义<mvc:annotation-driven />的默认配置,请检查它支持的属性和子元素。 可以查看Spring MVC XML架构或使用IDE的代码完成功能来发现可用的属性和子元素。
3. 转换和格式化
默认情况下,会安装Number和Date类型的格式化程序,包括对@NumberFormat和@DateTimeFormat注解的支持。 如果类路径中存在Joda-Time,则还会安装对Joda-Time格式库的完全支持。 要注册自定义格式化程序和转换器,请覆盖addFormatters方法:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addFormatters(FormatterRegistry registry) {
// ...
}
}
在MVC命名空间中,添加<mvc:annotation-driven>时会应用相同的默认值。 要注册自定义格式化程序和转换器,只需提供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>
4. 校验
Spring提供了一个Validator接口,可用于在应用程序的所有层中进行验证。在Spring MVC中,可以将其配置为用作全局Validator实例,在遇到@Valid或@Validated控制器方法参数时使用,或通过@InitBinder方法在控制器中作为本地Validator使用。可以组合全局和本地验证器实例以提供复合验证。
Spring还通过LocalValidatorFactoryBean支持JSR-303/JSR-349 Bean验证,它使Spring org.springframework.validation.Validator接口适应Bean Validation javax.validation.Validator契约。如下所述,此类可以作为全局验证器插入Spring MVC。
默认情况下,当在类路径上检测到Bean验证提供程序(如Hibernate Validator)时,使用@EnableWebMvc或<mvc:annotation-driven>会自动在Spring MVC中通过LocalValidatorFactoryBean注册Bean Validation支持。
注:
有时将LocalValidatorFactoryBean注入控制器或其他类是很方便的。最简单的方法是声明自己的@Bean并使用@Primary标记它,以避免与MVC Java配置提供的冲突。
如果更喜欢使用MVC Java配置中的那个,则需要从WebMvcConfigurationSupport覆盖mvcValidator方法,并声明该方法显式返回LocalValidatorFactory而不是Validator。
或者,可以配置自己的全局Validator实例:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public Validator getValidator(); {
// return "global" validator
}
}
并在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());
}
}
使用此最小配置,只要遇到@Valid或@Validated方法参数,它将由配置的验证器进行验证。 任何验证违规都将自动暴露为BindingResult中的错误,可作为方法参数访问,也可在Spring MVC HTML视图中呈现。
5. 拦截器
可以配置HandlerInterceptors或WebRequestInterceptors,然后将它们应用到所有传入的请求或限制为特定URL路径模式。
在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/*");
}
}
在XML中使用<mvc:interceptors>元素:
<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>
6. 内容协商
可以配置Spring MVC如何根据请求确定所请求的媒体类型。 可用选项是检查URL路径获取文件扩展名,检查“Accept”头,特定查询参数,或在没有请求任何内容时回退到默认内容类型。 默认情况下,首先检查请求URI中的路径扩展,然后检查“Accept”头。
如果相应的依赖项在类路径上,则MVC Java配置和MVC命名空间默认注册json,xml,rss,atom。 还可以明确地注册附加的路径媒体扩展到类型映射,并且还具有将它们列为白名单以将其作为用于RFD攻击检测的安全扩展的效果。
以下是通过MVC Java配置自定义内容协商选项的示例:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.mediaType("json", MediaType.APPLICATION_JSON);
}
}
在MVC命名空间中,<mvc:annotation-driven>元素具有content-negotiation-manager属性,该属性需要ContentNegotiationManager,ContentNegotiationManager可以使用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>
如果不使用MVC Java配置或MVC命名空间,则需要创建ContentNegotiationManager的实例并使用它来配置RequestMappingHandlerMapping以进行请求映射,并使用RequestMappingHandlerAdapter和ExceptionHandlerExceptionResolver进行内容协商。
提示:ContentNegotiatingViewResolver也可以使用ContentNegotiationManager进行配置,因此可以在Spring MVC中使用一个共享实例。
在更高级的情况下,配置多个ContentNegotiationManager实例可能会很有用,而这些实例又可能包含自定义ContentNegotiationStrategy实现。例如,可以使用ContentNegotiationManager配置ExceptionHandlerExceptionResolver,它始终将请求的媒体类型解析为“application/json”。或者,如果没有请求内容类型,可能希望插入具有某种逻辑的自定义策略来选择默认内容类型(例如XML或JSON)。
7. 视图控制器
这是定义ParameterizableViewController的快捷方式,该方法在调用时立即转发到视图。在视图生成响应之前,如果没有要执行的Java控制器逻辑,请在静态情况下使用它。
将对“/”的请求转发到Java中名为“home”的视图的示例:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home");
}
}
在XML中使用<mvc:view-controller>元素:
<mvc:view-controller path="/" view-name="home"/>
8. 视图解析器
MVC配置简化了视图解析器的注册。
以下是使用FreeMarker HTML模板配置内容协商视图解析的Java配置示例,以及Jackson作为JSON渲染的默认视图:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@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、Velocity、Tiles、Groovy Markup和script 模板也需要配置底层视图技术。
MVC名称空间提供专用元素。 例如使用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>
在Java配置中,只需添加相应的“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;
}
}
9. 资源服务
此选项允许ResourceHttpRequestHandler从任何资源位置列表中为特定URL模式的静态资源请求提供服务。 这提供了一种方便的方法来从Web应用程序根目录以外的位置提供静态资源,包括类路径上的位置。 cache-period属性可用于设置头部到期时间(Page Speed和YSlow等优化工具推荐1年),以便客户端更有效地使用它们。 处理器还正确地评估Last-Modified头(如果存在),以便适当地返回304状态代码,从而避免对于客户端已缓存的资源的不必要开销。 例如,要从Web应用程序根目录中的公共资源目录提供URL模式为/resources/**的资源请求,将使用:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/");
}
}
在XML中也一样:
<mvc:resources mapping="/resources/**" location="/public-resources/"/>
要在一年到期时提供这些资源,以确保最大限度地使用浏览器缓存并减少浏览器发出的HTTP请求:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/public-resources/").setCachePeriod(31556926);
}
}
在XML中:
<mvc:resources mapping="/resources/**" location="/public-resources/" cache-period="31556926"/>
有关更多详细信息,请参阅静态资源的HTTP缓存支持。
- mapping属性必须是SimpleUrlHandlerMapping可以使用的Ant模式,
- location属性必须指定一个或多个有效的资源目录位置。 可以使用逗号分隔的值列表指定多个资源位置。 将按指定的顺序检查指定的位置是否存在任何给定请求的资源。 例如,要启用来自Web应用程序根目录和来自类路径上任何jar中的/META-INF/public-web-resources/的已知路径的资源,请使用:
@EnableWebMvc
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/", "classpath:/META-INF/public-web-resources/");
}
}
在XML中:
<mvc:resources mapping="/resources/**" location="/, classpath:/META-INF/public-web-resources/"/>
在提供可能在部署新版本的应用程序时更改的资源时,建议将版本字符串合并到用于请求资源的映射模式中,以便可以强制客户端请求新部署的应用程序资源版本。对版本化URL的支持已经内置于框架中,可以通过在资源处理器上配置资源链来启用。该链包含一个ResourceResolver实例,后跟一个或多个ResourceTransformer实例。它们可以一起提供任意解析和资源转换。
可以使用不同的策略配置内置的VersionResourceResolver。例如,FixedVersionStrategy可以使用属性,日期或其他作为版本。 ContentVersionStrategy使用根据资源内容计算的MD5哈希值(称为“指纹识别”URL)。请注意,VersionResourceResolver在提供资源时会自动将已解析的版本字符串用作HTTP ETag头值。
ContentVersionStrategy是一个很好的默认选择,除非它无法使用(例如使用JavaScript模块加载器)。可以针对不同的模式配置不同的版本策略,如下所示。还要记住,基于计算内容的版本很昂贵,因此应该在生产中启用资源链缓存。
Java配置示例;
@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示例:
<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>
为了使上述工作正常,应用程序还必须使用版本展示URL。最简单的方法是配置ResourceUrlEncodingFilter,它包装响应并覆盖其encodeURL方法。这将适用于JSP,FreeMarker,Velocity以及调用响应encodeURL方法的任何其他视图技术。或者,应用程序也可以直接注入和使用ResourceUrlProvider bean,它使用MVC Java配置和MVC命名空间自动声明。
WebJarsResourceResolver也支持Webjars,当"org.webjars:webjars-locator"库在classpath上时会自动注册。此解析器允许资源链从HTTP GET请求解析版本无关的库“GET /jquery/jquery.min.js”将返回资源“/jquery/1.2.0/jquery.min.js”。它还可以通过在模板中重写资源URL<script src="/jquery/jquery.min.js"/> -> <script src="/jquery/1.2.0/jquery.min.js”/>来工作。
10. 默认Servlet
这允许将DispatcherServlet映射到"/"(从而覆盖容器的默认Servlet的映射),同时仍允许容器的默认Servlet处理静态资源请求。它配置DefaultServletHttpRequestHandler,其URL映射为“/**”,并且相对于其他URL映射具有最低优先级。
此处理器将所有请求转发到默认Servlet。因此,重要的是它在所有URL HandlerMapping中顺序保持最后。如果使用<mvc:annotation-driven>,或者如果要设置自己的自定义HandlerMapping实例,请确保将其order属性设置为低于DefaultServletHttpRequestHandler(Integer.MAX_VALUE)的值。
要使用默认设置启用该功能,请使用:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@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,或者在默认Servlet名称未知的情况下使用了不同的Servlet容器,则必须显式提供默认的Servlet名称,如下例所示:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
或者用XML:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
11. 路径匹配
这允许自定义与URL映射和路径匹配相关的各种设置。 有关各个选项的详细信息,请查看PathMatchConfigurer API。
以下是Java配置中的示例:
@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() {
//...
}
}
在XML中也一样,使用<mvc:path-matching>元素:
<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"/>
12. 消息转换器
如果想要替换Spring MVC创建的默认转换器,或者如果只想自定义它们或者将其他转换器添加到默认转换器中,则可以通过覆盖configureMessageConverters()来实现HttpMessageConverter的自定义。
下面是一个示例,它使用自定义的ObjectMapper而不是默认的ObjectMapper添加Jackson JSON和XML转换器:
@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()));
}
}
在此示例中,Jackson2ObjectMapperBuilder用于为MappingJackson2HttpMessageConverter和MappingJackson2XmlHttpMessageConverter创建通用配置,并启用缩进、自定义日期格式和jackson-module-parameters-names的注册,增加了对访问参数名称的支持(Java 8中添加的功能)。
注:使用Jackson XML支持启用缩进除了jackson-dataformat-xml之外还需要woodstox-core-asl依赖。
其他可用的Jackson模块:
- jackson-datatype-money:支持javax.money类型(非官方模块)
- jackson-datatype-hibernate:支持Hibernate特定的类型和属性(包括延迟加载方面)
也可以在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"/>
13. 使用MVC Java配置进行高级自定义
从上面的示例中可以看出,MVC Java配置和MVC命名空间提供了更高级别的构造,这些构造不需要深入了解创建的底层bean。相反,它可以帮助我们专注于应用程序需求。但是,在某些时候可能需要更细粒度的控制,或者可能只是希望了解底层配置。
实现更细粒度控制的第一步是查看创建的基础bean。在MVC Java配置中,可以在WebMvcConfigurationSupport中看到javadoc和@Bean方法。此类中的配置将通过@EnableWebMvc注解自动导入。实际上,如果打开@EnableWebMvc,可以看到@Import语句。
更精细控制的下一步是在WebMvcConfigurationSupport中创建的bean之一上自定义属性,或者提供自己的实例。这需要两件事:
- 删除@EnableWebMvc注解以防止导入
- 然后从DelegatingWebMvcConfiguration扩展,这是WebMvcConfigurationSupport的子类
这是一个例子:
@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
}
}
应用程序应该只有一个配置扩展DelegatingWebMvcConfiguration或一个@EnableWebMvc注释类,因为它们都注册相同的底层bean。
以这种方式修改bean不会阻止您使用本节前面所示的任何更高级别的构造。 WebMvcConfigurerAdapter子类和WebMvcConfigurer实现仍在使用中。
14. 使用MVC命名空间进行高级自定义
使用MVC命名空间对创建的配置进行细粒度控制会有点困难。
如果确实需要这样做,而不是复制它提供的配置,请考虑配置BeanPostProcessor,以检测要按类型自定义的bean,然后根据需要修改其属性。 例如:
@Component
public class MyPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
// Modify properties of the adapter
}
}
}
请注意,MyPostProcessor需要包含在<component scan />中才能被检测到,或者可以使用XML bean声明显式声明它。