Spring MVC

Spring Boot 提供了多个 starter,其中包含 Spring MVC。 请注意,某些 starter 是通过依赖项间接引入 Spring MVC,而非直接包含它。 本节将解答有关 Spring MVC 和 Spring Boot 的常见问题。spring-doc.cadn.net.cn

编写 JSON REST 服务

只要类路径上有 Jackson 3,Spring Boot 应用程序中的任何 Spring @RestController 默认都应渲染 JSON 响应,如下例所示:spring-doc.cadn.net.cn

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 能被 Jackson 3 序列化(对于普通的 POJO 或 Groovy 对象来说都是成立的),那么默认情况下,localhost:8080/thing 就会提供其 JSON 表示形式。 请注意,在浏览器中有时可能会看到 XML 响应,因为浏览器发送的 Accept 请求头通常优先选择 XML。spring-doc.cadn.net.cn

编写 XML REST 服务

如果你在类路径中包含了 Jackson XML 扩展(jackson-dataformat-xml),就可以使用它来渲染 XML 响应。 我们之前用于 JSON 的示例同样适用。 要使用 Jackson XML 渲染器,请向你的项目添加以下依赖项:spring-doc.cadn.net.cn

<dependency>
	<groupId>tools.jackson.dataformat</groupId>
	<artifactId>jackson-dataformat-xml</artifactId>
</dependency>

如果 Jackson 的 XML 扩展不可用但 JAXB 可用,则可以通过将 MyThing 注解为 @XmlRootElement 来渲染 XML,如下例所示:spring-doc.cadn.net.cn

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 库已包含在您的项目中,例如通过添加以下内容:spring-doc.cadn.net.cn

<dependency>
	<groupId>org.glassfish.jaxb</groupId>
	<artifactId>jaxb-runtime</artifactId>
</dependency>
要让服务器渲染 XML 而不是 JSON,你可能需要发送一个 Accept: text/xml 请求头(或者使用浏览器)。

自定义 Jackson JsonMapper

您可以使用环境来配置 JsonMapper。 Jackson 提供了一套丰富的开关功能,可用于配置其处理的各个方面。 这些功能在 Jackson 中的多个枚举中进行了描述,并映射到环境中的属性:spring-doc.cadn.net.cn

枚举 <property> </property>

DateTimeFeaturespring-doc.cadn.net.cn

spring.jackson.datatype.datetime.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

EnumFeaturespring-doc.cadn.net.cn

spring.jackson.datatype.enum.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

JsonNodeFeaturespring-doc.cadn.net.cn

spring.jackson.datatype.json-node.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

JsonInclude.Includespring-doc.cadn.net.cn

spring.jackson.default-property-inclusionspring-doc.cadn.net.cn

always, non_null, non_absent, non_default, non_emptyspring-doc.cadn.net.cn

DeserializationFeaturespring-doc.cadn.net.cn

spring.jackson.deserialization.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

JsonReadFeaturespring-doc.cadn.net.cn

spring.jackson.json.read.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

JsonWriteFeaturespring-doc.cadn.net.cn

spring.jackson.json.write.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

MapperFeaturespring-doc.cadn.net.cn

spring.jackson.mapper.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

SerializationFeaturespring-doc.cadn.net.cn

spring.jackson.serialization.<feature_name>spring-doc.cadn.net.cn

true, falsespring-doc.cadn.net.cn

例如,要启用美化输出(pretty print),请设置 spring.jackson.serialization.indent_output=true。 请注意,由于使用了宽松绑定(relaxed binding)indent_output 的大小写不必与对应的枚举常量 INDENT_OUTPUT 的大小写完全一致。spring-doc.cadn.net.cn

此基于环境的配置应用于自动配置的 JsonMapper.Builder Bean,并适用于通过使用构建器创建的任何 Mapper,包括自动配置的 JsonMapper Bean。spring-doc.cadn.net.cn

