Spring 4 官方文档学习(十一)Web MVC 框架之配置Spring MVC
内容列表:
- 启用MVC Java config 或 MVC XML namespace
- 修改已提供的配置
- 类型转换和格式化
- 校验
- 拦截器
- 内容协商
- View Controllers
- View Resolvers
- 服务于资源
- 回滚到默认的Servlet
- Path Matching - 路径匹配
- Message Converters - 消息转换器
- MVC Java config中的高级定制
- MVC namespace中的高级定制
在前面的文档中讲解了Spring MVC的特殊beans,以及DispatcherServlet使用的默认实现。在本部分,你会学习两种额外的方式来配置Spring MVC。分别是:MVC Java config 和 MVC XML namespace。
原文:
Section 22.2.1, “Special Bean Types In the WebApplicationContext” and Section 22.2.2, “Default DispatcherServlet Configuration” explained about Spring MVC’s special beans and the default implementations used by the
DispatcherServlet
.
MVC Java config 和 MVC namespace,提供了类似的默认配置,都覆盖了DispatcherServlet的默认配置。其目标是①让多数应用免于创建同样的配置,还是②提供更高级的构建来配置Spring MVC,不需要底层配置的相关知识。
你可以按照你的爱好来选择MVC Java config 或 MVC namespace。只是,在后面你会发现,使用MVC Java config,更容易发现底层的配置,从而可以对创建好的Spring MVC beans做出更细化的定制。
现在让我们开始吧。
1、启用MVC Java config 或 MVC XML namespace
想要启用MVC Java config,只需要将@EnableWebMvc添加到你的一个@Configuration class即可。
@Configuration @EnableWebMvc public class WebConfig { }
或者在XML中,需要在你的DispatcherServlet context (或你的root context -- 如果没有定义DispatcherServlet context的话)内使用 <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>
上面,已经注册了一个 RequestMappingHandlerMapping、一个RequestMappingHandlerAdapter、以及一个ExceptionHandlerExceptionResolver 以支持使用注解Controller的注解方法(如@RequestMapping、@ExceptionHandler)来处理request。
它还启用了如下内容:
- Spring 3 风格的类型转换 -- 通过一个ConversionService 实例 配合JavaBean PropertyEditors,用于Data Binding。
- 支持@NumberFormat注解通过ConversionService 来格式化Number字段。
- 支持使用@DateTimeFormat注解来格式化Date、Calendar、Long、以及Joda Time字段。
- 支持使用@Valid校验@Controller input -- 如果classpath中存在一个JSR-303 Provider。
- HttpMessageConverter支持@RequestMapping或@ExceptionHandler method的 @RequestBody method parameters和@ResponseBody method 返回值。 -- 比较长,其实就是支持handler (controller)的@RequestBody参数/@ResponseBody返回值。
下面是<mvc:annotation-driven> 设置的完整的HttpMessageConverter列表:
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 Section 22.16.12, “Message Converters” for more information about how to customize these default converters.
Jackson JSON 和 XML converters是使用Jackson2ObjectMapperBuilder创建的ObjectMapper实例们来创建的,其目的是提供一个更好的默认配置。
该builder定制了Jackson的默认properties:
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
is disabled.MapperFeature.DEFAULT_VIEW_INCLUSION
is disabled.
它还自动注册了下列很有名的模块 -- 如果能够在classpath中检测到的话:
- jackson-datatype-jdk7: support for Java 7 types like
java.nio.file.Path
. - jackson-datatype-joda: support for Joda-Time types.
- jackson-datatype-jsr310: support for Java 8 Date & Time API types.
- jackson-datatype-jdk8: support for other Java 8 types like
Optional
.
想要以Java形式定制默认的配置,你可以简单的实现WebMvcConfigurer接口,或者继承WebMvcConfigurerAdapter并重写需要的方法:
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { // Override configuration methods... }
想要定制 <mvc:annotation-driven>的默认配置,需要检查其attributes和其子元素。可以查看Spring MVC XML schema,或者使用IDE的自动完成功能来探索可用的attributes和子元素。
默认已注册了Number和Date类型的formatters,支持@NumberFormat和@DateTimeFormat注解。 还注册了对于Joda Time格式化库的完全支持 -- 需要在classpath中有Joda Time。想要注册自定义的formatters和converters,重写addFormatters方法即可:
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addFormatters(FormatterRegistry registry) { // Add formatters and/or converters } }
在MVC namespace中,<mvc:annotation-driven>会应用同样的默认设置。如果想注册自己的formatters和converters,只需要提供一个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>
See Section 9.6.4, “FormatterRegistrar SPI” and the
FormattingConversionServiceFactoryBean
for more information on when to use FormatterRegistrars.
Spring提供了一个Validator接口,可被用于在应用的所有layers上的校验。在Spring MVC中,你可以将其配置成一个全局的Validator实例,用于所有@Valid或@Validated controller method argument的地方,和/或一个Controller内局部的Validator,通过一个@InitBinder方法。 全局的和局部的validator实例们可以组合校验。
Spring还支持 JSR-303/JSR-349 Bean Validation -- 通过LocalValidatorFactoryBean,LocalValidatorFactoryBean会将Spring的Validator接口适配到javax.validation.Validator。 该类可以被插入Spring MVC作为一个全局的validator,下面有讲。
使用@EnableWebMvc或 <mvc:annotation-driven>,会默认地在Spring MVC中自动注册Bean Validation支持 -- 通过LocalValidatorFactoryBean,前提是classpath中有一个Bean Validation Provider,如Hibernate Validator。
有时候,将LocalValidatorFactoryBean注入到controller或其他类中很方便。最简单的方法就是声明你自己的@Bean,并使用@Primary以避免与MVC Java config提供的那个发送冲突。
如果你更喜欢MVC Java config提供的那个,你会需要重写WebMvcConfigurationSupport的mvcValidator(),并声明方法显式地返回LocalValidatorFactory而非Validator。详见 Section 22.16.13, “Advanced Customizations with MVC Java Config”。
或者,你可以配置自己的全局 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>
想要联合全局的和局部的validation,只需要简单地添加一个或多个local validator(s):
@Controller public class MyController { @InitBinder protected void initBinder(WebDataBinder binder) { binder.addValidators(new FooValidator()); } }
使用这种最小化的配置,任何时间只要@Valid或@Validated method argument遇到了,就会被配置好的validators校验。任何校验都会自动的被暴露成BindingResult中的errors,可被方法参数访问,在Spring MVC HTML views中也是可渲染的。 -- 其实都是废话,就是说 method(..@Valid T t, BindingResult br)。
HandlerInterceptor 或 WebRequestInterceptor,可被用于所有incoming requests 或 特定的URL path patterns。
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>
你可以配置Spring MVC如何判断request中的请求媒体类型。可用的选项是:①检查URL路径中的文件扩展名,②检查Accept header,③特定的query parameter,④或回滚到默认的内容类型 -- 当什么都不请求时。 默认,先检查request URI中的扩展名,再检查Accept header。
MVC Java config和 MVC namespace 默认会注册 json、xml、rss、atom,前提是classpath中有相应的依赖。可以显式地注册额外的path extension-to-media类型映射。
下面是通过MVC Java config定制内容协商选项的例子:
@Configuration @EnableWebMvc public class WebConfig extends WebMvcConfigurerAdapter { @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.mediaType("json", MediaType.APPLICATION_JSON); } }
中MVC namespace中,<mvc:annotation-driven>元素有个 content-negotiation-manager attribute,它预期的是一个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 config 或 MVC namespace,你会需要创建一个ContentNegotiationManager实例,并用它来配置RequestMappingHandlerMapping -- 用于request mapping目的,以及配置RequestMappingHandlerAdapter 和 ExceptionHandlerExceptionResolver -- 用于内容协商目的。
注意,ContentNegotiatingViewResolver 现在也可以使用一个ContentNegotiationManager来配置,所以你可以使用一个共享的实例。
更多的情况下,配置多个ContentNegotiationManager实例(可能包含定制的ContentNegotiationStrategy实现)可能很有用。例如,你可以使用一个ContentNegotiationManager来配置ExceptionHandlerExceptionResolver,然后总是将请求的媒体类型处理成”application/json”。或者,你可能想插入一个定制的策略,如果没有内容类型被请求时,使用一些逻辑来选择默认的内容类型--如XML或JSON。
有一种简便的方式来定义一个ParameterizableViewController --当调用时会立即转发到一个view。一般用于静态案例。
例如,以Java形式将对”/”的请求转发至”home” view:
@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"/>
MVC config 简化了view resolvers的注册。
下面是一个Java config示例,配置了内容协商视图解决方案使用FreeMarker HTML 模板,还配置了Jackson作为默认JSON View:
@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和脚本模板,同样要求配置底层的view 技术。
MVC namespace提供了专用的元素。 例如,针对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 config中,只需要简单的添加相应的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; } }
该选项允许静态资源请求按照特定的URL pattern,由ResourceHttpRequestHandler来服务 -- 从Resource locations列表中的任意一个。这提供了一种便捷的方式来服务静态资源,不只是web app root的位置,还包括classpath (牛掰大了)。其cache-period property可以被用来设置失效headers (对于Page Speed and YSlow等工具来说,推荐设为1年),这样它们会被client更有效的使用。handler还会正确的evaluate Last-Modified header (如果有) -- 并在恰当的时候返回 304 status code,这样会避免不必要的重复资源获取。例如,想要使用 /resources/** 形式的URL pattern来请求 web root 下public-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/"/>
设定 1年有效期:
@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"/>
更多详见 Spring 4 官方文档学习(十一)Web MVC 框架之HTTP caching support 。
注意:mapping attribute 必须是一个Ant 模式的,这样才能被SimpleUrlHandlerMapping使用;location attribute 必须指定一个或多个有效的资源目录。 多个资源位置可以使用逗号间隔。指定的位置会按照指定的顺序被检查。例如,想要同时支持 web root 和classpath中任何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/"/>
当资源可能随着新版本的部署而发生改变时,建议在请求资源的mapping pattern中加入一个版本字符串,这样你可以强制客户端请求新部署版本的资源。 框架天然支持带版本的URLs,且可以通过配置resource handler的resource chain来启用。该chain由一个或多个ResourceResolver实例(伴有一个或多个ResourceTransformer实例)组成。它们一起可以为资源提供任意的resolution和transformation。
内置的VersionResourceResolver,可以被配置不同的策略。例如,一个FixedVersionStrategy可以使用一个property、一个date,或其他作为版本。一个ContentVersionStrategy 使用根据资源内容计算的MD5 hash(也被叫做fingerprinting URLs)作为版本。 注意,VersionResourceResolver会自动使用resolved version strings作为 HTTP ETag header的值。
ContentVersionStrategy是一个很好的默认选择,除非不能使用 (例如,当使用JavaScript 模块加载器时)。 你可以配置不同的版本策略。务必记住,基于内容计算的版本是很耗费系统资源的,因此,在生产模型中应该启用resource chain 缓存。
Java config 例子:
@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>
为了让上面的内容正常工作,应用必须在URLs中带有版本。 最简单的方式就是配置一个ResourceUrlEncodingFilter,它封装了response,并重写了其encodeURL method。在JSPs、FreeMarker、Velocity、和任何调用response encodeURL method的其他view技术中,都可以工作。或者,一个应用也可以注入和直接使用 ResourceUrlProvider bean,MVC Java config 和 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"/>
.
这允许将 DispatcherServlet 映射到 “/”(因此,覆盖了容器的default Servlet的映射),同时,仍然允许容器的default Servlet来处理静态资源请求。它配置了一个DefaultServletHttpRequestHandler,并映射到 “/**”,该映射具有最低的优先级。
该Handler 会将所有请求转发给default Servlet。因此,它在所有其他URL HandlerMappings中排名最后很重要(就是必须放在最后的意思)。当你使用<mvc:annotation-driven> 或 当你在设置你自己定制的HandlerMapping实例时,其order property的值应比DefaultServletHttpRequestHandler的值小,嗯嗯,后者是 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(); } }
或者,在XML中:
<mvc:default-servlet-handler/>
针对覆盖 “/” Servlet mapping的警告是:default Servlet 的 RequestDispatcher 必须通过name来获取,而非通过path。DefaultServletHttpRequestHandler 会在Servlet容器启动时试图自动探测其default Servlet -- 使用一个包含大多数已知Servlet容器的name列表(包括Tomcat、Jetty、GlassFish、JBoss、Resin、WebLogic、WebSphere) 。 如果default Servlet已经被配置了不同的name,或者如果使用了一个不同的Servlet容器(不知其default Servlet name),那么必须按照如下方式来提供default Servlet name:
@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"/>
这里允许针对URL mapping和path matching 自定义不同的设置。 针对每个选项的详细信息,请检查PathMatchConfigurer API。
下面是一个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() { //... } }
或在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"/>
针对HttpMessageConverter的定制,可以通过重写configureMessageConverters() 或重写extendMessageConverters()来实现,二者不同之处在于:前者会取代Spring MVC创建的默认转换器,后者则是添加额外的转换器。(个人推荐后者)
下面是一个取代默认设置的例子:
@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-parameter-names的注册(会添加访问parameter names的支持 -- Java 8中的功能)。
启用Jackson XML的缩进支持,需要jaskson-dataformat-xml 还有 woodstox-core-asl 依赖。
其他有趣的可用Jackson模块包括:
- jackson-datatype-money: support for
javax.money
types (unofficial module) - jackson-datatype-hibernate: support for Hibernate specific types and properties (including lazy-loading aspects)
在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"/>
如果你在前面的例子中看到的一样,MVC Java config 和 MVC namespace 都提供了高级别的指令 -- 不需要高深的底层知识。相反,它会帮助你将精力放在应用上面。然而,某些时候你的确可能需要更细化的控制,或者你只是简单地想理解底层的配置。
迈向更细化的控制的第一步,就是查看底层的beans。在MVC Java config 中你可以看到javadocs 和 WebMvcConfigurationSupport中的@Bean methods。 通过@EnableWebMvc注解,可以自动导入该类中的配置。 事实上,你点开@EnableWebMvc 就可以看到 @Import语句。
第二步就是自定义下WebMvcConfigurationSupport创建的某个bean的一个property,或者,干脆提供你自己的实例。这需要两件事情:移除@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 class, 因为它们会注册相同的底层beans。
以这种方式修改beans,不会阻止你使用任何更高级别的方式 -- 就是前面讲述的那些方式。WebMvcConfigurerAdapter的子类们和WebMvcConfigurer实现们 仍然被使用。
好吧,MVC namespace中更细化的控制有点麻烦。
建议配置一个 BeanPostProcessor,用它来侦探你想定制的bean,然后修改器properties即可。例如:
@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定义。
官方文档链接:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-config
posted on 2016-12-11 22:01 LarryZeal 阅读(11107) 评论(0) 编辑 收藏 举报