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/xml
Headers(或使用浏览器)。
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 还具有一些功能,可以更轻松地自定义此行为。
您可以使用环境配置ObjectMapper
和XmlMapper
实例。Jackson 提供了一套广泛的简单的开/关功能,可用于配置其处理的各个方面。在六个枚举(在 Jackson 中)中描述了这些功能,这些枚举 Map 到环境中的属性:
Enum | Property | Values |
---|---|---|
com.fasterxml.jackson.databind.DeserializationFeature | spring.jackson.deserialization.<feature_name> | true , false |
com.fasterxml.jackson.core.JsonGenerator.Feature | spring.jackson.generator.<feature_name> | true , false |
com.fasterxml.jackson.databind.MapperFeature | spring.jackson.mapper.<feature_name> | true , false |
com.fasterxml.jackson.core.JsonParser.Feature | spring.jackson.parser.<feature_name> | true , false |
com.fasterxml.jackson.databind.SerializationFeature | spring.jackson.serialization.<feature_name> | true , false |
com.fasterxml.jackson.annotation.JsonInclude.Include | spring.jackson.default-property-inclusion | always , non_null , non_absent , non_default , non_empty |
例如,要启用漂亮打印,请设置spring.jackson.serialization.indent_output=true
。注意,由于使用了relaxed binding,indent_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 编码的文件数据作为@RequestParam
Comments 类型MultipartFile
的参数时,Multipart 支持会很有帮助。
有关更多详细信息,请参见MultipartAutoConfiguration源。
Note
建议使用容器的内置支持进行分段上传,而不要引入其他依赖项,例如 Apache Commons File Upload。
79.6 关闭 Spring MVC DispatcherServlet
默认情况下,所有内容均从应用程序的根目录(/
)提供。如果您希望 Map 到其他路径,则可以如下配置:
spring.mvc.servlet.path=/acme
如果您还有其他 servlet,则可以为每个 servlet 声明Servlet
或ServletRegistrationBean
类型的@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.prefix
和spring.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.prefix
和spring.groovy.template.suffix
)来在加载程序路径中查找资源。前缀和后缀分别具有默认值'classpath:/ templates /'和'.tpl'。您可以通过提供同名的 bean 来覆盖GroovyMarkupViewResolver
。
有关更多详细信息,请参见以下部分: