79. Spring MVC

Spring Boot 有许多启动器,其中包括 Spring MVC。请注意,一些 Starter 者包括对 Spring MVC 的依赖,而不是直接包含它。本部分回答有关 Spring MVC 和 Spring Boot 的常见问题。

79.1 编写 JSON REST 服务

默认情况下,只要 Jackson2 在 Classpath 上,Spring Boot 应用程序中的任何 Spring @RestController都应渲染 JSON 响应,如以下示例所示:

@RestController
public class MyController {

	@RequestMapping("/thing")
	public MyThing thing() {
			return new MyThing();
	}

}

只要 Jackson_2 可以将MyThing序列化(对于普通的 POJO 或 Groovy 对象为 true),则默认情况下localhost:8080/thing为其提供 JSON 表示。请注意,在浏览器中,有时可能会看到 XML 响应,因为浏览器倾向于发送更喜欢 XML 的接受 Headers。

79.2 编写 XML REST 服务

如果 Classpath 上具有 Jackson XML extensions(jackson-dataformat-xml),则可以使用它来渲染 XML 响应。我们用于 JSON 的先前示例可以正常工作。要使用 Jackson XML 渲染器,请将以下依赖项添加到您的项目中:

<dependency>
	<groupId>com.fasterxml.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

如果无法使用 Jackson 的 XML extensions,则使用 JAXB(JDK 中默认提供),另外要求将MyThing标注为@XmlRootElement,如以下示例所示:

@XmlRootElement
public class MyThing {
	private String name;
	// .. getters and setters
}

要使服务器渲染 XML 而不是 JSON,您可能必须发送Accept: text/xmlHeaders(或使用浏览器)。

79.3 自定义 Jackson ObjectMapper

Spring MVC(Client 端和服务器端)使用HttpMessageConverters来协商 HTTP 交换中的内容转换。如果 Jackson 在 Classpath 中,则您已经获得Jackson2ObjectMapperBuilder提供的默认转换器,该转换器的实例已为您自动配置。

ObjectMapper(对于 Jackson XML 转换器,则为XmlMapper)实例(默认情况下创建)具有以下自定义属性:

  • MapperFeature.DEFAULT_VIEW_INCLUSION已禁用

  • DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES已禁用

  • SerializationFeature.WRITE_DATES_AS_TIMESTAMPS已禁用

Spring Boot 还具有一些功能,可以更轻松地自定义此行为。

您可以使用环境配置ObjectMapperXmlMapper实例。Jackson 提供了一套广泛的简单的开/关功能,可用于配置其处理的各个方面。在六个枚举(在 Jackson 中)中描述了这些功能,这些枚举 Map 到环境中的属性:

EnumPropertyValues
com.fasterxml.jackson.databind.DeserializationFeaturespring.jackson.deserialization.<feature_name>true , false
com.fasterxml.jackson.core.JsonGenerator.Featurespring.jackson.generator.<feature_name>true , false
com.fasterxml.jackson.databind.MapperFeaturespring.jackson.mapper.<feature_name>true , false
com.fasterxml.jackson.core.JsonParser.Featurespring.jackson.parser.<feature_name>true , false
com.fasterxml.jackson.databind.SerializationFeaturespring.jackson.serialization.<feature_name>true , false
com.fasterxml.jackson.annotation.JsonInclude.Includespring.jackson.default-property-inclusionalways , non_null , non_absent , non_default , non_empty

例如,要启用漂亮打印,请设置spring.jackson.serialization.indent_output=true。注意,由于使用了relaxed bindingindent_output的情况不必与相应的枚举常量INDENT_OUTPUT的情况匹配。

这种基于环境的配置将应用于自动配置的Jackson2ObjectMapperBuilder bean,并应用于使用构建器创建的任何 Map 器,包括自动配置的ObjectMapper bean。

