21.16.10 回到默认的Servlet来提供资源
这样的配置可以把DispatcherServlet对象映射到”/”(这样就覆盖了web容器的默认Servlet的映射),同时,静态资源的请求依然可以被容器的默认Servlet所处理。它会配置一个带有”/**”的URL映射的DefaultServletHttpRequestHandler,对于其他的URL映射来说,其具有最低优先级。
这个handler会forward所有请求到默认Servlet。因此,将它放置于其他URL HandlerMappings的最后是很重要的。如果你使用<mvc:annotation_driven>或者你设置了自定的HandlerMapping实例,确认设置了低于DefaultServletHttpRequestHandler的order属性值(Integer.MAX_VALUE)。
为了启用这个特性,可以使用如下设置:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter{
@Override
public voidconfigureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
或者在XML中如下配置:
<mvc:default-servlet-handler/>
请注意,覆盖了”/”的Servlet映射后,默认Servlet的RequestDispatcher就必须根据名字而不是路径来进行检索。DefaultServletHttpRequestHandler会会使用主流Servlet容器的名字(Tomcat,Jetty,GlassFish,JBoss,Resin,WebLogic,WebSphere)在启动时自动检测容器的默认Servlet。如果默认Servlet被配置成不同的名字,或者使用了某个不知名的非主流容器,那就必须显式地指定默认Servlet的名字了,如下例:
@Configuration
@EnableWebMvc
public class WebConfig extendsWebMvcConfigurerAdapter {
@Override
public voidconfigureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable("myCustomDefaultServlet");
}
}
或者在XML中,这样配置:
<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>
21.16.11 路径匹配
这个配置可以自定义关于URL映射和路径匹配的很多选项。关于某些独立选项的配置详情,请参阅PathMatchConfigurer 的API。
下方是用Java config配置的例子:
@Configuration
@EnableWebMvc
public class WebConfig extendsWebMvcConfigurerAdapter {
@Override
public voidconfigurePathMatch(PathMatchConfigurer configurer) {
configurer
.setUseSuffixPatternMatch(true)
.setUseTrailingSlashMatch(false)
.setUseRegisteredSuffixPatternMatch(true)
.setPathMatcher(antPathMatcher())
.setUrlPathHelper(urlPathHelper());
}
@Bean
public UrlPathHelperurlPathHelper() {
//...
}
@Bean
public PathMatcherantPathMatcher() {
//...
}
}
使用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"/>
21.16.12 MessageConverters(消息转换器)
如果你想要替换Spring MVC创建的默认转换器时,可以在Java config方式中,通过覆写configureMessageCoonverters()方法来定制HttpMessageConverter。或者,当你想要自定义转换器或添加额外的转换器到默认的转换器上时,可以覆写extendMessageConverters()来实现。
下面的例子展示了使用一个定制的ObjectMapper而不是默认的转换器来添加jackson JSON和XML的转换器:
@Configuration
@EnableWebMvc
public class WebConfiguration extendsWebMvcConfigurerAdapter {
@Override
public voidconfigureMessageConverters(List<HttpMessageConverter<?>>converters) {
Jackson2ObjectMapperBuilder builder = newJackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
.modulesToInstall(newParameterNamesModule());
converters.add(newMappingJackson2HttpMessageConverter(builder.build()));
converters.add(newMappingJackson2XmlHttpMessageConverter(builder.xml().build()));
}
}
在此例中,Jackson2ObjectMapperBuilder被用来为MappingJackson2HttpMessageConverter和MappingJackson2XmlHttpMessageConverter创建通用的配置,包括了一个自定义的日期格式并注册了jackson-module-parameter-names,它可以用来访问参数名(Java 8的新特性)。
请注意:
为了支持Jackson XML的缩进,除了jackson-dataformat-xml以外,还需要woodstox-core-asl的支持。
关于Jackson的其他的比较有趣模组也是可用的:
1. jackson-datatype-money:支持javax.money类型(非官方模组)
2. Jackson-datatype-hibernate:支持Hibernate特定的类型和属性(包括了lazy-loading方面的支持)
同样的,也可以在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"/>
21.16.13 使用MVC Java Config进行进阶定制
就如你见到的之前的例子那样,MVC Java config和MVC namespace提供了更高等级的架构,并且不需要了解为你创建的bean的更深层次的知识。这样能让你把注意力集中在你应用的需求上。然而,在某些情况下,你可能需要更细致的控制,或者想了解配置背后的知识。
为了更细致的控制它,第一步就是了解为你创建的那些bean。在MVC Javaconfig中,你可以看看javadocs和在WebMvcConfigurationSupport类中的@Bean方法。这个类中的配置会通过@EnableWebMvc注解自动地导入。事实上,如果你打开@EnableWebMvc你就能看见@Import声明。
下一步,是定制在WebMvcConfigurationSupport中的某个bean的属性,或者,让它提供一个你自己的实例。这包括两件事——去除@EnableWebMvc注解来避免导入的操作,并从DelegatingWebMvcConfiguration处继承,它是WebMvcConfiguratioonSupport的子类,见下例:
@Configuration
public class WebConfig extendsDelegatingWebMvcConfiguration {
@Override
public voidaddInterceptors(InterceptorRegistry registry){
// ...
}
@Override
@Bean
publicRequestMappingHandlerAdapter requestMappingHandlerAdapter() {
//创建一个适配器,或者让父类来创建它
//然后,定制这个适配器的某个属性
}
}
小提示:
继承自DelegatingWebMvcConfiguration类,或者单个@EnableWebMvc注解了的类的配置在应用中只能有一个。因为它们注册相同的底层bean。修改这些bean并不会让你不能使用此章节之前展示过的那些高等级架构的配置。WebMvcConfigurerAdapter的子类和WebMvcConfigurer的实现还是会被使用。
21.16.14 使用MVC namespace进行进阶定制
使用命名空间来进行更细致的控制则会更难一些。
如果你确实要脱离Spring MVC所提供的配置来这么干,可以考虑配置用来根据类型来检测你想配置的bean的BeanPostProcessor类来实现,然后来修改它的属性,如下例:
@Component
public class MyPostProcessor implements BeanPostProcessor{
public ObjectpostProcessBeforeInitialization(Object bean, String name) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
// Modify properties of the adapter
}
}
}
请注意,MyPostProcessor需要使用<componentscan/>来把其包含在内,这样才能检测到它,或者你可以在XML的bean声明中显式的声明上它。