Spring MVC
Spring Boot 有多个包含 Spring MVC 的启动器。 请注意,一些启动器包含对 Spring MVC 的依赖,而不是直接包含它。 本节回答有关 Spring MVC 和 Spring Boot 的常见问题。
编写 JSON REST 服务
只要 Jackson2 在类路径上,Spring Boot 应用程序中的任何 Spring @RestController
都应该默认渲染 JSON 响应,如下例所示:
-
Java
-
Kotlin
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@RequestMapping("/thing")
public MyThing thing() {
return new MyThing();
}
}
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
class MyController {
@RequestMapping("/thing")
fun thing(): MyThing {
return MyThing()
}
}
只要 MyThing
可以被 Jackson2 序列化(对于普通的 POJO 或 Groovy 对象来说都是如此),那么 localhost:8080/thing
默认会提供它的 JSON 表示。
请注意,在浏览器中,您有时可能会看到 XML 响应,因为浏览器倾向于发送优先选择 XML 的 accept 头。
编写 XML REST 服务
如果您的类路径上有 Jackson XML 扩展(jackson-dataformat-xml
),您可以使用它来渲染 XML 响应。
我们用于 JSON 的前一个示例也可以工作。
要使用 Jackson XML 渲染器,请将以下依赖项添加到您的项目中:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
如果 Jackson 的 XML 扩展不可用,而 JAXB 可用,则可以通过将 MyThing
注解为 @XmlRootElement
来渲染 XML,如下例所示:
-
Java
-
Kotlin
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class MyThing {
private String name;
// getters/setters ...
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
import jakarta.xml.bind.annotation.XmlRootElement
@XmlRootElement
class MyThing {
var name: String? = null
}
您需要确保 JAXB 库是项目的一部分,例如通过添加:
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
注意:要让服务器渲染 XML 而不是 JSON,您可能需要发送 Accept: text/xml
头(或使用浏览器)。
自定义 Jackson ObjectMapper
Spring MVC(客户端和服务器端)使用 HttpMessageConverters
来协商 HTTP 交换中的内容转换。
如果 Jackson 在类路径上,您已经获得了由 Jackson2ObjectMapperBuilder
提供的默认转换器,该构建器的实例会自动为您配置。
ObjectMapper
(或用于 Jackson XML 转换器的 XmlMapper
)实例(默认创建)具有以下自定义属性:
-
MapperFeature.DEFAULT_VIEW_INCLUSION
被禁用 -
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES
被禁用 -
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS
被禁用 -
SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS
被禁用
Spring Boot 还有一些功能可以更容易地自定义此行为。
您可以使用环境配置 ObjectMapper
和 XmlMapper
实例。
Jackson 提供了一套广泛的开/关功能,可用于配置其处理的各个方面。
这些功能在 Jackson 中的几个枚举中描述,这些枚举映射到环境中的属性:
枚举 | 属性 | 值 |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,要启用漂亮打印,请设置 spring.jackson.serialization.indent_output=true
。
请注意,由于使用了 宽松绑定,indent_output
的大小写不必与相应枚举常量的大小写匹配,即 INDENT_OUTPUT
。
这种基于环境的配置应用于自动配置的 Jackson2ObjectMapperBuilder
bean,并适用于使用构建器创建的任何映射器,包括自动配置的 ObjectMapper
bean。
上下文的 Jackson2ObjectMapperBuilder
可以通过一个或多个 Jackson2ObjectMapperBuilderCustomizer
bean 进行自定义。
这些自定义器 bean 可以排序(Boot 自己的自定义器顺序为 0),允许在 Boot 的自定义之前和之后应用额外的自定义。
任何类型为 Module
的 bean 都会自动注册到自动配置的 Jackson2ObjectMapperBuilder
中,并应用于它创建的任何 ObjectMapper
实例。
这为在向应用程序添加新功能时贡献自定义模块提供了一种全局机制。
如果您想完全替换默认的 ObjectMapper
,可以定义该类型的 @Bean
,或者如果您更喜欢基于构建器的方法,可以定义 Jackson2ObjectMapperBuilder
@Bean
。
在定义 ObjectMapper
bean 时,建议将其标记为 @Primary
,因为它将替换的自动配置的 ObjectMapper
是 @Primary
。
请注意,无论哪种情况,这样做都会禁用 ObjectMapper
的所有自动配置。
如果您提供任何类型为 MappingJackson2HttpMessageConverter
的 @Beans
,它们会替换 MVC 配置中的默认值。
此外,还提供了一个类型为 HttpMessageConverters
的便捷 bean(如果您使用默认的 MVC 配置,它始终可用)。
它有一些有用的方法来访问默认和用户增强的消息转换器。
有关更多详细信息,请参阅 自定义 @ResponseBody 渲染 部分和 WebMvcAutoConfiguration
源代码。
自定义 @ResponseBody 渲染
Spring 使用 HttpMessageConverters
来渲染 @ResponseBody
(或来自 @RestController
的响应)。
您可以通过在 Spring Boot 上下文中添加适当类型的 bean 来贡献额外的转换器。
如果您添加的 bean 的类型本来就会被默认包含(例如用于 JSON 转换的 MappingJackson2HttpMessageConverter
),它会替换默认值。
如果您使用默认的 MVC 配置,还提供了一个类型为 HttpMessageConverters
的便捷 bean,它始终可用。
它有一些有用的方法来访问默认和用户增强的消息转换器(例如,如果您想手动将它们注入到自定义的 RestTemplate
中,这可能很有用)。
与普通 MVC 用法一样,您提供的任何 WebMvcConfigurer
bean 也可以通过覆盖 configureMessageConverters
方法来贡献转换器。
但是,与普通 MVC 不同,您只能提供您需要的额外转换器(因为 Spring Boot 使用相同的机制来贡献其默认值)。
最后,如果您通过提供自己的 @EnableWebMvc
配置来选择退出默认的 Spring Boot MVC 配置,您可以通过使用 WebMvcConfigurationSupport
的 getMessageConverters
完全控制并手动完成所有操作。
有关更多详细信息,请参阅 WebMvcAutoConfiguration
源代码。
处理多部分文件上传
Spring Boot 采用 servlet 5 Part
API 来支持文件上传。
默认情况下,Spring Boot 配置 Spring MVC 时,每个文件的最大大小为 1MB,单个请求中的文件数据最大为 10MB。
您可以通过使用 MultipartProperties
类中公开的属性来覆盖这些值、中间数据存储的位置(例如,到 /tmp
目录)以及数据刷新到磁盘的阈值。
例如,如果您想指定文件大小不受限制,请将 spring.servlet.multipart.max-file-size
属性设置为 -1
。
当您想在 Spring MVC 控制器处理方法中接收多部分编码的文件数据作为类型为 MultipartFile
的 @RequestParam
注解参数时,多部分支持很有帮助。
有关更多详细信息,请参阅 MultipartAutoConfiguration
源代码。
注意:建议使用容器的内置多部分上传支持,而不是引入额外的依赖项,如 Apache Commons File Upload。
关闭 Spring MVC DispatcherServlet
默认情况下,所有内容都从应用程序的根目录(/
)提供服务。
如果您想映射到不同的路径,可以按如下方式配置:
-
Properties
-
YAML
spring.mvc.servlet.path=/mypath
spring:
mvc:
servlet:
path: "/mypath"
如果您有其他 servlet,您可以为每个 servlet 声明一个类型为 Servlet
或 ServletRegistrationBean
的 @Bean
,Spring Boot 将透明地将它们注册到容器中。
因为 servlet 是以这种方式注册的,所以它们可以映射到 DispatcherServlet
的子上下文,而不会调用它。
自己配置 DispatcherServlet
是不常见的,但如果您确实需要这样做,还必须提供一个类型为 DispatcherServletPath
的 @Bean
来提供自定义 DispatcherServlet
的路径。
关闭默认 MVC 配置
完全控制 MVC 配置的最简单方法是提供您自己的带有 @EnableWebMvc
注解的 @Configuration
。
这样做会将所有 MVC 配置交给您处理。
自定义 ViewResolvers
ViewResolver
是 Spring MVC 的核心组件,它将 @Controller
中的视图名称转换为实际的 View
实现。
请注意,视图解析器主要用于 UI 应用程序,而不是 REST 风格的服务(View
不用于渲染 @ResponseBody
)。
有许多 ViewResolver
的实现可供选择,Spring 本身对您应该使用哪些实现没有意见。
另一方面,Spring Boot 会根据它在类路径和应用程序上下文中找到的内容为您安装一个或两个。
DispatcherServlet
使用它在应用程序上下文中找到的所有解析器,依次尝试每个解析器,直到获得结果。
如果您添加自己的解析器,您必须注意顺序以及您的解析器添加的位置。
WebMvcAutoConfiguration
将以下 ViewResolver
bean 添加到您的上下文中:
-
一个名为 ‘defaultViewResolver’ 的
InternalResourceViewResolver
。 这个解析器定位可以使用DefaultServlet
渲染的物理资源(包括静态资源和 JSP 页面,如果您使用这些)。 它将前缀和后缀应用于视图名称,然后在 servlet 上下文中查找具有该路径的物理资源(默认值都为空,但可以通过spring.mvc.view.prefix
和spring.mvc.view.suffix
从外部配置访问)。 您可以通过提供相同类型的 bean 来覆盖它。 -
一个名为 ‘beanNameViewResolver’ 的
BeanNameViewResolver
。 这是视图解析器链中的一个有用成员,它会选择与正在解析的View
同名的任何 bean。 不应该需要覆盖或替换它。 -
一个名为 ‘viewResolver’ 的
ContentNegotiatingViewResolver
仅在实际上存在类型为View
的 bean 时添加。 这是一个复合解析器,委托给所有其他解析器,并尝试找到与客户端发送的 ‘Accept’ HTTP 头匹配的解析器。 有一个关于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
。 前缀和后缀的默认值分别为空和 ‘.ftlh’。 您可以通过提供相同名称的 bean 来覆盖FreeMarkerViewResolver
。 FreeMarker 变量可以通过定义类型为FreeMarkerVariablesCustomizer
的 bean 来自定义。 -
如果您使用 Groovy 模板(实际上,如果
groovy-templates
在您的类路径上),您还有一个名为 ‘groovyMarkupViewResolver’ 的GroovyMarkupViewResolver
。 它通过在视图名称周围添加前缀和后缀(外部化为spring.groovy.template.prefix
和spring.groovy.template.suffix
)在加载器路径中查找资源。 前缀和后缀的默认值分别为 ‘classpath:/templates/’ 和 ‘.tpl’。 您可以通过提供相同名称的 bean 来覆盖GroovyMarkupViewResolver
。 -
如果您使用 Mustache,您还有一个名为 ‘mustacheViewResolver’ 的
MustacheViewResolver
。 它通过在视图名称周围添加前缀和后缀来查找资源。 前缀是spring.mustache.prefix
,后缀是spring.mustache.suffix
。 前缀和后缀的值默认为 ‘classpath:/templates/’ 和 ‘.mustache’。 您可以通过提供相同名称的 bean 来覆盖MustacheViewResolver
。
有关更多详细信息,请参阅以下部分:
自定义 ‘whitelabel’ 错误页面
Spring Boot 安装了一个 ‘whitelabel’ 错误页面,如果您遇到服务器错误,您会在浏览器客户端中看到它(使用 JSON 和其他媒体类型的机器客户端应该看到带有正确错误代码的合理响应)。
注意:设置 server.error.whitelabel.enabled=false
可以关闭默认错误页面。
这样做会恢复您使用的 servlet 容器的默认值。
请注意,Spring Boot 仍然尝试解析错误视图,因此您可能应该添加自己的错误页面,而不是完全禁用它。
使用您自己的错误页面覆盖错误页面取决于您使用的模板技术。
例如,如果您使用 Thymeleaf,您可以添加一个 error.html
模板。
如果您使用 FreeMarker,您可以添加一个 error.ftlh
模板。
通常,您需要一个解析为 error
名称的 View
或一个处理 /error
路径的 @Controller
。
除非您替换了一些默认配置,否则您应该在 ApplicationContext
中找到 BeanNameViewResolver
,因此一个名为 error
的 @Bean
将是一种方法。
有关更多选项,请参阅 ErrorMvcAutoConfiguration
。
另请参阅 错误处理 部分,了解如何在 servlet 容器中注册处理程序。