上下文的Jackson2ObjectMapperBuilder可以由一个或多个Jackson2ObjectMapperBuilderCustomizer bean 进行自定义。可以对此类定制器 bean 进行排序(Boot 自己的定制器的 Sequences 为 0),从而可以在 Boot 定制之前和之后应用其他定制。

类型为com.fasterxml.jackson.databind.Module的任何 bean 都会自动向自动配置的Jackson2ObjectMapperBuilder注册,并应用于它创建的ObjectMapper实例。当您向应用程序中添加新功能时,这提供了一种用于贡献自定义模块的全局机制。

如果要完全替换默认的ObjectMapper,请定义该类型的@Bean并将其标记为@Primary,或者,如果您更喜欢基于构建器的方法,请定义Jackson2ObjectMapperBuilder @Bean。请注意,无论哪种情况,这样做都会禁用ObjectMapper的所有自动配置。

如果您提供任何MappingJackson2HttpMessageConverter类型的@Beans,它们将替换 MVC 配置中的默认值。此外,还提供了HttpMessageConverters类型的便捷 bean(如果使用默认的 MVC 配置,则始终可用)。它提供了一些有用的方法来访问默认的和用户增强的消息转换器。

有关更多详细信息,请参见“ 第 79.4 节“自定义@ResponseBody 渲染””部分和WebMvcAutoConfiguration源代码。

79.4 自定义@ResponseBody 渲染

Spring 使用HttpMessageConverters渲染@ResponseBody(或@RestController的响应)。您可以通过在 Spring Boot 上下文中添加适当类型的 bean 来贡献额外的转换器。如果您添加的 bean 的类型无论如何都是默认包含的(例如MappingJackson2HttpMessageConverter表示 JSON 转换),它将替换默认值。提供了HttpMessageConverters类型的便捷 bean,如果使用默认的 MVC 配置,它将始终可用。它有一些有用的方法来访问默认的和用户增强的消息转换器(例如,如果要手动将它们注入到自定义RestTemplate中,则可能会很有用)。

与正常的 MVC 用法一样,您提供的任何WebMvcConfigurer bean 也可以通过覆盖configureMessageConverters方法来贡献转换器。但是,与普通的 MVC 不同,您只能提供所需的其他转换器(因为 Spring Boot 使用相同的机制来提供其默认值)。最后,如果您通过提供自己的@EnableWebMvc配置选择退出 Spring Boot 默认 MVC 配置,则可以完全控制并通过使用WebMvcConfigurationSupport中的getMessageConverters手动进行所有操作。

有关更多详细信息,请参见WebMvcAutoConfiguration源代码。

79.5 处理分段文件上传

Spring Boot 包含 Servlet 3 javax.servlet.http.Part API 以支持上传文件。默认情况下,Spring Boot 用单个请求将 Spring MVC 配置为每个文件最大大小为 1MB,最大文件数据为 10MB。您可以使用MultipartProperties类中公开的属性覆盖这些值,存储中间数据的位置(例如,存储到/tmp目录)以及将数据刷新到磁盘的阈值。例如,如果要指定文件不受限制,请将spring.servlet.multipart.max-file-size属性设置为-1

当您想在 Spring MVC 控制器处理程序方法中接收 Multipart 编码的文件数据作为@RequestParamComments 类型MultipartFile的参数时,Multipart 支持会很有帮助。

有关更多详细信息,请参见MultipartAutoConfiguration源。

Note

建议使用容器的内置支持进行分段上传,而不要引入其他依赖项,例如 Apache Commons File Upload。

79.6 关闭 Spring MVC DispatcherServlet

默认情况下,所有内容均从应用程序的根目录(/)提供。如果您希望 Map 到其他路径,则可以如下配置:

spring.mvc.servlet.path=/acme

如果您还有其他 servlet,则可以为每个 servlet 声明ServletServletRegistrationBean类型的@Bean,Spring Boot 会将它们透明地注册到容器中。因为 servlet 是通过这种方式注册的,所以可以将它们 Map 到DispatcherServlet的子上下文而无需调用它。

