MVC Java配置和MVC XML命名空间提供了适合大多数应用程序的默认配置,并提供了一个配置API来定制它。

一、启用 MVC 配置

在Java配置中,你可以使用@EnableWebMvc注解来启用MVC配置,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig {}

在XML配置中,你可以使用元素来启用MVC配置,如下例所示:

二、MVC 配置 API

在Java配置中,你可以实现WebMvcConfigurer接口,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {// Implement configuration methods...}

在XML中,你可以检查 的属性和子元素。你可以查看 Spring MVC XML schema 或使用IDE的代码补全功能来发现有哪些属性和子元素。

三、类型转换

默认情况下,各种数字和日期类型的 formatter 已被安装,同时还支持通过字段上的 @NumberFormat 和 @DateTimeFormat 进行定制。
要在 Java config 中注册自定义 formatter 和 converter,请使用以下方法:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {// ...}}

要在XML配置中做同样的事情,请使用以下方法:

默认情况下,Spring MVC 在解析和格式化日期值时考虑了请求的 Locale。这适用于日期被表示为字符串的 “input” 表单字段。然而,对于 “date” 和 “time” 表单字段,浏览器使用HTML规范中定义的固定格式。在这种情况下,日期和时间的格式化可以按以下方式定制:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addFormatters(FormatterRegistry registry) {DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();registrar.setUseIsoFormat(true);registrar.registerFormatters(registry);}}

四、校验

默认情况下,如果 Bean Validation` 在classpath上存在(例如Hibernate Validator),LocalValidatorFactoryBean 会被注册为全局 Validator,用于 @Valid 和 Validated 的 controller 方法参数。
在 Java 配置中,你可以自定义全局 Validator 实例,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic Validator getValidator() {// ...}}

下面的例子显示了如何在XML中实现同样的配置:

注意,你也可以在本地注册Validator实现,如下例所示:

@Controllerpublic class MyController {@InitBinderprotected void initBinder(WebDataBinder binder) {binder.addValidators(new FooValidator());}}

五、拦截器

在Java配置中,你可以注册拦截器来应用于传入的请求,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LocaleChangeInterceptor());registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");}}

下面的例子显示了如何在XML中实现同样的配置:

六、Content Type

你可以配置Spring MVC如何从请求中确定所请求的媒体类型(例如,Accept 头、URL路径扩展、查询参数,以及其他)。
默认情况下,只有`Accept` 头被检查。
如果你必须使用基于URL的内容类型解析,考虑使用查询参数策略而不是路径扩展。
在Java配置中,你可以自定义请求的 content type 解析,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configureContentNegotiation(ContentNegotiationConfigurer configurer) {configurer.mediaType("json", MediaType.APPLICATION_JSON);configurer.mediaType("xml", MediaType.APPLICATION_XML);}}

下面的例子显示了如何在XML中实现同样的配置:

json=application/jsonxml=application/xml

七、Message 转换器(Converter)

你可以通过写 configureMessageConverters()(替换Spring MVC创建的默认转换器)或覆写 extendMessageConverters()(自定义默认转换器或为默认转换器添加额外的转换器)在Java配置中定制 HttpMessageConverter。
下面的例子添加了XML和Jackson JSON转换器,用一个定制的 ObjectMapper 代替默认的:

@Configuration@EnableWebMvcpublic class WebConfiguration implements WebMvcConfigurer {@Overridepublic 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()));}}

在前面的例子中, Jackson2ObjectMapperBuilder 被用来为 MappingJackson2HttpMessageConverter 和 MappingJackson2XmlHttpMessageConverter 创建一个共同的配置,其中启用了缩进,自定义了日期格式,并注册了 jackson-module-parameter-names,这增加了对访问参数名称的支持(Java 8中增加的一个功能)。
这个 builder 定制了 Jackson 的默认属性,如下所示:

  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES 被禁用。
  • MapperFeature.DEFAULT_VIEW_INCLUSION 被禁用。

如果在classpath上检测到以下知名模块,它也会自动注册这些模块:

  • jackson-datatype-joda: 对Joda-Time类型的支持。
  • jackson-datatype-jsr310: 支持Java 8 Date 和 Time API类型。
  • jackson-datatype-jdk8: 支持其他Java 8类型,如 Optional。
  • jackson-module-kotlin: 支持Kotlin类和数据类(data classe)。

还有其他有趣的 Jackson 模块可用:

  • jackson-datatype-money: 支持 javax.money 类型(非官方模块)。
  • jackson-datatype-hibernate: 支持Hibernate特有的类型和属性(包括懒加载切面)。

下面的例子显示了如何在XML中实现同样的配置:

八、View Controller

这是一个定义ParameterizableViewController的快捷方式,当调用时立即转发到视图。你可以在静态情况下使用它,在视图生成响应之前没有Java controller 逻辑需要运行。
下面这个Java配置的例子将一个对/的请求转发给一个叫做home的视图:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/").setViewName("home");}}

下面的例子通过使用元素,实现了与前面的例子相同的事情,但使用了XML:

如果一个@RequestMapping方法被映射到任何HTTP方法的URL上,那么视图控制器就不能被用来处理同一个URL。这是因为通过URL与注解控制器的匹配被认为是一个足够强大的端点所有权的指示,所以405(METHOD_NOT_ALLOWED),415(UNSUPPORTED_MEDIA_TYPE),或类似的响应可以被发送到客户端以帮助调试。出于这个原因,我们建议避免将URL处理分割到一个注解控制器和一个视图控制器。

九、视图(View)解析器

MVC配置简化了视图解析器的注册。
下面的Java配置例子通过使用JSP和Jackson作为JSON渲染的默认 View 来配置内容协商的视图解析:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.enableContentNegotiation(new MappingJackson2JsonView());registry.jsp();}}

下面的例子显示了如何在XML中实现同样的配置:

然而,请注意,FreeMarker、Groovy Markup 和 script 模板也需要配置底层视图技术。 MVC命名空间提供了专用元素。下面的例子适用于FreeMarker:

在Java配置中,你可以添加相应的 Configurer bean,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configureViewResolvers(ViewResolverRegistry registry) {registry.enableContentNegotiation(new MappingJackson2JsonView());registry.freeMarker().cache(false);}@Beanpublic FreeMarkerConfigurer freeMarkerConfigurer() {FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();configurer.setTemplateLoaderPath("/freemarker");return configurer;}}

十、静态资源

这个选项提供了一个方便的方法,从基于 Resource 的位置列表中提供静态资源。
在下一个例子中,给定一个以 /resources 开头的请求,相对路径被用来寻找和提供相对于Web应用root下的 /public 或 /static 下classpath的静态资源。这些资源在未来一年内到期,以确保最大限度地利用浏览器的缓存,减少浏览器的HTTP请求。Last-Modified 信息是从 Resource#lastModified 中推导出来的,因此HTTP条件请求支持 “Last-Modified” header。
下面的列表显示了如何用Java配置来实现:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/public", "classpath:/static/").setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));}}

下面的例子显示了如何在XML中实现同样的配置:

resource handler 还支持 ResourceResolver 实现和 ResourceTransformer 实现的链,你可以用它们来创建一个处理优化资源的工具链。
你可以使用 VersionResourceResolver 来获取基于从内容计算的MD5哈希值、固定的应用程序版本或其他的版本资源URL。ContentVersionStrategy(MD5哈希值)是一个不错的选择—​但也有一些明显的例外,比如与模块加载器一起使用的JavaScript资源。
下面的例子显示了如何在Java配置中使用 VersionResourceResolver:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/resources/**").addResourceLocations("/public/").resourceChain(true).addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));}}

下面的例子显示了如何在XML中实现同样的配置:

然后你可以使用 ResourceUrlProvider 重写URL,并应用完整的解析器(resolver)和转换器链—​例如,插入版本。MVC配置提供了一个 ResourceUrlProvider bean,这样它就可以被注入到其他地方。你也可以用 ResourceUrlEncodingFilter 使重写透明化,用于 Thymeleaf、JSP、FreeMarker 和其他有依赖 HttpServletResponse#encodeURL 的URL标签。
注意,当同时使用 EncodedResourceResolver(例如,用于 serving gzipped 或 brotli 编码的资源)和 VersionResourceResolver 时,你必须按照这个顺序注册它们。这可以确保基于内容的版本总是在未编码文件的基础上被可靠地计算出来。
对于 WebJars 来说,像 /webjars/jquery/1.2.0/jquery.min.js 这样的版本化URL是推荐的、最有效的使用方式。相关的资源位置在Spring Boot中是开箱即配置的(也可以通过 ResourceHandlerRegistry 手动配置),不需要添加 org.webjars:webjars-locator-core 依赖。
像 /webjars/jquery/jquery.min.js 这样无版本的URL是通过 WebJarsResourceResolver 支持的,当 org.webjars:webjars-locator-core 库出现在classpath上时,它就会自动注册,代价是classpath扫描会减慢应用程序的启动。该解析器可以重写URL以包括jar的版本,也可以与传入的没有版本的URL相匹配—​例如,从 /webjars/jquery/jquery.min.js 到 /webjars/jquery/1.2.0/jquery.min.js。

十一、Default Servlet

Spring MVC允许将 DispatcherServlet 映射到 /(从而覆盖容器的默认Servlet的映射),同时仍然允许静态资源请求由容器的默认Servlet处理。它配置了一个 DefaultServletHttpRequestHandler,其URL映射为 /**,相对于其他URL映射,其优先级最低。
这个 handler 将所有请求转发到默认的Servlet。因此,它必须在所有其他URL HandlerMappings 的顺序中保持最后。如果你使用 ,情况就是这样。另外,如果你设置了你自己的自定义 HandlerMapping 实例,请确保将其 order 属性设置为低于 DefaultServletHttpRequestHandler 的值,即 Integer.MAX_VALUE。
下面的例子显示了如何通过使用默认设置来启用该功能:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}}

下面的例子显示了如何在XML中实现同样的配置:

重写/Servlet映射的注意事项是,默认Servlet的RequestDispatcher必须通过名称而不是路径来检索。DefaultServletHttpRequestHandler试图在启动时自动检测容器的默认Servlet,使用大多数主要Servlet容器(包括Tomcat、Jetty、GlassFish、JBoss、Resin、WebLogic和WebSphere)的已知名称列表。如果默认的Servlet被定制配置了不同的名字,或者如果使用的是不同的Servlet容器,而默认的Servlet名字未知,那么你必须明确地提供默认Servlet的名字,如下例所示:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable("myCustomDefaultServlet");}}

下面的例子显示了如何在XML中实现同样的配置:

十二、路径(Path)匹配

你可以自定义与路径匹配和处理URL有关的选项。
下面的例子显示了如何在Java配置中自定义路径匹配:

@Configuration@EnableWebMvcpublic class WebConfig implements WebMvcConfigurer {@Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {configurer.addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));}private PathPatternParser patternParser() {// ...}}

下面的例子显示了如何在XML配置中自定义路径匹配:

十三、高级Java配置

@启用WebMvc导入,其中:DelegatingWebMvcConfiguration
为Spring MVC应用程序提供默认的Spring配置。
检测并委托给 WebMvcConfigurer 实现来定制该配置。
对于高级模式,你可以去掉 @EnableWebMvc,直接从 DelegatingWebMvcConfiguration 扩展,而不是实现 WebMvcConfigurer,如下例所示:

@Configurationpublic class WebConfig extends DelegatingWebMvcConfiguration {// ...}

你可以保留WebConfig中现有的方法,但你现在也可以覆盖基类中的bean声明,而且你仍然可以在classpath上拥有任何数量的其他WebMvcConfigurer实现。

十四、高级 XML 配置

MVC命名空间没有高级模式。如果你需要在Bean上定制一个你无法以其他方式改变的属性,你可以使用Spring ApplicationContext 的 BeanPostProcessor 生命周期钩子,如下例所示:

@Componentpublic class MyPostProcessor implements BeanPostProcessor {public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {// ...}}

请注意,你需要将MyPostProcessor声明为一个Bean,可以在XML中明确声明,也可以通过声明让它被检测到。

大家好,我是Doker品牌的Sinbad,欢迎点赞和评论,您的鼓励是我们持续更新的动力!欢迎加微信进入技术群聊!