在处理之前使用 Jackson 2 的应用程序时,为了简化迁移过程,可以将自动配置的 JsonMapper 配置为使用尽可能接近 Spring Boot 为 Jackson 2 所使用的默认设置。要启用这些默认设置,请将 spring.jackson.use-jackson2-defaults 设置为 truespring-doc.cadn.net.cn

上下文的 JsonMapper.Builder 可以通过一个或多个 JsonMapperBuilderCustomizer Bean 进行自定义。 此类自定义器 Bean 可以排序(Boot 自身的自定义器顺序为 0),从而允许在 Boot 自定义之前和之后应用额外的自定义。spring-doc.cadn.net.cn

任何类型为 JacksonModule 的 Bean 都会自动注册到自动配置的 JsonMapper.Builder 中,并应用于该配置创建的任何 JsonMapper 实例。 这为应用程序提供了一种全局机制,以便在添加新功能时贡献自定义模块。spring-doc.cadn.net.cn

任何参与 Java ServiceLoader 机制的模块,默认情况下都会被发现并添加到自动配置的 JsonMapper.Builder 中。要禁用此行为,请将 spring.jackson.find-and-add-modules 设置为 falsespring-doc.cadn.net.cn

如果您想完全替换默认的 JsonMapper,可以定义一个该类型的 @Bean,或者如果您更倾向于基于构建器的方法,则定义一个 JsonMapper.Builder @Bean。 在定义 JsonMapper Bean 时,建议将其标记为 @Primary,因为自动配置中将被替换的 JsonMapper@Primary。 请注意,无论哪种情况,这样做都会禁用 JsonMapper 的所有自动配置。spring-doc.cadn.net.cn

如果您提供任何类型为 @BeanJacksonJsonHttpMessageConverter,它们将替换 MVC 配置中的默认值。 此外,还提供了一个类型为 HttpMessageConverters 的便捷 Bean(如果您使用默认 MVC 配置,则该 Bean 始终可用)。 它包含一些有用的方法,用于访问默认的和用户增强的消息转换器。spring-doc.cadn.net.cn

请参阅自定义@ResponseBody 渲染部分以及 WebMvcAutoConfiguration 源代码以获取更多详情。spring-doc.cadn.net.cn

自定义 @ResponseBody 渲染

Spring 使用 HttpMessageConverters 来渲染 @ResponseBody(或来自 @RestController 的响应)。 您可以通过在 Spring Boot 上下文中添加适当类型的 Bean 来贡献额外的转换器。 如果您添加的 Bean 类型本来就会默认包含(例如用于 JSON 转换的 JacksonJsonHttpMessageConverter),它将替换默认值。 提供了一个类型为 HttpMessageConverters 的便捷 Bean,如果您使用默认的 MVC 配置,该 Bean 始终可用。 它提供一些有用的方法来访问默认和用户增强的消息转换器(例如,如果您想手动将它们注入到自定义的 RestTemplate 中,这会很有用)。spring-doc.cadn.net.cn

与正常的 MVC 用法一样,您提供的任何 WebMvcConfigurer Bean 也可以通过重写 configureMessageConverters 方法来贡献转换器。 然而,与正常的 MVC 不同,您只需提供所需的额外转换器(因为 Spring Boot 使用相同的机制来贡献其默认值)。 最后,如果您通过提供自己的 @EnableWebMvc 配置来选择退出默认的 Spring Boot MVC 配置,则可以完全掌控并通过使用来自 WebMvcConfigurationSupportgetMessageConverters 手动完成所有操作。spring-doc.cadn.net.cn

请参阅 WebMvcAutoConfiguration 源代码以获取更多详情。spring-doc.cadn.net.cn

处理多部分文件上传

Spring Boot 拥抱 servlet 5 Part API 以支持文件上传。 默认情况下,Spring Boot 将 Spring MVC 配置为每个文件最大 1MB,单个请求中文件数据最大 10MB。 您可以使用 MultipartProperties 类中暴露的属性来覆盖这些值、中间数据的存储位置(例如到 /tmp 目录),以及数据刷新到磁盘的阈值。 例如,如果您想指定文件大小无限制,请将 spring.servlet.multipart.max-file-size 属性设置为 -1spring-doc.cadn.net.cn

当您希望在 Spring MVC 控制器处理方法中接收以 @RequestParam 注解标注的、类型为 MultipartFile 的多部分编码文件数据时,多部分支持功能将非常有用。spring-doc.cadn.net.cn

查看更多详情,请参阅 MultipartAutoConfiguration 源代码。spring-doc.cadn.net.cn

建议使用容器内置的多部分上传(multipart uploads)支持,而不是引入额外的依赖项,例如 Apache Commons FileUpload。

关闭 Spring MVC 的 DispatcherServlet

默认情况下,所有内容都从应用程序的根路径(/)提供。 如果你希望映射到不同的路径,可以按如下方式配置:spring-doc.cadn.net.cn

spring.mvc.servlet.path=/mypath
spring:
  mvc:
    servlet:
      path: "/mypath"

如果您有其他 Servlet,可以为每个声明一个类型为 @BeanServletServletRegistrationBean 的实例,Spring Boot 会将它们透明地注册到容器中。 也可以使用 @ServletRegistration 作为 ServletRegistrationBean 的基于注解的替代方案。 由于 Servlet 是以这种方式注册的,因此可以将它们映射到 DispatcherServlet 的子上下文,而无需调用它。spring-doc.cadn.net.cn

自行配置 DispatcherServletPath 并不常见,但如果您确实需要这样做,则还必须提供一个类型为 DispatcherServletPath@Bean,以提供您自定义 DispatcherServlet 的路径。spring-doc.cadn.net.cn

关闭默认的 MVC 配置

完全控制 MVC 配置的最简单方法是提供您自己的带有 @EnableWebMvc 注解的 @Configuration。 这样做可以将所有 MVC 配置掌握在您手中。spring-doc.cadn.net.cn

自定义视图解析器

ViewResolver 是 Spring MVC 的核心组件,负责将 @Controller 中的视图名称转换为实际的 View 实现。 请注意,视图解析器主要用于 UI 应用程序,而非 REST 风格的服务(View 并不用于渲染 @ResponseBody)。 ViewResolver 有多种实现可供选择,Spring 本身对于应该使用哪种实现并没有强制偏好。 另一方面,Spring Boot 会根据它在类路径和应用程序上下文中发现的内容,为您安装一个或两个视图解析器。 DispatcherServlet 会使用它在应用程序上下文中的所有解析器,依次尝试每一个,直到获得结果为止。 如果您添加了自己的解析器,则需要注意顺序以及您的解析器被添加的位置。spring-doc.cadn.net.cn

WebMvcAutoConfiguration 将以下 ViewResolver Bean 添加到您的上下文中:spring-doc.cadn.net.cn

  • 一个名为'defaultViewResolver'的InternalResourceViewResolver。 它定位可以使用DefaultServlet渲染的物理资源(包括静态资源和 JSP 页面,如果您使用它们的话)。 它会为视图名称应用前缀和后缀,然后在 servlet 上下文中查找具有该路径的物理资源(默认值均为空,但可以通过spring.mvc.view.prefixspring.mvc.view.suffix进行外部配置)。 您可以通过提供相同类型的 bean 来覆盖它。spring-doc.cadn.net.cn

  • 一个名为‘beanNameViewResolver’的BeanNameViewResolver。 这是视图解析器链中有用的一员,它会拾取任何与正在解析的View同名的 bean。 通常无需覆盖或替换它。spring-doc.cadn.net.cn

  • 仅当实际存在类型为 View 的 Bean 时,才会添加一个名为 'viewResolver' 的 ContentNegotiatingViewResolver。 这是一个组合解析器,它将委托给所有其他解析器,并尝试匹配客户端发送的 'Accept' HTTP 请求头。 有一篇关于 ContentNegotiatingViewResolver 的实用 博客,您可以阅读以了解更多详情,也可以查看源代码获取细节。 您可以通过定义一个名为 'viewResolver' 的 Bean 来关闭自动配置的 ContentNegotiatingViewResolverspring-doc.cadn.net.cn

  • 如果您使用 Thymeleaf,您还将拥有一个名为‘thymeleafViewResolver’的ThymeleafViewResolver。 它通过在视图名称前后添加前缀和后缀来查找资源。 前缀是spring.thymeleaf.prefix,后缀是spring.thymeleaf.suffix。 前缀和后缀的默认值分别为'classpath:/templates/'和'.html'。 您可以通过提供同名的 bean 来覆盖ThymeleafViewResolverspring-doc.cadn.net.cn

  • 如果您使用 FreeMarker,您还会有一个名为'freeMarkerViewResolver'的FreeMarkerViewResolver。 它通过在视图名称前后添加前缀和后缀,在加载器路径(外部化为spring.freemarker.templateLoaderPath,默认值为'classpath:/templates/')中查找资源。 前缀外部化为spring.freemarker.prefix,后缀外部化为spring.freemarker.suffix。 前缀和后缀的默认值分别为空和'.ftlh'。 您可以通过提供同名的 bean 来覆盖FreeMarkerViewResolver。 可以通过定义类型为FreeMarkerVariablesCustomizer的 bean 来自定义 FreeMarker 变量。spring-doc.cadn.net.cn

  • 如果您使用 Groovy 模板(实际上,如果 groovy-templates 在您的类路径上),您还将拥有一个名为'groovyMarkupViewResolver'的 GroovyMarkupViewResolver。 它通过在视图名称前后添加前缀和后缀(外部化为 spring.groovy.template.prefixspring.groovy.template.suffix)来在加载器路径中查找资源。 前缀和后缀的默认值分别为'classpath:/templates/'和'.tpl'。 您可以通过提供同名的 bean 来覆盖 GroovyMarkupViewResolverspring-doc.cadn.net.cn

  • 如果您使用 Mustache,您还会有一个名为'mustacheViewResolver'的MustacheViewResolver。 它通过在视图名称周围添加前缀和后缀来查找资源。 前缀是spring.mustache.prefix,后缀是spring.mustache.suffix。 前缀和后缀的默认值分别为'classpath:/templates/'和'.mustache'。 您可以通过提供同名的 bean 来覆盖MustacheViewResolverspring-doc.cadn.net.cn

有关更多详细信息,请参阅以下章节:spring-doc.cadn.net.cn

自定义'whitelabel'错误页面

Spring Boot 会安装一个“白标”错误页面,当你在浏览器客户端遇到服务器错误时会看到该页面(使用 JSON 和其他媒体类型的机器客户端则会收到带有正确错误代码的合理响应)。spring-doc.cadn.net.cn

spring.web.error.whitelabel.enabled 设置为 false 以关闭默认错误页面。 这样做会恢复你所使用的 Servlet 容器的默认行为。 请注意,Spring Boot 仍会尝试解析错误视图,因此你最好添加自己的错误页面,而不是完全禁用它。

使用您自己的页面覆盖错误页面取决于您使用的模板技术。 例如,如果您使用 Thymeleaf,可以添加一个 error.html 模板。 如果您使用 FreeMarker,可以添加一个 error.ftlh 模板。 通常,您需要一个解析名称为 errorView,或者一个处理 /error 路径的 @Controller。 除非您替换了某些默认配置,否则您应该在 ApplicationContext 中找到一个 BeanNameViewResolver,因此名为 error@Bean 是一种实现方式。 请参阅 ErrorMvcAutoConfiguration 以了解更多选项。spring-doc.cadn.net.cn

另请参阅错误处理一节,了解如何在 Servlet 容器中注册处理器的详细信息。spring-doc.cadn.net.cn