自己配置DispatcherServlet是不寻常的,但如果确实需要配置,则还必须提供DispatcherServletPath类型的@Bean以提供自定义DispatcherServlet的路径。

79.7 关闭默认的 MVC 配置

完全控制 MVC 配置的最简单方法是为自己的@Configuration提供@EnableWebMvc注解。这样做会使您掌握所有 MVC 配置。

79.8 自定义 ViewResolvers

ViewResolver是 Spring MVC 的核心组件,将@Controller中的视图名称转换为实际的View实现。请注意,ViewResolvers主要用于 UI 应用程序,而不是 REST 风格的服务(View不用于渲染@ResponseBody)。 ViewResolver的实现有很多可供选择,而 Spring 本身并未就应该使用哪个实现提出意见。另一方面,Spring Boot 会根据您在 Classpath 和应用程序上下文中找到的内容为您安装一两个。 DispatcherServlet使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器直到得到结果,因此,如果添加自己的解析器,则必须知道解析器的 Sequences 和添加位置。

WebMvcAutoConfiguration将以下ViewResolvers添加到您的上下文中:

  • InternalResourceViewResolver名为“ defaultViewResolver”。此代码查找可以使用DefaultServlet渲染的物理资源(包括静态资源和 JSP 页面,如果使用的话)。它在视图名称上应用前缀和后缀,然后在 Servlet 上下文中查找具有该路径的物理资源(默认值均为空,但可通过spring.mvc.view.prefixspring.mvc.view.suffix进行外部配置访问)。您可以通过提供相同类型的 bean 覆盖它。

  • BeanNameViewResolver名为“ beanNameViewResolver”。这是视图解析器链的有用成员,可以拾取与要解析的View同名的所有 bean。不必重写或替换它。

  • 仅当实际存在View类型的 Bean 时,才添加名为ContentNegotiatingViewResolver的“ viewResolver”。这是一个“主”解析器,委派给所有其他解析器,并尝试查找与 Client 端发送的“ Accept” HTTP Headers 匹配的内容。您可能想学习有用的关于 ContentNegotiatingViewResolver 的博客以了解更多信息,也可以查看源代码以获取详细信息。您可以通过定义一个名为'viewResolver'的 bean 来关闭自动配置的ContentNegotiatingViewResolver

  • 如果您使用 Thymeleaf,则还有一个ThymeleafViewResolver,名为“ thymeleafViewResolver”。它通过在视图名称前后加上前缀和后缀来查找资源。前缀为spring.thymeleaf.prefix,后缀为spring.thymeleaf.suffix。前缀和后缀的值分别默认为“ classpath:/ templates /”和“ .html”。您可以通过提供同名的 bean 来覆盖ThymeleafViewResolver

  • 如果使用 FreeMarker,则还有一个FreeMarkerViewResolver名为“ freeMarkerViewResolver”。它通过在视图名称前加上前缀和后缀来在加载程序路径(外部化为spring.freemarker.templateLoaderPath且默认值为“ classpath:/ templates /”)中查找资源。前缀外部化为spring.freemarker.prefix,后缀外部化为spring.freemarker.suffix。前缀和后缀的默认值分别为空和'.ftl'。您可以通过提供同名的 bean 来覆盖FreeMarkerViewResolver

  • 如果您使用 Groovy 模板(实际上,如果groovy-templates在 Classpath 上),则您也有一个GroovyMarkupViewResolver,名为“ groovyMarkupViewResolver”。它通过在视图名称前加上前缀和后缀(扩展为spring.groovy.template.prefixspring.groovy.template.suffix)来在加载程序路径中查找资源。前缀和后缀分别具有默认值'classpath:/ templates /'和'.tpl'。您可以通过提供同名的 bean 来覆盖GroovyMarkupViewResolver

有关更多详细信息,请参见以下部分: