1.3. Annotated Controllers

预计阅读时间: 111 分钟

1.3. 注解控制器

Spring MVC provides an annotation-based programming model where @Controller and @RestController components use annotations to express request mappings, request input, exception handling, and more. Annotated controllers have flexible method signatures and do not have to extend base classes nor implement specific interfaces.
Spring MVC 提供了一个基于注解的编程模型,其中 @Controller@RestController 组件使用注解来表示请求映射、请求输入、异常处理等。注解控制器具有灵活的方法签名,无需扩展基类或实现特定接口。
The following example shows a controller defined by annotations:
以下示例展示了通过注解定义的控制器:

@Controller public class HelloController { @GetMapping("/hello") public String handle(Model model) { model.addAttribute("message", "Hello World!"); return "index"; } }
import org.springframework.ui.set @Controller class HelloController { @GetMapping("/hello") fun handle(model: Model): String { model["message"] = "Hello World!" return "index" } }

In the preceding example, the method accepts a Model and returns a view name as a String, but many other options exist and are explained later in this chapter.
在前面示例中,该方法接受一个 Model 并返回一个视图名称作为 String ,但许多其他选项将在本章后面进行解释。

Guides and tutorials on spring.io use the annotation-based programming model described in this section.
本节中描述的基于注解的编程模型在 spring.io 上的指南和教程中使用。

(#mvc-ann-controller)1.3.1. Declaration 1.3.1. 声明

You can define controller beans by using a standard Spring bean definition in the Servlet’s WebApplicationContext. The @Controller stereotype allows for auto-detection, aligned with Spring general support for detecting @Component classes in the classpath and auto-registering bean definitions for them. It also acts as a stereotype for the annotated class, indicating its role as a web component.
您可以使用 Servlet 的 WebApplicationContext 中的标准 Spring bean 定义来定义控制器 bean。 @Controller stereotypes 允许自动检测,与 Spring 对检测类路径中的 @Component 类的通用支持相一致,并自动注册它们的 bean 定义。它还充当注解类的 stereotype,表明其作为 Web 组件的角色。

To enable auto-detection of such @Controller beans, you can add component scanning to your Java configuration, as the following example shows:
要启用自动检测此类 @Controller 实例,您可以在 Java 配置中添加组件扫描,如下例所示:

@Configuration @ComponentScan("org.example.web") public class WebConfig { // ... }
@Configuration @ComponentScan("org.example.web") class WebConfig { // ... }

The following example shows the XML configuration equivalent of the preceding example:
以下示例显示了前一个示例的 XML 配置等效项:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.example.web"/> <!-- ... --> </beans>

@RestController is a composed annotation that is itself meta-annotated with @Controller and @ResponseBody to indicate a controller whose every method inherits the type-level @ResponseBody annotation and, therefore, writes directly to the response body versus view resolution and rendering with an HTML template.
@RestController 是一个由注解组成的注解,它本身被 @Controller@ResponseBody 元注解所标注,以指示每个方法都继承自类型级别的 @ResponseBody 注解的控制器,因此它直接写入响应体,而不是使用 HTML 模板进行视图解析和渲染。

(#mvc-ann-requestmapping-proxying)AOP Proxies AOP 代理

In some cases, you may need to decorate a controller with an AOP proxy at runtime. One example is if you choose to have @Transactional annotations directly on the controller. When this is the case, for controllers specifically, we recommend using class-based proxying. This is typically the default choice with controllers.
在某些情况下,您可能需要在运行时使用 AOP 代理装饰控制器。一个例子是如果您选择在控制器上直接使用 @Transactional 注解。在这种情况下,对于控制器特别推荐使用基于类的代理。这通常是控制器的默认选择。
However, if a controller must implement an interface that is not a Spring Context callback (such as InitializingBean, *Aware, and others), you may need to explicitly configure class-based proxying. For example, with <tx:annotation-driven/> you can change to <tx:annotation-driven proxy-target-class="true"/>, and with @EnableTransactionManagement you can change to @EnableTransactionManagement(proxyTargetClass = true).
然而,如果控制器必须实现一个不是 Spring Context 回调的接口(例如 InitializingBean*Aware ,以及其他),您可能需要显式配置基于类的代理。例如,使用 <tx:annotation-driven/> 可以更改为 <tx:annotation-driven proxy-target-class="true"/> ,使用 @EnableTransactionManagement 可以更改为 @EnableTransactionManagement(proxyTargetClass = true)

(#mvc-ann-requestmapping)1.3.2. Request Mapping 1.3.2. 请求映射

You can use the @RequestMapping annotation to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types.
您可以使用 @RequestMapping 注解将请求映射到控制器方法。它具有各种属性,可以按 URL、HTTP 方法、请求参数、头部和媒体类型进行匹配。
You can use it at the class level to express shared mappings or at the method level to narrow down to a specific endpoint mapping.
您可以在类级别使用它来表示共享映射,或在方法级别缩小到特定的端点映射。

There are also HTTP method specific shortcut variants of @RequestMapping:
也存在针对 @RequestMapping 的特定 HTTP 方法快捷变体:

  • @GetMapping

  • @PostMapping

  • @PutMapping

  • @DeleteMapping

  • @PatchMapping

The shortcuts are Custom Annotations that are provided because, arguably, most controller methods should be mapped to a specific HTTP method versus using @RequestMapping, which, by default, matches to all HTTP methods. A @RequestMapping is still needed at the class level to express shared mappings.
快捷键是自定义注解,提供这些注解的原因是,可以说,大多数控制器方法应该映射到特定的 HTTP 方法,而不是使用 @RequestMapping ,默认情况下,它会匹配所有 HTTP 方法。在类级别上仍然需要一个 @RequestMapping 来表示共享映射。

The following example has type and method level mappings:
以下示例具有类型和方法级别的映射:

@RestController @RequestMapping("/persons") class PersonController { @GetMapping("/{id}") public Person getPerson(@PathVariable Long id) { // ... } @PostMapping @ResponseStatus(HttpStatus.CREATED) public void add(@RequestBody Person person) { // ... } }
@RestController @RequestMapping("/persons") class PersonController { @GetMapping("/{id}") fun getPerson(@PathVariable id: Long): Person { // ... } @PostMapping @ResponseStatus(HttpStatus.CREATED) fun add(@RequestBody person: Person) { // ... } }

(#mvc-ann-requestmapping-uri-templates)URI patterns URI 模式

@RequestMapping methods can be mapped using URL patterns. There are two alternatives:
@RequestMapping 方法可以通过 URL 模式进行映射。有两种选择:

  • PathPattern— a pre-parsed pattern matched against the URL path also pre-parsed as PathContainer. Designed for web use, this solution deals effectively with encoding and path parameters, and matches efficiently.
    PathPattern — 与作为 PathContainer 预解析的 URL 路径匹配的预解析模式。专为网络使用设计,此解决方案有效地处理编码和路径参数,并高效匹配。

  • AntPathMatcher— match String patterns against a String path. This is the original solution also used in Spring configuration to select resources on the classpath, on the filesystem, and other locations.
    AntPathMatcher — 将字符串模式与字符串路径进行匹配。这是原始解决方案,也用于 Spring 配置中在类路径、文件系统和其他位置选择资源。
    It is less efficient and the String path input is a challenge for dealing effectively with encoding and other issues with URLs.
    它效率较低,且字符串路径输入在有效处理 URL 的编码和其他问题方面是一个挑战。

PathPattern is the recommended solution for web applications and it is the only choice in Spring WebFlux. Prior to version 5.3, AntPathMatcher was the only choice in Spring MVC and continues to be the default. However PathPattern can be enabled in the MVC config.
PathPattern 是推荐用于 Web 应用的解决方案,在 Spring WebFlux 中它是唯一的选择。在版本 5.3 之前, AntPathMatcher 是 Spring MVC 的唯一选择,并且继续作为默认选项。然而, PathPattern 可以在 MVC 配置中启用。

PathPattern supports the same pattern syntax as AntPathMatcher. In addition it also supports the capturing pattern, e.g. {*spring}, for matching 0 or more path segments at the end of a path. PathPattern also restricts the use of ** for matching multiple path segments such that it’s only allowed at the end of a pattern. This eliminates many cases of ambiguity when choosing the best matching pattern for a given request. For full pattern syntax please refer to PathPattern and AntPathMatcher.
PathPattern 支持与 AntPathMatcher 相同的模式语法。此外,它还支持捕获模式,例如 {*spring} ,用于匹配路径末尾的 0 个或多个路径段。 PathPattern 还限制了 ** 用于匹配多个路径段的使用,使其仅在模式末尾允许。这消除了在选择给定请求的最佳匹配模式时的许多歧义情况。有关完整的模式语法,请参阅 PathPattern 和 AntPathMatcher。

Some example patterns:一些示例模式:

  • "/resources/ima?e.png" - match one character in a path segment
    "/resources/ima?e.png" - 匹配路径段中的一个字符

  • "/resources/*.png" - match zero or more characters in a path segment
    "/resources/*.png" - 在路径段中匹配零个或多个字符

  • "/resources/**" - match multiple path segments
    "/resources/**" - 匹配多个路径段

  • "/projects/{project}/versions" - match a path segment and capture it as a variable
    "/projects/{project}/versions" - 匹配路径段并将其捕获为变量

  • "/projects/{project:[a-z]+}/versions" - match and capture a variable with a regex
    "/projects/{project:[a-z]+}/versions" - 使用正则表达式匹配并捕获一个变量

Captured URI variables can be accessed with @PathVariable. For example:
捕获的 URI 变量可以通过 @PathVariable 访问。例如:

@GetMapping("/owners/{ownerId}/pets/{petId}") public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { // ... }
@GetMapping("/owners/{ownerId}/pets/{petId}") fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet { // ... }

You can declare URI variables at the class and method levels, as the following example shows:
您可以在类和方法级别声明 URI 变量,如下例所示:

@Controller @RequestMapping("/owners/{ownerId}") public class OwnerController { @GetMapping("/pets/{petId}") public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) { // ... } }
@Controller @RequestMapping("/owners/{ownerId}") class OwnerController { @GetMapping("/pets/{petId}") fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet { // ... } }

URI variables are automatically converted to the appropriate type, or TypeMismatchException is raised. Simple types ( int, long, Date, and so on) are supported by default and you can register support for any other data type. See Type Conversion and DataBinder.
URI 变量会自动转换为适当的类型,或者抛出 TypeMismatchException 异常。默认支持简单类型( intlongDate 等),您可以注册对任何其他数据类型的支持。请参阅类型转换和 DataBinder

You can explicitly name URI variables (for example, @PathVariable("customId")), but you can leave that detail out if the names are the same and your code is compiled with debugging information or with the -parameters compiler flag on Java 8.
您可以显式命名 URI 变量(例如, @PathVariable("customId") ),但如果变量名称相同,并且您的代码在带有调试信息或开启 Java 8 的 -parameters 编译器标志的情况下编译,则可以省略此细节。

The syntax {varName:regex} declares a URI variable with a regular expression that has syntax of {varName:regex}. For example, given URL "/spring-web-3.0.5.jar", the following method extracts the name, version, and file extension:
{varName:regex} 声明一个具有 {varName:regex} 语法正则表达式的 URI 变量。例如,给定 URL "/spring-web-3.0.5.jar" ,以下方法提取名称、版本和文件扩展名:

@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") public void handle(@PathVariable String name, @PathVariable String version, @PathVariable String ext) { // ... }
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}") fun handle(@PathVariable name: String, @PathVariable version: String, @PathVariable ext: String) { // ... }

URI path patterns can also have embedded ${…​} placeholders that are resolved on startup by using PropertySourcesPlaceholderConfigurer against local, system, environment, and other property sources. You can use this, for example, to parameterize a base URL based on some external configuration.
URI 路径模式也可以包含嵌入的 ${…​} 占位符,这些占位符在启动时通过使用 PropertySourcesPlaceholderConfigurer 与本地、系统、环境和其它属性源进行解析。您可以使用此功能,例如,根据某些外部配置参数化基本 URL。

(#mvc-ann-requestmapping-pattern-comparison)Pattern Comparison 模式比较

When multiple patterns match a URL, the best match must be selected. This is done with one of the following depending on whether use of parsed PathPattern is enabled for use or not:
当多个模式匹配一个 URL 时,必须选择最佳匹配。这取决于是否启用了使用解析的 PathPattern

Both help to sort patterns with more specific ones on top. A pattern is less specific if it has a lower count of URI variables (counted as 1), single wildcards (counted as 1), and double wildcards (counted as 2). Given an equal score, the longer pattern is chosen.
两者都帮助将更具体的模式放在顶部排序。如果一个模式具有更少的 URI 变量(计为 1)、单个通配符(计为 1)和双通配符(计为 2),则该模式更不具体。如果得分相同,则选择更长的模式。
Given the same score and length, the pattern with more URI variables than wildcards is chosen.
给定相同的分数和长度,选择具有更多 URI 变量而非通配符的模式。

The default mapping pattern (/**) is excluded from scoring and always sorted last. Also, prefix patterns (such as /public/**) are considered less specific than other pattern that do not have double wildcards.
默认映射模式( /** )不计入评分并始终排在最后。此外,前缀模式(如 /public/** )被认为比没有双通配符的其他模式更不具体。

For the full details, follow the above links to the pattern Comparators.
有关详细信息,请点击上述链接查看模式比较器。

(#mvc-ann-requestmapping-suffix-pattern-match)Suffix Match 后缀匹配

Starting in 5.3, by default Spring MVC no longer performs .* suffix pattern matching where a controller mapped to /person is also implicitly mapped to /person.*. As a consequence path extensions are no longer used to interpret the requested content type for the response — for example, /person.pdf, /person.xml, and so on.
从 5.3 版本开始,默认情况下 Spring MVC 不再执行 .* 后缀模式匹配,即映射到 /person 的控制器也隐式映射到 /person.* 。因此,路径扩展不再用于解释响应请求的内容类型——例如, /person.pdf/person.xml ,等等。

Using file extensions in this way was necessary when browsers used to send Accept headers that were hard to interpret consistently. At present, that is no longer a necessity and using the Accept header should be the preferred choice.
使用文件扩展名在这种情况下是必要的,因为当浏览器曾经发送难以一致解释的 Accept 标头时。目前,这不再是必需的,使用 Accept 标头应该是首选的选择。

Over time, the use of file name extensions has proven problematic in a variety of ways. It can cause ambiguity when overlain with the use of URI variables, path parameters, and URI encoding.
随着时间的推移,文件扩展名的使用在多种方式上已被证明存在问题。当与 URI 变量、路径参数和 URI 编码一起使用时,可能会导致歧义。
Reasoning about URL-based authorization and security (see next section for more details) also becomes more difficult.
关于基于 URL 的授权和安全的推理(更多细节请参见下一节)也变得更加困难。

To completely disable the use of path extensions in versions prior to 5.3, set the following:
为了完全禁用 5.3 版本之前的路径扩展使用,设置以下内容:

  • useSuffixPatternMatching(false), see PathMatchConfigurer
    useSuffixPatternMatching(false) ,请参阅 PathMatchConfigurer

  • favorPathExtension(false), see ContentNegotiationConfigurer
    favorPathExtension(false) ,请参阅 ContentNegotiationConfigurer

Having a way to request content types other than through the "Accept" header can still be useful, e.g. when typing a URL in a browser. A safe alternative to path extensions is to use the query parameter strategy. If you must use file extensions, consider restricting them to a list of explicitly registered extensions through the mediaTypes property of ContentNegotiationConfigurer.
拥有一种方法来请求除通过 "Accept" 头以外的内容类型仍然很有用,例如在浏览器中输入 URL 时。路径扩展的一个安全替代方案是使用查询参数策略。如果您必须使用文件扩展名,请考虑通过 ContentNegotiationConfigurer 的 mediaTypes 属性将它们限制为显式注册的扩展名列表。

(#mvc-ann-requestmapping-rfd)Suffix Match and RFD

后缀匹配和 RFD

A reflected file download (RFD) attack is similar to XSS in that it relies on request input (for example, a query parameter and a URI variable) being reflected in the response.
反射文件下载(RFD)攻击类似于 XSS 攻击,因为它依赖于请求输入(例如查询参数和 URI 变量)在响应中反射。
However, instead of inserting JavaScript into HTML, an RFD attack relies on the browser switching to perform a download and treating the response as an executable script when double-clicked later.
然而,RFD 攻击不是将 JavaScript 插入 HTML 中,而是依赖于浏览器切换以执行下载,并在稍后双击时将响应作为可执行脚本处理。

In Spring MVC, @ResponseBody and ResponseEntity methods are at risk, because they can render different content types, which clients can request through URL path extensions. Disabling suffix pattern matching and using path extensions for content negotiation lower the risk but are not sufficient to prevent RFD attacks.
在 Spring MVC 中, @ResponseBodyResponseEntity 方法存在风险,因为它们可以渲染不同的内容类型,客户端可以通过 URL 路径扩展来请求这些类型。禁用后缀模式匹配和使用路径扩展进行内容协商可以降低风险,但不足以防止 RFD 攻击。

To prevent RFD attacks, prior to rendering the response body, Spring MVC adds a Content-Disposition:inline;filename=f.txt header to suggest a fixed and safe download file. This is done only if the URL path contains a file extension that is neither allowed as safe nor explicitly registered for content negotiation.
为了防止 RFD 攻击,在渲染响应体之前,Spring MVC 会添加一个 Content-Disposition:inline;filename=f.txt 头,建议下载一个固定且安全的文件。这仅在 URL 路径包含既不被视为安全也不明确注册为内容协商的文件扩展名时才执行。
However, it can potentially have side effects when URLs are typed directly into a browser.
然而,当直接在浏览器中输入 URL 时,它可能产生潜在的副作用。

Many common path extensions are allowed as safe by default. Applications with custom HttpMessageConverter implementations can explicitly register file extensions for content negotiation to avoid having a Content-Disposition header added for those extensions. See Content Types.
许多常见的路径扩展默认被视为安全。具有自定义 HttpMessageConverter 实现的程序可以明确注册文件扩展名以进行内容协商,以避免为这些扩展名添加 Content-Disposition 头。请参阅内容类型。

See CVE-2015-5211 for additional recommendations related to RFD.
查看 CVE-2015-5211 以获取有关 RFD 的附加建议。

(#mvc-ann-requestmapping-consumes)Consumable Media Types 消耗性媒体类型

You can narrow the request mapping based on the Content-Type of the request, as the following example shows:
您可以根据请求的 Content-Type 来缩小请求映射,如下例所示:

@PostMapping(path = "/pets", consumes = "application/json") (1) public void addPet(@RequestBody Pet pet) { // ... }

1

Using a consumes attribute to narrow the mapping by the content type.
使用 consumes 属性通过内容类型缩小映射范围。

@PostMapping("/pets", consumes = ["application/json"]) (1) fun addPet(@RequestBody pet: Pet) { // ... }

1

Using a consumes attribute to narrow the mapping by the content type.

The consumes attribute also supports negation expressions — for example, !text/plain means any content type other than text/plain.
consumes 属性也支持否定表达式——例如, !text/plain 表示除了 text/plain 之外的所有内容类型。

You can declare a shared consumes attribute at the class level. Unlike most other request-mapping attributes, however, when used at the class level, a method-level consumes attribute overrides rather than extends the class-level declaration.
您可以在类级别声明一个共享的 consumes 属性。然而,与其他大多数请求映射属性不同,当在类级别使用时,方法级别的 consumes 属性会覆盖而不是扩展类级别的声明。

MediaType provides constants for commonly used media types, such as APPLICATION_JSON_VALUE and APPLICATION_XML_VALUE.
MediaType 提供了常用媒体类型的常量,例如 APPLICATION_JSON_VALUEAPPLICATION_XML_VALUE

(#mvc-ann-requestmapping-produces)Producible Media Types 可生产的媒体类型

You can narrow the request mapping based on the Accept request header and the list of content types that a controller method produces, as the following example shows:
您可以根据 Accept 请求头和控制器方法生成的内容类型列表来缩小请求映射,如下例所示:

@GetMapping(path = "/pets/{petId}", produces = "application/json") (1) @ResponseBody public Pet getPet(@PathVariable String petId) { // ... }

1

Using a produces attribute to narrow the mapping by the content type.
使用 produces 属性通过内容类型缩小映射范围。

@GetMapping("/pets/{petId}", produces = ["application/json"]) (1) @ResponseBody fun getPet(@PathVariable petId: String): Pet { // ... }

1

Using a produces attribute to narrow the mapping by the content type.

The media type can specify a character set. Negated expressions are supported — for example, !text/plain means any content type other than "text/plain".
媒体类型可以指定字符集。支持否定表达式——例如, !text/plain 表示除"text/plain"之外的所有内容类型。

You can declare a shared produces attribute at the class level. Unlike most other request-mapping attributes, however, when used at the class level, a method-level produces attribute overrides rather than extends the class-level declaration.
您可以在类级别声明一个共享的 produces 属性。然而,与其他大多数请求映射属性不同,当在类级别使用时,方法级别的 produces 属性会覆盖而不是扩展类级别的声明。

MediaType provides constants for commonly used media types, such as APPLICATION_JSON_VALUE and APPLICATION_XML_VALUE.
MediaType 提供了常用媒体类型的常量,例如 APPLICATION_JSON_VALUEAPPLICATION_XML_VALUE

(#mvc-ann-requestmapping-params-and-headers)Parameters, headers 参数,头部

You can narrow request mappings based on request parameter conditions. You can test for the presence of a request parameter (myParam), for the absence of one (!myParam), or for a specific value (myParam=myValue). The following example shows how to test for a specific value:
您可以根据请求参数条件缩小请求映射。您可以测试请求参数的存在( myParam ),不存在( !myParam ),或特定值( myParam=myValue )。以下示例展示了如何测试特定值:

@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") (1) public void findPet(@PathVariable String petId) { // ... }

1

Testing whether myParam equals myValue.
测试是否 myParam 等于 myValue

@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) (1) fun findPet(@PathVariable petId: String) { // ... }

1

Testing whether myParam equals myValue.

You can also use the same with request header conditions, as the following example shows:
您也可以使用相同的请求头条件,如下例所示:

@GetMapping(path = "/pets/{petId}", headers = "myHeader=myValue") (1) public void findPet(@PathVariable String petId) { // ... }

1

Testing whether myHeader equals myValue.
测试是否 myHeader 等于 myValue

@GetMapping("/pets/{petId}", headers = ["myHeader=myValue"]) (1) fun findPet(@PathVariable petId: String) { // ... }

You can match Content-Type and Accept with the headers condition, but it is better to use consumes and produces instead.
您可以使用 Content-TypeAccept 与头部条件进行匹配,但最好使用 consumes 和 produces。

(#mvc-ann-requestmapping-head-options)HTTP HEAD, OPTIONS HTTP HEAD,OPTIONS

@GetMapping (and @RequestMapping(method=HttpMethod.GET)) support HTTP HEAD transparently for request mapping. Controller methods do not need to change. A response wrapper, applied in javax.servlet.http.HttpServlet, ensures a Content-Length header is set to the number of bytes written (without actually writing to the response).
@GetMapping (以及 @RequestMapping(method=HttpMethod.GET) )支持对 HTTP HEAD 请求进行透明映射。控制器方法无需更改。在 javax.servlet.http.HttpServlet 中应用的一个响应包装器确保将 Content-Length 头设置为已写入的字节数(实际上并不写入响应)。

@GetMapping (and @RequestMapping(method=HttpMethod.GET)) are implicitly mapped to and support HTTP HEAD. An HTTP HEAD request is processed as if it were HTTP GET except that, instead of writing the body, the number of bytes are counted and the Content-Length header is set.
@GetMapping (以及 @RequestMapping(method=HttpMethod.GET) )隐式映射并支持 HTTP HEAD。HTTP HEAD 请求的处理方式与 HTTP GET 相同,除了不写入主体,而是计算字节数并设置 Content-Length 头。

By default, HTTP OPTIONS is handled by setting the Allow response header to the list of HTTP methods listed in all @RequestMapping methods that have matching URL patterns.
默认情况下,通过设置 Allow 响应头为所有具有匹配 URL 模式的 @RequestMapping 方法中列出的 HTTP 方法来处理 HTTP OPTIONS。

For a @RequestMapping without HTTP method declarations, the Allow header is set to GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS. Controller methods should always declare the supported HTTP methods (for example, by using the HTTP method specific variants: @GetMapping, @PostMapping, and others).
对于一个没有 HTTP 方法声明的 @RequestMappingAllow 头被设置为 GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS 。控制器方法应始终声明支持的 HTTP 方法(例如,通过使用特定于 HTTP 方法的变体: @GetMapping@PostMapping ,以及其他)。

You can explicitly map the @RequestMapping method to HTTP HEAD and HTTP OPTIONS, but that is not necessary in the common case.
您可以将 @RequestMapping 方法显式映射到 HTTP HEAD 和 HTTP OPTIONS,但在常见情况下这不是必要的。

(#mvc-ann-requestmapping-composed)Custom Annotations 自定义注解

Spring MVC supports the use of composed annotations for request mapping. Those are annotations that are themselves meta-annotated with @RequestMapping and composed to redeclare a subset (or all) of the @RequestMapping attributes with a narrower, more specific purpose.
Spring MVC 支持使用组合注解进行请求映射。这些注解本身被 @RequestMapping 元注解,并组合起来重新声明一个子集(或全部)的 @RequestMapping 属性,以实现更窄、更具体的目的。

@GetMapping, @PostMapping, @PutMapping, @DeleteMapping, and @PatchMapping are examples of composed annotations. They are provided because, arguably, most controller methods should be mapped to a specific HTTP method versus using @RequestMapping, which, by default, matches to all HTTP methods. If you need an example of composed annotations, look at how those are declared.
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMapping 是组合注解的示例。它们被提供出来,因为可以说,大多数控制器方法都应该映射到特定的 HTTP 方法,而不是使用默认匹配所有 HTTP 方法的 @RequestMapping 。如果您需要查看组合注解的示例,请查看它们的声明方式。

Spring MVC also supports custom request-mapping attributes with custom request-matching logic. This is a more advanced option that requires subclassing RequestMappingHandlerMapping and overriding the getCustomMethodCondition method, where you can check the custom attribute and return your own RequestCondition.
Spring MVC 还支持使用自定义请求匹配逻辑的自定义请求映射属性。这是一个更高级的选项,需要继承 RequestMappingHandlerMapping 并重写 getCustomMethodCondition 方法,在那里您可以检查自定义属性并返回您自己的 RequestCondition

(#mvc-ann-requestmapping-registration)Explicit Registrations 显式注册

You can programmatically register handler methods, which you can use for dynamic registrations or for advanced cases, such as different instances of the same handler under different URLs. The following example registers a handler method:
您可以编程注册处理方法,这些方法可用于动态注册或用于高级情况,例如在不同 URL 下相同处理器的不同实例。以下示例注册了一个处理方法:

@Configuration public class MyConfig { @Autowired public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) (1) throws NoSuchMethodException { RequestMappingInfo info = RequestMappingInfo .paths("/user/{id}").methods(RequestMethod.GET).build(); (2) Method method = UserHandler.class.getMethod("getUser", Long.class); (3) mapping.registerMapping(info, handler, method); (4) } }

1

Inject the target handler and the handler mapping for controllers.
注入目标处理器和控制器处理器映射。

2

Prepare the request mapping meta data.
准备请求映射元数据。

3

Get the handler method. 获取处理器方法。

4

Add the registration. 添加注册。

@Configuration class MyConfig { @Autowired fun setHandlerMapping(mapping: RequestMappingHandlerMapping, handler: UserHandler) { (1) val info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build() (2) val method = UserHandler::class.java.getMethod("getUser", Long::class.java) (3) mapping.registerMapping(info, handler, method) (4) } }

1

Inject the target handler and the handler mapping for controllers.

2

Prepare the request mapping meta data.

3

Get the handler method.

4

Add the registration.

(#mvc-ann-methods)1.3.3. Handler Methods 1.3.3. 处理方法

@RequestMapping handler methods have a flexible signature and can choose from a range of supported controller method arguments and return values.
@RequestMapping 处理方法具有灵活的签名,可以从一系列支持的控制器方法参数和返回值中进行选择。

(#mvc-ann-arguments)Method Arguments 方法参数

The next table describes the supported controller method arguments. Reactive types are not supported for any arguments.
下表描述了支持的控制器方法参数。不支持任何参数使用响应式类型。

JDK 8’s java.util.Optional is supported as a method argument in combination with annotations that have a required attribute (for example, @RequestParam, @RequestHeader, and others) and is equivalent to required=false.
JDK 8 的 java.util.Optional 可以作为方法参数与具有 required 属性(例如, @RequestParam@RequestHeader 等)的注解一起使用,相当于 required=false

Controller method argument
控制器方法参数

Description 描述

WebRequest, NativeWebRequest

Generic access to request parameters and request and session attributes, without direct use of the Servlet API.
通用访问请求参数和请求及会话属性,无需直接使用 Servlet API。

javax.servlet.ServletRequest, javax.servlet.ServletResponse

Choose any specific request or response type — for example, ServletRequest, HttpServletRequest, or Spring’s MultipartRequest, MultipartHttpServletRequest.
选择任何特定的请求或响应类型——例如, ServletRequestHttpServletRequest ,或 Spring 的 MultipartRequestMultipartHttpServletRequest

javax.servlet.http.HttpSession

Enforces the presence of a session. As a consequence, such an argument is never null. Note that session access is not thread-safe. Consider setting the RequestMappingHandlerAdapter instance’s synchronizeOnSession flag to true if multiple requests are allowed to concurrently access a session.
强制执行会话的存在。因此,这样的参数永远不会是 null 。请注意,会话访问不是线程安全的。考虑将 RequestMappingHandlerAdapter 实例的 synchronizeOnSession 标志设置为 true ,如果允许多个请求同时访问会话。

javax.servlet.http.PushBuilder

Servlet 4.0 push builder API for programmatic HTTP/2 resource pushes. Note that, per the Servlet specification, the injected PushBuilder instance can be null if the client does not support that HTTP/2 feature.
Servlet 4.0 推送构建器 API 用于程序化 HTTP/2 资源推送。请注意,根据 Servlet 规范,如果客户端不支持该 HTTP/2 功能,注入的 PushBuilder 实例可以为 null。

java.security.Principal

Currently authenticated user — possibly a specific Principal implementation class if known.
当前认证用户 — 如果已知,可能是特定的 Principal 实现类。

Note that this argument is not resolved eagerly, if it is annotated in order to allow a custom resolver to resolve it before falling back on default resolution via HttpServletRequest#getUserPrincipal. For example, the Spring Security Authentication implements Principal and would be injected as such via HttpServletRequest#getUserPrincipal, unless it is also annotated with @AuthenticationPrincipal in which case it is resolved by a custom Spring Security resolver through Authentication#getPrincipal.
请注意,此参数不是急切解析的,如果它被注解以允许自定义解析器在通过 HttpServletRequest#getUserPrincipal 回退到默认解析之前解析它。例如,Spring Security Authentication 实现 Principal ,并通过 HttpServletRequest#getUserPrincipal 注入,除非它也被 @AuthenticationPrincipal 注解,在这种情况下,它将通过 Authentication#getPrincipal 由自定义 Spring Security 解析器解析。

HttpMethod

The HTTP method of the request.
请求的 HTTP 方法。

java.util.Locale

The current request locale, determined by the most specific LocaleResolver available (in effect, the configured LocaleResolver or LocaleContextResolver).
当前请求的区域设置,由最具体的 LocaleResolver 确定(实际上,是配置的 LocaleResolverLocaleContextResolver )。

java.util.TimeZone + java.time.ZoneId

The time zone associated with the current request, as determined by a LocaleContextResolver.
当前请求关联的时间区域,由 LocaleContextResolver 确定。

java.io.InputStream, java.io.Reader

For access to the raw request body as exposed by the Servlet API.
用于访问 Servlet API 暴露的原始请求体。

java.io.OutputStream, java.io.Writer

For access to the raw response body as exposed by the Servlet API.
用于访问 Servlet API 暴露的原始响应体。

@PathVariable

For access to URI template variables. See URI patterns.
用于访问 URI 模板变量。请参阅 URI 模式。

@MatrixVariable

For access to name-value pairs in URI path segments. See Matrix Variables.
用于访问 URI 路径段中的键值对。请参阅矩阵变量。

@RequestParam

For access to the Servlet request parameters, including multipart files. Parameter values are converted to the declared method argument type. See @RequestParam as well as Multipart.
为了访问 Servlet 请求参数,包括多部分文件。参数值被转换为声明的参数类型。请参阅 @RequestParam 以及 Multipart。

Note that use of @RequestParam is optional for simple parameter values. See “Any other argument”, at the end of this table.
请注意,对于简单的参数值,使用 @RequestParam 是可选的。请参阅此表末尾的“任何其他参数”。

@RequestHeader

For access to request headers. Header values are converted to the declared method argument type. See @RequestHeader.
用于访问请求头。将头值转换为声明的参数类型。见 @RequestHeader

@CookieValue

For access to cookies. Cookies values are converted to the declared method argument type. See @CookieValue.
为了访问 cookie。cookie 值被转换为声明的参数类型。见 @CookieValue

@RequestBody

For access to the HTTP request body. Body content is converted to the declared method argument type by using HttpMessageConverter implementations. See @RequestBody.
为了访问 HTTP 请求体。通过使用 HttpMessageConverter 实现将请求体内容转换为声明的方法参数类型。见 @RequestBody

HttpEntity<B>

For access to request headers and body. The body is converted with an HttpMessageConverter. See HttpEntity.
用于访问请求头和正文。正文通过 HttpMessageConverter 转换。参见 HttpEntity。

@RequestPart

For access to a part in a multipart/form-data request, converting the part’s body with an HttpMessageConverter. See Multipart.
为了访问 multipart/form-data 请求中的部分,将部分的内容使用 HttpMessageConverter 进行转换。参见多部分。

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap

For access to the model that is used in HTML controllers and exposed to templates as part of view rendering.
用于访问在 HTML 控制器中使用的模型,并将其作为视图渲染的一部分暴露给模板。

RedirectAttributes

Specify attributes to use in case of a redirect (that is, to be appended to the query string) and flash attributes to be stored temporarily until the request after redirect. See Redirect Attributes and Flash Attributes.
指定在重定向时使用的属性(即附加到查询字符串的属性)以及临时存储直到重定向后的请求的闪存属性。请参阅重定向属性和闪存属性。

@ModelAttribute

For access to an existing attribute in the model (instantiated if not present) with data binding and validation applied. See @ModelAttribute as well as Model and DataBinder.
为了访问模型中现有的属性(如果不存在则实例化),并应用数据绑定和验证。请参阅 @ModelAttribute 以及 Model 和 DataBinder

Note that use of @ModelAttribute is optional (for example, to set its attributes). See “Any other argument” at the end of this table.
请注意,使用 @ModelAttribute 是可选的(例如,用于设置其属性)。请参阅此表末尾的“任何其他参数”。

Errors, BindingResult

For access to errors from validation and data binding for a command object (that is, a @ModelAttribute argument) or errors from the validation of a @RequestBody or @RequestPart arguments. You must declare an Errors, or BindingResult argument immediately after the validated method argument.
为了访问命令对象(即, @ModelAttribute 参数)的验证和数据绑定错误,或访问 @RequestBody@RequestPart 参数的验证错误。您必须在验证方法参数之后立即声明一个 ErrorsBindingResult 参数。

SessionStatus + class-level @SessionAttributes``SessionStatus + 类级别 @SessionAttributes

For marking form processing complete, which triggers cleanup of session attributes declared through a class-level @SessionAttributes annotation. See @SessionAttributes for more details.
为了标记表单处理完成,这会触发通过类级别 @SessionAttributes 注解声明的会话属性的清理。有关更多详细信息,请参阅 @SessionAttributes

UriComponentsBuilder

For preparing a URL relative to the current request’s host, port, scheme, context path, and the literal part of the servlet mapping. See URI Links.
为了准备一个相对于当前请求的主机、端口、协议、上下文路径和 servlet 映射的文本部分的 URL。请参阅 URI 链接。

@SessionAttribute

For access to any session attribute, in contrast to model attributes stored in the session as a result of a class-level @SessionAttributes declaration. See @SessionAttribute for more details.
为了访问任何会话属性,与由于类级别 @SessionAttributes 声明而存储在会话中的模型属性相反。有关更多详细信息,请参阅 @SessionAttribute

@RequestAttribute

For access to request attributes. See @RequestAttribute for more details.
用于访问请求属性。有关更多详细信息,请参阅 @RequestAttribute

Any other argument 任何其他参数

If a method argument is not matched to any of the earlier values in this table and it is a simple type (as determined by BeanUtils#isSimpleProperty), it is resolved as a @RequestParam. Otherwise, it is resolved as a @ModelAttribute.
如果方法参数与表中早先的任何值都不匹配,并且它是一个简单类型(由 BeanUtils#isSimpleProperty 确定),则将其解析为 @RequestParam 。否则,将其解析为 @ModelAttribute

(#mvc-ann-return-types)Return Values 返回值

The next table describes the supported controller method return values. Reactive types are supported for all return values.
下表描述了支持的控制器方法返回值。所有返回值都支持响应式类型。

Controller method return value
控制器方法返回值

Description 描述

@ResponseBody

The return value is converted through HttpMessageConverter implementations and written to the response. See @ResponseBody.
返回值通过 HttpMessageConverter 实现转换并写入响应。见 @ResponseBody

HttpEntity<B>, ResponseEntity<B>

The return value that specifies the full response (including HTTP headers and body) is to be converted through HttpMessageConverter implementations and written to the response. See ResponseEntity.
返回值指定完整响应(包括 HTTP 头和主体)应通过 HttpMessageConverter 实现进行转换并写入响应。请参阅 ResponseEntity。

HttpHeaders

For returning a response with headers and no body.
用于返回带有头部但没有主体的响应。

String

A view name to be resolved with ViewResolver implementations and used together with the implicit model — determined through command objects and @ModelAttribute methods. The handler method can also programmatically enrich the model by declaring a Model argument (see Explicit Registrations).
一个用于与 ViewResolver 实现一起解析的视图名称,并用于与隐式模型一起使用——通过命令对象和 @ModelAttribute 方法确定。处理方法还可以通过声明一个 Model 参数(见显式注册)来程序化丰富模型。

View

A View instance to use for rendering together with the implicit model — determined through command objects and @ModelAttribute methods. The handler method can also programmatically enrich the model by declaring a Model argument (see Explicit Registrations).
一个用于与隐式模型一起渲染的 View 实例 —— 通过命令对象和 @ModelAttribute 方法确定。处理方法还可以通过声明一个 Model 参数(见显式注册)来编程丰富模型。

java.util.Map, org.springframework.ui.Model

Attributes to be added to the implicit model, with the view name implicitly determined through a RequestToViewNameTranslator.
属性将添加到隐式模型中,视图名称通过 RequestToViewNameTranslator 隐式确定。

@ModelAttribute

An attribute to be added to the model, with the view name implicitly determined through a RequestToViewNameTranslator.
一个要添加到模型中的属性,视图名称通过 RequestToViewNameTranslator 隐式确定。

Note that @ModelAttribute is optional. See "Any other return value" at the end of this table.
请注意, @ModelAttribute 是可选的。请参阅此表末尾的“任何其他返回值”。

ModelAndView objectModelAndView 对象

The view and model attributes to use and, optionally, a response status.
要使用的视图和模型属性以及可选的响应状态。

void

A method with a void return type (or null return value) is considered to have fully handled the response if it also has a ServletResponse, an OutputStream argument, or an @ResponseStatus annotation. The same is also true if the controller has made a positive ETag or lastModified timestamp check ( see Controllers for details).
一个具有 void 返回类型(或 null 返回值)的方法,如果它还具有 ServletResponseOutputStream 参数或 @ResponseStatus 注解,则被认为已完全处理了响应。如果控制器已经进行了积极的 ETaglastModified 时间戳检查(详见控制器部分),也是如此。

If none of the above is true, a void return type can also indicate “no response body” for REST controllers or a default view name selection for HTML controllers.
如果上述情况都不成立, void 返回类型也可以表示 REST 控制器中的“无响应体”或 HTML 控制器中的默认视图名称选择。

DeferredResult<V>

Produce any of the preceding return values asynchronously from any thread — for example, as a result of some event or callback. See Asynchronous Requests and DeferredResult.
异步地从任何线程生成前面的任何返回值——例如,作为某些事件或回调的结果。请参阅异步请求和 DeferredResult

Callable<V>

Produce any of the above return values asynchronously in a Spring MVC-managed thread. See Asynchronous Requests and Callable.
异步地在 Spring MVC 管理的线程中产生上述任何返回值。请参阅异步请求和 Callable

ListenableFuture<V>, java.util.concurrent.CompletionStage<V>, java.util.concurrent.CompletableFuture<V>

Alternative to DeferredResult, as a convenience (for example, when an underlying service returns one of those).
DeferredResult 的替代方案,作为一种便利(例如,当底层服务返回这些之一时)。

ResponseBodyEmitter, SseEmitter

Emit a stream of objects asynchronously to be written to the response with HttpMessageConverter implementations. Also supported as the body of a ResponseEntity. See Asynchronous Requests and HTTP Streaming.
异步发射对象流以写入响应,使用 HttpMessageConverter 实现。同时支持作为 ResponseEntity 的主体。请参阅异步请求和 HTTP 流。

StreamingResponseBody

Write to the response OutputStream asynchronously. Also supported as the body of a ResponseEntity. See Asynchronous Requests and HTTP Streaming.
异步写入响应 OutputStream 。也支持作为 ResponseEntity 的主体。参见异步请求和 HTTP 流。

Reactor and other reactive types registered via ReactiveAdapterRegistry
反应器和其他通过 ReactiveAdapterRegistry 注册的响应式类型

A single value type, e.g. Mono, is comparable to returning DeferredResult. A multi-value type, e.g. Flux, may be treated as a stream depending on the requested media type, e.g. "text/event-stream", "application/json+stream", or otherwise is collected to a List and rendered as a single value. See Asynchronous Requests and Reactive Types.
单个值类型,例如 Mono ,相当于返回 DeferredResult 。多值类型,例如 Flux ,根据请求的媒体类型,例如 "text/event-stream"、" application/json+stream",可能被视为流,否则收集到一个列表中,并作为单个值渲染。请参阅异步请求和响应式类型。

Other return values 其他返回值

If a return value remains unresolved in any other way, it is treated as a model attribute, unless it is a simple type as determined by BeanUtils#isSimpleProperty, in which case it remains unresolved.
如果返回值在其他任何方式下都无法解决,则将其视为模型属性,除非通过 BeanUtils#isSimpleProperty 确定其为简单类型,在这种情况下,它仍然未解决。

(#mvc-ann-typeconversion)Type Conversion 类型转换

Some annotated controller method arguments that represent String-based request input (such as @RequestParam, @RequestHeader, @PathVariable, @MatrixVariable, and @CookieValue) can require type conversion if the argument is declared as something other than String.
一些表示基于 String 的请求输入的注解控制器方法参数(如 @RequestParam@RequestHeader@PathVariable@MatrixVariable@CookieValue )如果参数声明为 String 以外的类型,则可能需要进行类型转换。

For such cases, type conversion is automatically applied based on the configured converters. By default, simple types ( int, long, Date, and others) are supported. You can customize type conversion through a WebDataBinder (see DataBinder) or by registering Formatters with the FormattingConversionService. See Spring Field Formatting.
对于此类情况,将自动应用类型转换,基于配置的转换器。默认情况下,支持简单类型( intlongDate 等)。您可以通过 WebDataBinder (见 DataBinder )自定义类型转换或通过 FormattingConversionService 注册 Formatters 。请参阅 Spring 字段格式化。

A practical issue in type conversion is the treatment of an empty String source value. Such a value is treated as missing if it becomes null as a result of type conversion. This can be the case for Long, UUID, and other target types. If you want to allow null to be injected, either use the required flag on the argument annotation, or declare the argument as @Nullable.
类型转换中的实际问题之一是处理空字符串源值。如果该值在类型转换后变为 null ,则被视为缺失。这可能适用于 LongUUID 和其他目标类型。如果您想允许注入 null ,则可以使用参数注解上的 required 标志,或将参数声明为 @Nullable

As of 5.3, non-null arguments will be enforced even after type conversion. If your handler method intends to accept a null value as well, either declare your argument as @Nullable or mark it as required=false in the corresponding @RequestParam, etc. annotation. This is a best practice and the recommended solution for regressions encountered in a 5.3 upgrade.
自 5.3 版本起,即使经过类型转换,也将强制执行非空参数。如果您的处理方法打算接受空值,则可以将参数声明为 @Nullable 或在其对应的 required=false 等注解中标记为 @RequestParam 。这是一个最佳实践,也是解决在 5.3 升级中遇到的回归问题的推荐解决方案。

Alternatively, you may specifically handle e.g. the resulting MissingPathVariableException in the case of a required @PathVariable. A null value after conversion will be treated like an empty original value, so the corresponding Missing…​Exception variants will be thrown.
或者,您可以特别处理例如所需的 @PathVariable 的情况下产生的 MissingPathVariableException 。转换后的空值将被视为空原始值,因此将抛出相应的 Missing…​Exception 变体。

(#mvc-ann-matrix-variables)Matrix Variables 矩阵变量

RFC 3986 discusses name-value pairs in path segments. In Spring MVC, we refer to those as “matrix variables” based on an “old post” by Tim Berners-Lee, but they can be also be referred to as URI path parameters.
RFC 3986 讨论了路径段中的名值对。在 Spring MVC 中,我们根据 Tim Berners-Lee 的一篇“旧文章”称其为“矩阵变量”,但它们也可以被称为 URI 路径参数。

Matrix variables can appear in any path segment, with each variable separated by a semicolon and multiple values separated by comma (for example, /cars;color=red,green;year=2012). Multiple values can also be specified through repeated variable names (for example, color=red;color=green;color=blue).
矩阵变量可以出现在任何路径段中,每个变量由分号分隔,多个值由逗号分隔(例如, /cars;color=red,green;year=2012 )。也可以通过重复变量名来指定多个值(例如, color=red;color=green;color=blue )。

If a URL is expected to contain matrix variables, the request mapping for a controller method must use a URI variable to mask that variable content and ensure the request can be matched successfully independent of matrix variable order and presence.
如果预期 URL 包含矩阵变量,控制器方法的请求映射必须使用 URI 变量来隐藏该变量内容,并确保请求能够成功匹配,无论矩阵变量顺序和是否存在。
The following example uses a matrix variable:
以下示例使用一个矩阵变量:

// GET /pets/42;q=11;r=22 @GetMapping("/pets/{petId}") public void findPet(@PathVariable String petId, @MatrixVariable int q) { // petId == 42 // q == 11 }
// GET /pets/42;q=11;r=22 @GetMapping("/pets/{petId}") fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) { // petId == 42 // q == 11 }

Given that all path segments may contain matrix variables, you may sometimes need to disambiguate which path variable the matrix variable is expected to be in. The following example shows how to do so:
考虑到所有路径段都可能包含矩阵变量,有时您可能需要区分矩阵变量应在哪个路径变量中。以下示例展示了如何进行区分:

// GET /owners/42;q=11/pets/21;q=22 @GetMapping("/owners/{ownerId}/pets/{petId}") public void findPet( @MatrixVariable(name="q", pathVar="ownerId") int q1, @MatrixVariable(name="q", pathVar="petId") int q2) { // q1 == 11 // q2 == 22 }
// GET /owners/42;q=11/pets/21;q=22 @GetMapping("/owners/{ownerId}/pets/{petId}") fun findPet( @MatrixVariable(name = "q", pathVar = "ownerId") q1: Int, @MatrixVariable(name = "q", pathVar = "petId") q2: Int) { // q1 == 11 // q2 == 22 }

A matrix variable may be defined as optional and a default value specified, as the following example shows:
一个矩阵变量可以被定义为可选的,并指定一个默认值,如下例所示:

// GET /pets/42 @GetMapping("/pets/{petId}") public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) { // q == 1 }
// GET /pets/42 @GetMapping("/pets/{petId}") fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) { // q == 1 }

To get all matrix variables, you can use a MultiValueMap, as the following example shows:
the following example shows: 获取所有矩阵变量,可以使用 MultiValueMap ,如下所示:

// GET /owners/42;q=11;r=12/pets/21;q=22;s=23 @GetMapping("/owners/{ownerId}/pets/{petId}") public void findPet( @MatrixVariable MultiValueMap<String, String> matrixVars, @MatrixVariable(pathVar="petId") MultiValueMap<String, String> petMatrixVars) { // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] // petMatrixVars: ["q" : 22, "s" : 23] }
// GET /owners/42;q=11;r=12/pets/21;q=22;s=23 @GetMapping("/owners/{ownerId}/pets/{petId}") fun findPet( @MatrixVariable matrixVars: MultiValueMap<String, String>, @MatrixVariable(pathVar="petId") petMatrixVars: MultiValueMap<String, String>) { // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23] // petMatrixVars: ["q" : 22, "s" : 23] }

Note that you need to enable the use of matrix variables. In the MVC Java configuration, you need to set a UrlPathHelper with removeSemicolonContent=false through Path Matching. In the MVC XML namespace, you can set <mvc:annotation-driven enable-matrix-variables="true"/>.
请注意,您需要启用矩阵变量的使用。在 MVC Java 配置中,您需要通过路径匹配设置 UrlPathHelperremoveSemicolonContent=false 。在 MVC XML 命名空间中,您可以设置 <mvc:annotation-driven enable-matrix-variables="true"/>

(#mvc-ann-requestparam)@RequestParam

You can use the @RequestParam annotation to bind Servlet request parameters (that is, query parameters or form data) to a method argument in a controller.
您可以使用 @RequestParam 注解将 Servlet 请求参数(即查询参数或表单数据)绑定到控制器的方法参数中。

The following example shows how to do so:
以下示例展示了如何这样做:

@Controller @RequestMapping("/pets") public class EditPetForm { // ... @GetMapping public String setupForm(@RequestParam("petId") int petId, Model model) { (1) Pet pet = this.clinic.loadPet(petId); model.addAttribute("pet", pet); return "petForm"; } // ... }

1

Using @RequestParam to bind petId.
使用 @RequestParam 绑定 petId

import org.springframework.ui.set @Controller @RequestMapping("/pets") class EditPetForm { // ... @GetMapping fun setupForm(@RequestParam("petId") petId: Int, model: Model): String { (1) val pet = this.clinic.loadPet(petId); model["pet"] = pet return "petForm" } // ... }

1

Using @RequestParam to bind petId.

By default, method parameters that use this annotation are required, but you can specify that a method parameter is optional by setting the @RequestParam annotation’s required flag to false or by declaring the argument with an java.util.Optional wrapper.
默认情况下,使用此注解的方法参数是必需的,但您可以通过将 @RequestParam 注解的 required 标志设置为 false 或将参数声明为带有 java.util.Optional 包装器的参数来指定方法参数是可选的。

Type conversion is automatically applied if the target method parameter type is not String. See Type Conversion.
类型转换在目标方法参数类型不是 String 时自动应用。请参阅类型转换。

Declaring the argument type as an array or list allows for resolving multiple parameter values for the same parameter name.
声明参数类型为数组或列表,允许解析相同参数名的多个参数值。

When an @RequestParam annotation is declared as a Map<String, String> or MultiValueMap<String, String>, without a parameter name specified in the annotation, then the map is populated with the request parameter values for each given parameter name.
当一个 @RequestParam 注解被声明为 Map<String, String>MultiValueMap<String, String> ,且注解中没有指定参数名称时,则映射中填充了每个给定参数名称的请求参数值。

Note that use of @RequestParam is optional (for example, to set its attributes). By default, any argument that is a simple value type (as determined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver, is treated as if it were annotated with @RequestParam.
请注意,使用 @RequestParam 是可选的(例如,用于设置其属性)。默认情况下,任何由 BeanUtils#isSimpleProperty 确定的简单值类型(且未被任何其他参数解析器解析)的参数,都视为已标注为 @RequestParam

You can use the @RequestHeader annotation to bind a request header to a method argument in a controller.
您可以使用 @RequestHeader 注解将请求头绑定到控制器的方法参数中。

Consider the following request, with headers:
考虑以下带有标题的请求:

Host localhost:8080 Accept text/html,application/xhtml+xml,application/xml;q=0.9 Accept-Language fr,en-gb;q=0.7,en;q=0.3 Accept-Encoding gzip,deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 300

The following example gets the value of the Accept-Encoding and Keep-Alive headers:
以下示例获取了 Accept-EncodingKeep-Alive 头部的值:

@GetMapping("/demo") public void handle( @RequestHeader("Accept-Encoding") String encoding, (1) @RequestHeader("Keep-Alive") long keepAlive) { (2) //... }

1

Get the value of the Accept-Encoding header.
获取 Accept-Encoding 头部的值。

2

Get the value of the Keep-Alive header.
获取 Keep-Alive 头部的值。

@GetMapping("/demo") fun handle( @RequestHeader("Accept-Encoding") encoding: String, (1) @RequestHeader("Keep-Alive") keepAlive: Long) { (2) //... }

1

Get the value of the Accept-Encoding header.

2

Get the value of the Keep-Alive header.

If the target method parameter type is not String, type conversion is automatically applied. See Type Conversion.
如果目标方法参数类型不是 String ,则会自动应用类型转换。请参阅类型转换。

When an @RequestHeader annotation is used on a Map<String, String>, MultiValueMap<String, String>, or HttpHeaders argument, the map is populated with all header values.
当在 Map<String, String>MultiValueMap<String, String>HttpHeaders 参数上使用 @RequestHeader 注解时,该映射将包含所有头部值。

Built-in support is available for converting a comma-separated string into an array or collection of strings or other types known to the type conversion system. For example, a method parameter annotated with @RequestHeader("Accept") can be of type String but also String or List<String>.
内置支持将逗号分隔的字符串转换为数组或字符串或其他类型转换系统所知的集合。例如,一个用 @RequestHeader("Accept") 注解的方法参数可以是 String 类型,也可以是 StringList<String> 类型。

(#mvc-ann-cookievalue)@CookieValue

You can use the @CookieValue annotation to bind the value of an HTTP cookie to a method argument in a controller.
您可以使用 @CookieValue 注解将 HTTP cookie 的值绑定到控制器的方法参数中。

Consider a request with the following cookie:
考虑以下 cookie 的请求:

JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84

The following example shows how to get the cookie value:
以下示例展示了如何获取 cookie 值:

@GetMapping("/demo") public void handle(@CookieValue("JSESSIONID") String cookie) { (1) //... }

1

Get the value of the JSESSIONID cookie.
获取 JSESSIONID cookie 的值。

@GetMapping("/demo") fun handle(@CookieValue("JSESSIONID") cookie: String) { (1) //... }

1

Get the value of the JSESSIONID cookie.

If the target method parameter type is not String, type conversion is applied automatically. See Type Conversion.
如果目标方法参数类型不是 String ,则会自动应用类型转换。请参阅类型转换。

(#mvc-ann-modelattrib-method-args)@ModelAttribute

You can use the @ModelAttribute annotation on a method argument to access an attribute from the model or have it be instantiated if not present. The model attribute is also overlain with values from HTTP Servlet request parameters whose names match to field names.
您可以使用 @ModelAttribute 注解在方法参数上访问模型中的属性,或者如果不存在则实例化它。模型属性还会覆盖与字段名称匹配的 HTTP Servlet 请求参数的值。
This is referred to as data binding, and it saves you from having to deal with parsing and converting individual query parameters and form fields. The following example shows how to do so:
这是指数据绑定,它可以让你免于处理解析和转换单个查询参数和表单字段。以下示例展示了如何进行操作:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute Pet pet) { // method logic... }

1

Adding a BindingResult next to the @ModelAttribute.
添加一个 BindingResult@ModelAttribute 后面。

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") fun processSubmit(@ModelAttribute pet: Pet): String { // method logic... }

The Pet instance above is sourced in one of the following ways:
上述 Pet 实例可以通过以下方式之一获取:

  • Retrieved from the model where it may have been added by a @ModelAttribute method.
    从可能通过 @ModelAttribute 方法添加到模型中的位置检索。

  • Retrieved from the HTTP session if the model attribute was listed in the class-level @SessionAttributes annotation.
    从 HTTP 会话中检索,如果模型属性在类级别的 @SessionAttributes 注解中列出。

  • Obtained through a Converter where the model attribute name matches the name of a request value such as a path variable or a request parameter (see next example).
    通过一个 Converter 获取,其中模型属性名称与请求值(如路径变量或请求参数)的名称匹配(见下一个示例)。

  • Instantiated using its default constructor.
    使用其默认构造函数实例化。

  • Instantiated through a “primary constructor” with arguments that match to Servlet request parameters. Argument names are determined through JavaBeans @ConstructorProperties or through runtime-retained parameter names in the bytecode.
    通过具有与 Servlet 请求参数匹配的参数的“主构造函数”实例化。参数名称通过 JavaBeans @ConstructorProperties 确定,或通过运行时保留的字节码中的参数名称确定。

One alternative to using a @ModelAttribute method to supply it or relying on the framework to create the model attribute, is to have a Converter<String, T> to provide the instance. This is applied when the model attribute name matches to the name of a request value such as a path variable or a request parameter, and there is a Converter from String to the model attribute type. In the following example, the model attribute name is account which matches the URI path variable account, and there is a registered Converter<String, Account> which could load the Account from a data store:
一种替代使用 @ModelAttribute 方法提供它或依赖框架创建模型属性的方法,是使用 Converter<String, T> 来提供实例。这适用于模型属性名称与请求值(如路径变量或请求参数)的名称匹配,并且存在从 String 到模型属性类型的 Converter 。在以下示例中,模型属性名称是 account ,它与 URI 路径变量 account 匹配,并且存在一个已注册的 Converter<String, Account> ,可以从数据存储中加载 Account

@PutMapping("/accounts/{account}") public String save(@ModelAttribute("account") Account account) { // ... }

1

Adding a BindingResult next to the @ModelAttribute.
添加一个 BindingResult@ModelAttribute 后面。

@PutMapping("/accounts/{account}") fun save(@ModelAttribute("account") account: Account): String { // ... }

After the model attribute instance is obtained, data binding is applied. The WebDataBinder class matches Servlet request parameter names (query parameters and form fields) to field names on the target Object. Matching fields are populated after type conversion is applied, where necessary. For more on data binding (and validation), see Validation. For more on customizing data binding, see DataBinder.
在获取模型属性实例后,应用数据绑定。 WebDataBinder 类将 Servlet 请求参数名称(查询参数和表单字段)与目标 Object 上的字段名称匹配。匹配的字段在必要时应用类型转换后填充。有关数据绑定(以及验证)的更多信息,请参阅验证。有关自定义数据绑定的更多信息,请参阅 DataBinder

Data binding can result in errors. By default, a BindException is raised. However, to check for such errors in the controller method, you can add a BindingResult argument immediately next to the @ModelAttribute, as the following example shows:
数据绑定可能导致错误。默认情况下,会抛出 BindException 异常。然而,为了在控制器方法中检查此类错误,您可以在 @ModelAttribute 旁边立即添加一个 BindingResult 参数,如下例所示:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { (1) if (result.hasErrors()) { return "petForm"; } // ... }

1

Setting @ModelAttribute(binding=false). 设置 @ModelAttribute(binding=false)

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1) if (result.hasErrors()) { return "petForm" } // ... }

In some cases, you may want access to a model attribute without data binding. For such cases, you can inject the Model into the controller and access it directly or, alternatively, set @ModelAttribute(binding=false), as the following example shows:
在某些情况下,您可能希望在无需数据绑定的情况下访问模型属性。对于此类情况,您可以将 Model 注入到控制器中并直接访问它,或者,如以下示例所示,设置 @ModelAttribute(binding=false)

@ModelAttribute public AccountForm setUpForm() { return new AccountForm(); } @ModelAttribute public Account findAccount(@PathVariable String accountId) { return accountRepository.findOne(accountId); } @PostMapping("update") public String update(@Valid AccountForm form, BindingResult result, @ModelAttribute(binding=false) Account account) { (1) // ... }

1

Setting @ModelAttribute(binding=false). 设置 @ModelAttribute(binding=false)

@ModelAttribute fun setUpForm(): AccountForm { return AccountForm() } @ModelAttribute fun findAccount(@PathVariable accountId: String): Account { return accountRepository.findOne(accountId) } @PostMapping("update") fun update(@Valid form: AccountForm, result: BindingResult, @ModelAttribute(binding = false) account: Account): String { (1) // ... }

You can automatically apply validation after data binding by adding the javax.validation.Valid annotation or Spring’s @Validated annotation (Bean Validation and Spring validation). The following example shows how to do so:
您可以通过添加 javax.validation.Valid 注解或 Spring 的 @Validated 注解(Bean Validation 和 Spring 验证)来自动应用数据绑定后的验证。以下示例展示了如何操作:

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { (1) if (result.hasErrors()) { return "petForm"; } // ... }

1

Validate the Pet instance.
验证 Pet 实例。

@PostMapping("/owners/{ownerId}/pets/{petId}/edit") fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { (1) if (result.hasErrors()) { return "petForm" } // ... }

Note that using @ModelAttribute is optional (for example, to set its attributes). By default, any argument that is not a simple value type (as determined by BeanUtils#isSimpleProperty) and is not resolved by any other argument resolver is treated as if it were annotated with @ModelAttribute.
请注意,使用 @ModelAttribute 是可选的(例如,用于设置其属性)。默认情况下,任何不是简单值类型(由 BeanUtils#isSimpleProperty 确定)且未被任何其他参数解析器解析的参数,都视为已标注为 @ModelAttribute

(#mvc-ann-sessionattributes)@SessionAttributes

@SessionAttributes is used to store model attributes in the HTTP Servlet session between requests. It is a type-level annotation that declares the session attributes used by a specific controller.
@SessionAttributes 用于在请求之间在 HTTP Servlet 会话中存储模型属性。它是一个类型级别的注解,用于声明特定控制器使用的会话属性。
This typically lists the names of model attributes or types of model attributes that should be transparently stored in the session for subsequent requests to access.
这通常列出应透明存储在会话中以便后续请求访问的模型属性名称或模型属性类型。

The following example uses the @SessionAttributes annotation:
以下示例使用了 @SessionAttributes 注解:

@Controller @SessionAttributes("pet") (1) public class EditPetForm { // ... }

1

Using the @SessionAttributes annotation.
使用 @SessionAttributes 注解。

@Controller @SessionAttributes("pet") (1) class EditPetForm { // ... }

1

Using the @SessionAttributes annotation.

On the first request, when a model attribute with the name, pet, is added to the model, it is automatically promoted to and saved in the HTTP Servlet session. It remains there until another controller method uses a SessionStatus method argument to clear the storage, as the following example shows:
在第一次请求时,当添加名为 pet 的模型属性到模型中,它会被自动提升并保存在 HTTP Servlet 会话中。它将保留在那里,直到另一个控制器方法使用 SessionStatus 方法参数来清除存储,如下例所示:

@Controller @SessionAttributes("pet") (1) public class EditPetForm { // ... @PostMapping("/pets/{id}") public String handle(Pet pet, BindingResult errors, SessionStatus status) { if (errors.hasErrors) { // ... } status.setComplete(); (2) // ... } }

1

Storing the Pet value in the Servlet session.
存储 Pet 值在 Servlet 会话中。

2

Clearing the Pet value from the Servlet session.
清除 Servlet 会话中的 Pet 值。

@Controller @SessionAttributes("pet") (1) class EditPetForm { // ... @PostMapping("/pets/{id}") fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String { if (errors.hasErrors()) { // ... } status.setComplete() (2) // ... } }

1

Storing the Pet value in the Servlet session.

2

Clearing the Pet value from the Servlet session.

(#mvc-ann-sessionattribute)@SessionAttribute

If you need access to pre-existing session attributes that are managed globally (that is, outside the controller — for example, by a filter) and may or may not be present, you can use the @SessionAttribute annotation on a method parameter, as the following example shows:
如果您需要访问全局(即在控制器之外,例如通过过滤器)管理的现有会话属性,这些属性可能存在也可能不存在,您可以在方法参数上使用 @SessionAttribute 注解,如下例所示:

@RequestMapping("/") public String handle(@SessionAttribute User user) { (1) // ... }

1

Using a @SessionAttribute annotation. 使用一个 @SessionAttribute 注解。

@RequestMapping("/") fun handle(@SessionAttribute user: User): String { (1) // ... }

For use cases that require adding or removing session attributes, consider injecting org.springframework.web.context.request.WebRequest or javax.servlet.http.HttpSession into the controller method.
为需要添加或删除会话属性的用例,考虑在控制器方法中注入 org.springframework.web.context.request.WebRequestjavax.servlet.http.HttpSession

For temporary storage of model attributes in the session as part of a controller workflow, consider using @SessionAttributes as described in @SessionAttributes.
为了在控制器工作流程中将模型属性临时存储在会话中,请考虑使用 @SessionAttributes 中描述的 @SessionAttributes

(#mvc-ann-requestattrib)@RequestAttribute

Similar to @SessionAttribute, you can use the @RequestAttribute annotations to access pre-existing request attributes created earlier (for example, by a Servlet Filter or HandlerInterceptor):
类似于 @SessionAttribute ,您可以使用 @RequestAttribute 注解来访问之前创建的现有请求属性(例如,由 Servlet FilterHandlerInterceptor 创建的):

@GetMapping("/") public String handle(@RequestAttribute Client client) { (1) // ... }

1

Using the @RequestAttribute annotation.
使用 @RequestAttribute 注解。

@GetMapping("/") fun handle(@RequestAttribute client: Client): String { (1) // ... }

1

Using the @RequestAttribute annotation.

(#mvc-redirecting-passing-data)Redirect Attributes 重定向属性

By default, all model attributes are considered to be exposed as URI template variables in the redirect URL. Of the remaining attributes, those that are primitive types or collections or arrays of primitive types are automatically appended as query parameters.
默认情况下,所有模型属性都被视为在重定向 URL 中以 URI 模板变量的形式暴露。剩余的属性中,那些是原始类型或原始类型的集合或数组的是自动附加为查询参数的。

Appending primitive type attributes as query parameters can be the desired result if a model instance was prepared specifically for the redirect.
追加原始类型属性作为查询参数,如果为重定向专门准备了模型实例,则可能是期望的结果。
However, in annotated controllers, the model can contain additional attributes added for rendering purposes (for example, drop-down field values). To avoid the possibility of having such attributes appear in the URL, a @RequestMapping method can declare an argument of type RedirectAttributes and use it to specify the exact attributes to make available to RedirectView. If the method does redirect, the content of RedirectAttributes is used. Otherwise, the content of the model is used.
然而,在注解控制器中,模型可以包含为渲染目的添加的额外属性(例如,下拉字段值)。为了避免这些属性出现在 URL 中的可能性,可以使用 @RequestMapping 方法声明一个类型为 RedirectAttributes 的参数,并使用它来指定要提供给 RedirectView 的确切属性。如果方法重定向,则使用 RedirectAttributes 的内容。否则,使用模型的内容。

The RequestMappingHandlerAdapter provides a flag called ignoreDefaultModelOnRedirect, which you can use to indicate that the content of the default Model should never be used if a controller method redirects. Instead, the controller method should declare an attribute of type RedirectAttributes or, if it does not do so, no attributes should be passed on to RedirectView. Both the MVC namespace and the MVC Java configuration keep this flag set to false, to maintain backwards compatibility. However, for new applications, we recommend setting it to true.
RequestMappingHandlerAdapter 提供了一个名为 ignoreDefaultModelOnRedirect 的标志,您可以使用它来指示如果控制器方法重定向,则不应使用默认的 Model 的内容。相反,控制器方法应声明一个类型为 RedirectAttributes 的属性,或者如果不这样做,则不应将任何属性传递给 RedirectView 。MVC 命名空间和 MVC Java 配置都将此标志设置为 false ,以保持向后兼容性。然而,对于新应用程序,我们建议将其设置为 true

Note that URI template variables from the present request are automatically made available when expanding a redirect URL, and you don’t need to explicitly add them through Model or RedirectAttributes. The following example shows how to define a redirect:
请注意,当前请求的 URI 模板变量在展开重定向 URL 时自动可用,您无需通过 ModelRedirectAttributes 显式添加。以下示例展示了如何定义重定向:

@PostMapping("/files/{path}") public String upload(...) { // ... return "redirect:files/{path}"; }
@PostMapping("/files/{path}") fun upload(...): String { // ... return "redirect:files/{path}" }

Another way of passing data to the redirect target is by using flash attributes. Unlike other redirect attributes, flash attributes are saved in the HTTP session (and, hence, do not appear in the URL). See Flash Attributes for more information.
另一种将数据传递给重定向目标的方法是使用闪存属性。与其它重定向属性不同,闪存属性保存在 HTTP 会话中(因此不会出现在 URL 中)。有关更多信息,请参阅闪存属性。

(#mvc-flash-attributes)Flash Attributes . 闪存属性

Flash attributes provide a way for one request to store attributes that are intended for use in another. This is most commonly needed when redirecting — for example, the Post-Redirect-Get pattern.
Flash 属性提供了一种方式,允许一个请求存储打算用于另一个请求的属性。这在重定向时最为常见,例如,Post-Redirect-Get 模式。
Flash attributes are saved temporarily before the redirect (typically in the session) to be made available to the request after the redirect and are removed immediately.
Flash 属性在重定向之前临时保存(通常在会话中),以便在重定向后可供请求使用,然后立即删除。

Spring MVC has two main abstractions in support of flash attributes. FlashMap is used to hold flash attributes, while FlashMapManager is used to store, retrieve, and manage FlashMap instances.
Spring MVC 支持闪存属性有两个主要抽象。 FlashMap 用于存储闪存属性,而 FlashMapManager 用于存储、检索和管理 FlashMap 实例。

Flash attribute support is always “on” and does not need to be enabled explicitly. However, if not used, it never causes HTTP session creation. On each request, there is an “input” FlashMap with attributes passed from a previous request ( if any) and an “output” FlashMap with attributes to save for a subsequent request. Both FlashMap instances are accessible from anywhere in Spring MVC through static methods in RequestContextUtils.
Flash 属性支持始终是“开启”状态,无需显式启用。然而,如果不使用,它永远不会导致 HTTP 会话创建。在每个请求中,都有一个“输入” FlashMap ,其中包含从上一个请求传递过来的属性(如果有),以及一个“输出” FlashMap ,其中包含要保存以供后续请求使用的属性。这两个 FlashMap 实例都可以通过 RequestContextUtils 中的静态方法在任何 Spring MVC 位置访问。

Annotated controllers typically do not need to work with FlashMap directly. Instead, a @RequestMapping method can accept an argument of type RedirectAttributes and use it to add flash attributes for a redirect scenario. Flash attributes added through RedirectAttributes are automatically propagated to the “output” FlashMap. Similarly, after the redirect, attributes from the “input” FlashMap are automatically added to the Model of the controller that serves the target URL.
注解控制器通常不需要直接与 FlashMap 交互。相反,一个 @RequestMapping 方法可以接受一个类型为 RedirectAttributes 的参数,并使用它为重定向场景添加闪存属性。通过 RedirectAttributes 添加的闪存属性会自动传播到“输出”FlashMap。同样,在重定向之后,“输入” FlashMap 的属性会自动添加到服务目标 URL 的控制器 Model 中。

(#mvc-multipart-forms)Multipart 多部分

After a MultipartResolver has been enabled, the content of POST requests with multipart/form-data is parsed and accessible as regular request parameters. The following example accesses one regular form field and one uploaded file:
在启用 MultipartResolver 之后,带有 multipart/form-data 的 POST 请求内容将被解析并可作为常规请求参数访问。以下示例访问了一个常规表单字段和一个上传的文件:

@Controller public class FileUploadController { @PostMapping("/form") public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) { if (!file.isEmpty()) { byte bytes = file.getBytes(); // store the bytes somewhere return "redirect:uploadSuccess"; } return "redirect:uploadFailure"; } }
@Controller class FileUploadController { @PostMapping("/form") fun handleFormUpload(@RequestParam("name") name: String, @RequestParam("file") file: MultipartFile): String { if (!file.isEmpty) { val bytes = file.bytes // store the bytes somewhere return "redirect:uploadSuccess" } return "redirect:uploadFailure" } }

Declaring the argument type as a List<MultipartFile> allows for resolving multiple files for the same parameter name.
声明参数类型为 List<MultipartFile> 允许解析具有相同参数名称的多个文件。

When the @RequestParam annotation is declared as a Map<String, MultipartFile> or MultiValueMap<String, MultipartFile>, without a parameter name specified in the annotation, then the map is populated with the multipart files for each given parameter name.
@RequestParam 注解被声明为 Map<String, MultipartFile>MultiValueMap<String, MultipartFile> 时,如果没有在注解中指定参数名称,则对于每个给定的参数名称,映射中将填充多部分文件。

With Servlet 3.0 multipart parsing, you may also declare javax.servlet.http.Part instead of Spring’s MultipartFile, as a method argument or collection value type.
使用 Servlet 3.0 的多部分解析,您也可以将 javax.servlet.http.Part 声明为 Spring 的 MultipartFile ,作为方法参数或集合值类型。

You can also use multipart content as part of data binding to a command object. For example, the form field and file from the preceding example could be fields on a form object, as the following example shows:
您还可以将多部分内容作为数据绑定到命令对象的一部分。例如,前面示例中的表单字段和文件可以作为表单对象上的字段,如下例所示:

class MyForm { private String name; private MultipartFile file; // ... } @Controller public class FileUploadController { @PostMapping("/form") public String handleFormUpload(MyForm form, BindingResult errors) { if (!form.getFile().isEmpty()) { byte bytes = form.getFile().getBytes(); // store the bytes somewhere return "redirect:uploadSuccess"; } return "redirect:uploadFailure"; } }
class MyForm(val name: String, val file: MultipartFile, ...) @Controller class FileUploadController { @PostMapping("/form") fun handleFormUpload(form: MyForm, errors: BindingResult): String { if (!form.file.isEmpty) { val bytes = form.file.bytes // store the bytes somewhere return "redirect:uploadSuccess" } return "redirect:uploadFailure" } }

Multipart requests can also be submitted from non-browser clients in a RESTful service scenario. The following example shows a file with JSON:
多部分请求也可以在 RESTful 服务场景中从非浏览器客户端提交。以下示例显示了一个包含 JSON 的文件:

POST /someUrl Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="meta-data" Content-Type: application/json; charset=UTF-8 Content-Transfer-Encoding: 8bit

{ "name": "value" } --edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp Content-Disposition: form-data; name="file-data"; filename="file.properties" Content-Type: text/xml Content-Transfer-Encoding: 8bit ... File Data ...

You can access the "meta-data" part with @RequestParam as a String but you’ll probably want it deserialized from JSON (similar to @RequestBody). Use the @RequestPart annotation to access a multipart after converting it with an HttpMessageConverter:
您可以使用 @RequestParam 作为 String 来访问“元数据”部分,但您可能希望将其从 JSON 反序列化(类似于 @RequestBody )。使用 @RequestPart 注解在将其转换为 HttpMessageConverter 后访问多部分:

@PostMapping("/") public String handle(@RequestPart("meta-data") MetaData metadata, @RequestPart("file-data") MultipartFile file) { // ... }
@PostMapping("/") fun handle(@RequestPart("meta-data") metadata: MetaData, @RequestPart("file-data") file: MultipartFile): String { // ... }

You can use @RequestPart in combination with javax.validation.Valid or use Spring’s @Validated annotation, both of which cause Standard Bean Validation to be applied. By default, validation errors cause a MethodArgumentNotValidException, which is turned into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally within the controller through an Errors or BindingResult argument, as the following example shows:
您可以使用 @RequestPartjavax.validation.Valid 结合使用,或者使用 Spring 的 @Validated 注解,这两种方式都会应用标准 Bean 验证。默认情况下,验证错误会导致一个 MethodArgumentNotValidException ,这会被转换为 400(BAD_REQUEST)响应。或者,您可以通过 ErrorsBindingResult 参数在控制器中本地处理验证错误,如下例所示:

@PostMapping("/") public String handle(@Valid @RequestPart("meta-data") MetaData metadata, BindingResult result) { // ... }
@PostMapping("/") fun handle(@Valid @RequestPart("meta-data") metadata: MetaData, result: BindingResult): String { // ... }

(#mvc-ann-requestbody)@RequestBody

You can use the @RequestBody annotation to have the request body read and deserialized into an Object through an HttpMessageConverter. The following example uses a @RequestBody argument:
您可以使用 @RequestBody 注解通过 HttpMessageConverter 将请求体读取并反序列化为 Object 。以下示例使用 @RequestBody 参数:

@PostMapping("/accounts") public void handle(@RequestBody Account account) { // ... }
@PostMapping("/accounts") fun handle(@RequestBody account: Account) { // ... }

You can use the Message Converters option of the MVC Config to configure or customize message conversion.
您可以使用 MVC 配置中的消息转换器选项来配置或自定义消息转换。

You can use @RequestBody in combination with javax.validation.Valid or Spring’s @Validated annotation, both of which cause Standard Bean Validation to be applied. By default, validation errors cause a MethodArgumentNotValidException, which is turned into a 400 (BAD_REQUEST) response. Alternatively, you can handle validation errors locally within the controller through an Errors or BindingResult argument, as the following example shows:
您可以使用 @RequestBodyjavax.validation.Valid 或 Spring 的 @Validated 注解结合使用,这两者都会应用标准 Bean 验证。默认情况下,验证错误会导致一个 MethodArgumentNotValidException ,这会被转换为 400(BAD_REQUEST)响应。或者,您可以通过 ErrorsBindingResult 参数在控制器中本地处理验证错误,如下例所示:

@PostMapping("/accounts") public void handle(@Valid @RequestBody Account account, BindingResult result) { // ... }
@PostMapping("/accounts") fun handle(@Valid @RequestBody account: Account, result: BindingResult) { // ... }

(#mvc-ann-httpentity)HttpEntity

HttpEntity is more or less identical to using @RequestBody but is based on a container object that exposes request headers and body. The following listing shows an example:
HttpEntity 大约等同于使用 @RequestBody ,但基于一个暴露请求头和体的容器对象。以下列表显示了一个示例:

@PostMapping("/accounts") public void handle(HttpEntity<Account> entity) { // ... }
@PostMapping("/accounts") fun handle(entity: HttpEntity<Account>) { // ... }

(#mvc-ann-responsebody)@ResponseBody

You can use the @ResponseBody annotation on a method to have the return serialized to the response body through an HttpMessageConverter. The following listing shows an example:
您可以使用 @ResponseBody 注解在方法上,将返回值序列化到响应体中,通过 HttpMessageConverter。以下列表显示了一个示例:

@GetMapping("/accounts/{id}") @ResponseBody public Account handle() { // ... }
@GetMapping("/accounts/{id}") @ResponseBody fun handle(): Account { // ... }

@ResponseBody is also supported at the class level, in which case it is inherited by all controller methods. This is the effect of @RestController, which is nothing more than a meta-annotation marked with @Controller and @ResponseBody.
@ResponseBody 也在类级别上得到支持,在这种情况下,它会被所有控制器方法继承。这就是 @RestController 的效果,它不过是一个标记了 @Controller@ResponseBody 的元注解。

You can use @ResponseBody with reactive types. See Asynchronous Requests and Reactive Types for more details.
您可以使用 @ResponseBody 与响应式类型一起使用。有关更多详细信息,请参阅异步请求和响应式类型。

You can use the Message Converters option of the MVC Config to configure or customize message conversion.
您可以使用 MVC 配置中的消息转换器选项来配置或自定义消息转换。

You can combine @ResponseBody methods with JSON serialization views. See Jackson JSON for details.
您可以将 @ResponseBody 方法与 JSON 序列化视图结合使用。有关详细信息,请参阅 Jackson JSON。

(#mvc-ann-responseentity)ResponseEntity 响应实体

ResponseEntity is like @ResponseBody but with status and headers. For example:
ResponseEntity 类似于 @ResponseBody ,但包含状态和头信息。例如:

@GetMapping("/something") public ResponseEntity<String> handle() { String body = ... ; String etag = ... ; return ResponseEntity.ok().eTag(etag).body(body); }
@GetMapping("/something") fun handle(): ResponseEntity<String> { val body = ... val etag = ... return ResponseEntity.ok().eTag(etag).build(body) }

Spring MVC supports using a single value reactive type to produce the ResponseEntity asynchronously, and/or single and multi-value reactive types for the body. This allows the following types of async responses:
Spring MVC 支持使用单个值响应式类型异步产生 ResponseEntity ,以及/或用于主体的单值和多值响应式类型。这允许以下类型的异步响应:

  • ResponseEntity<Mono<T>> or ResponseEntity<Flux<T>> make the response status and headers known immediately while the body is provided asynchronously at a later point. Use Mono if the body consists of 0..1 values or Flux if it can produce multiple values.
    ResponseEntity<Mono<T>>ResponseEntity<Flux<T>> 立即使响应状态和头部信息可知,而主体内容将在稍后异步提供。如果主体包含 0..1 个值,请使用 Mono ,如果可以产生多个值,请使用 Flux

  • Mono<ResponseEntity<T>> provides all three — response status, headers, and body, asynchronously at a later point. This allows the response status and headers to vary depending on the outcome of asynchronous request handling.
    Mono<ResponseEntity<T>> 在稍后的时间异步提供所有三项——响应状态、头信息和主体。这允许响应状态和头信息根据异步请求处理的结果而变化。

(#mvc-ann-jackson)Jackson JSON Jackson JSON 杰克逊 JSON

Spring offers support for the Jackson JSON library.
Spring 支持 Jackson JSON 库。

(#mvc-ann-jsonview)JSON Views JSON 视图

Spring MVC provides built-in support for Jackson’s Serialization Views, which allow rendering only a subset of all fields in an Object. To use it with @ResponseBody or ResponseEntity controller methods, you can use Jackson’s @JsonView annotation to activate a serialization view class, as the following example shows:
Spring MVC 为 Jackson 的序列化视图提供了内置支持,允许仅渲染 Object 中所有字段的一个子集。要与其 @ResponseBodyResponseEntity 控制器方法一起使用,您可以使用 Jackson 的 @JsonView 注解激活一个序列化视图类,如下例所示:

@RestController public class UserController { @GetMapping("/user") @JsonView(User.WithoutPasswordView.class) public User getUser() { return new User("eric", "7!jd#h23"); } } public class User { public interface WithoutPasswordView {}; public interface WithPasswordView extends WithoutPasswordView {}; private String username; private String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } @JsonView(WithoutPasswordView.class) public String getUsername() { return this.username; } @JsonView(WithPasswordView.class) public String getPassword() { return this.password; } }
@RestController class UserController { @GetMapping("/user") @JsonView(User.WithoutPasswordView::class) fun getUser() = User("eric", "7!jd#h23") } class User( @JsonView(WithoutPasswordView::class) val username: String, @JsonView(WithPasswordView::class) val password: String) { interface WithoutPasswordView interface WithPasswordView : WithoutPasswordView }

@JsonView allows an array of view classes, but you can specify only one per controller method. If you need to activate multiple views, you can use a composite interface.
@JsonView 允许一个视图类数组,但每个控制器方法只能指定一个。如果您需要激活多个视图,可以使用组合接口。

If you want to do the above programmatically, instead of declaring an @JsonView annotation, wrap the return value with MappingJacksonValue and use it to supply the serialization view:
如果您想以编程方式完成上述操作,而不是声明一个 @JsonView 注解,请将返回值包裹在 MappingJacksonValue 中,并使用它来提供序列化视图:

@RestController public class UserController { @GetMapping("/user") public MappingJacksonValue getUser() { User user = new User("eric", "7!jd#h23"); MappingJacksonValue value = new MappingJacksonValue(user); value.setSerializationView(User.WithoutPasswordView.class); return value; } }
@RestController class UserController { @GetMapping("/user") fun getUser(): MappingJacksonValue { val value = MappingJacksonValue(User("eric", "7!jd#h23")) value.serializationView = User.WithoutPasswordView::class.java return value } }

For controllers that rely on view resolution, you can add the serialization view class to the model, as the following example shows:
对于依赖于视图解析的控制器,您可以将序列化视图类添加到模型中,如下例所示:

@Controller public class UserController extends AbstractController { @GetMapping("/user") public String getUser(Model model) { model.addAttribute("user", new User("eric", "7!jd#h23")); model.addAttribute(JsonView.class.getName(), User.WithoutPasswordView.class); return "userView"; } }
import org.springframework.ui.set @Controller class UserController : AbstractController() { @GetMapping("/user") fun getUser(model: Model): String { model["user"] = User("eric", "7!jd#h23") model[JsonView::class.qualifiedName] = User.WithoutPasswordView::class.java return "userView" } }

(#mvc-ann-modelattrib-methods)1.3.4. Model 1.3.4. 模型

You can use the @ModelAttribute annotation:
您可以使用 @ModelAttribute 注解:

  • On a method argument in @RequestMapping methods to create or access an Object from the model and to bind it to the request through a WebDataBinder.
    @RequestMapping 方法中,方法参数用于创建或访问模型中的 Object ,并通过 WebDataBinder 将其绑定到请求上。

  • As a method-level annotation in @Controller or @ControllerAdvice classes that help to initialize the model prior to any @RequestMapping method invocation.
    作为一种在 @Controller@ControllerAdvice 类中的方法级别注解,有助于在调用任何 @RequestMapping 方法之前初始化模型。

  • On a @RequestMapping method to mark its return value is a model attribute.
    @RequestMapping 方法上标记其返回值是一个模型属性。

This section discusses @ModelAttribute methods — the second item in the preceding list. A controller can have any number of @ModelAttribute methods. All such methods are invoked before @RequestMapping methods in the same controller. A @ModelAttribute method can also be shared across controllers through @ControllerAdvice. See the section on Controller Advice for more details.
本节讨论 @ModelAttribute 方法——前述列表中的第二项。控制器可以有任意数量的 @ModelAttribute 方法。所有这些方法都在同一控制器中的 @RequestMapping 方法之前被调用。 @ModelAttribute 方法也可以通过 @ControllerAdvice 在控制器之间共享。有关更多详细信息,请参阅控制器建议部分。

@ModelAttribute methods have flexible method signatures. They support many of the same arguments as @RequestMapping methods, except for @ModelAttribute itself or anything related to the request body.
@ModelAttribute 方法具有灵活的方法签名。它们支持与 @RequestMapping 方法相同的许多参数,除了 @ModelAttribute 本身或与请求体相关的内容。

The following example shows a @ModelAttribute method:
以下示例展示了 @ModelAttribute 方法:

@ModelAttribute public void populateModel(@RequestParam String number, Model model) { model.addAttribute(accountRepository.findAccount(number)); // add more ... }
@ModelAttribute fun populateModel(@RequestParam number: String, model: Model) { model.addAttribute(accountRepository.findAccount(number)) // add more ... }

The following example adds only one attribute:
以下示例仅添加一个属性:

@ModelAttribute public Account addAccount(@RequestParam String number) { return accountRepository.findAccount(number); }
@ModelAttribute fun addAccount(@RequestParam number: String): Account { return accountRepository.findAccount(number) }

When a name is not explicitly specified, a default name is chosen based on the Object type, as explained in the javadoc for Conventions. You can always assign an explicit name by using the overloaded addAttribute method or through the name attribute on @ModelAttribute (for a return value).
which a name is not explicitly specified, a default name is selected based on the Object type, as explained in the javadoc for Conventions . You can always assign an explicit name by using the overloaded addAttribute method or through the name attribute on @ModelAttribute (for a return value).

You can also use @ModelAttribute as a method-level annotation on @RequestMapping methods, in which case the return value of the @RequestMapping method is interpreted as a model attribute. This is typically not required, as it is the default behavior in HTML controllers, unless the return value is a String that would otherwise be interpreted as a view name. @ModelAttribute can also customize the model attribute name, as the following example shows:
您还可以将 @ModelAttribute 用作 @RequestMapping 方法的方法级别注解,在这种情况下, @RequestMapping 方法的返回值被解释为模型属性。这通常不是必需的,因为在 HTML 控制器中这是默认行为,除非返回值是一个会被解释为视图名称的 String@ModelAttribute 还可以自定义模型属性名称,如下例所示:

@GetMapping("/accounts/{id}") @ModelAttribute("myAccount") public Account handle() { // ... return account; }
@GetMapping("/accounts/{id}") @ModelAttribute("myAccount") fun handle(): Account { // ... return account }

(#mvc-ann-initbinder)1.3.5.DataBinder

@Controller or @ControllerAdvice classes can have @InitBinder methods that initialize instances of WebDataBinder, and those, in turn, can:
@Controller@ControllerAdvice 类可以有 @InitBinder 方法来初始化 WebDataBinder 的实例,而那些方法反过来又可以:

  • Bind request parameters (that is, form or query data) to a model object.
    绑定请求参数(即表单或查询数据)到模型对象。

  • Convert String-based request values (such as request parameters, path variables, headers, cookies, and others) to the target type of controller method arguments.
    将基于字符串的请求值(如请求参数、路径变量、头部、Cookies 等)转换为控制器方法参数的目标类型。

  • Format model object values as String values when rendering HTML forms.
    将格式化模型对象值作为 String 值在渲染 HTML 表单时使用。

@InitBinder methods can register controller-specific java.beans.PropertyEditor or Spring Converter and Formatter components. In addition, you can use the MVC config to register Converter and Formatter types in a globally shared FormattingConversionService.
@InitBinder 方法可以注册控制器特定的 java.beans.PropertyEditor 或 Spring ConverterFormatter 组件。此外,您还可以使用 MVC 配置在全局共享的 ConverterFormatter 中注册 FormattingConversionService 类型。

@InitBinder methods support many of the same arguments that @RequestMapping methods do, except for @ModelAttribute (command object) arguments. Typically, they are declared with a WebDataBinder argument (for registrations) and a void return value. The following listing shows an example:
@InitBinder 方法支持与 @RequestMapping 方法相同的许多参数,除了 @ModelAttribute (命令对象)参数。通常,它们使用一个 WebDataBinder 参数(用于注册)和一个 void 返回值来声明。以下列表显示了一个示例:

@Controller public class FormController { @InitBinder (1) public void initBinder(WebDataBinder binder) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); dateFormat.setLenient(false); binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false)); } // ... }

1

Defining an @InitBinder method. 定义一个 @InitBinder 方法。

@Controller class FormController { @InitBinder (1) fun initBinder(binder: WebDataBinder) { val dateFormat = SimpleDateFormat("yyyy-MM-dd") dateFormat.isLenient = false binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false)) } // ... }

1

Defining an @InitBinder method.

Alternatively, when you use a Formatter-based setup through a shared FormattingConversionService, you can re-use the same approach and register controller-specific Formatter implementations, as the following example shows:
另外,当您通过共享 FormattingConversionService 使用基于 Formatter 的设置时,您可以重用相同的方法并注册控制器特定的 Formatter 实现,如下例所示:

@Controller public class FormController { @InitBinder (1) protected void initBinder(WebDataBinder binder) { binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); } // ... }

1

Defining an @InitBinder method on a custom formatter.
定义一个自定义格式化器的 @InitBinder 方法。

@Controller class FormController { @InitBinder (1) protected fun initBinder(binder: WebDataBinder) { binder.addCustomFormatter(DateFormatter("yyyy-MM-dd")) } // ... }

1

Defining an @InitBinder method on a custom formatter.

(#mvc-ann-initbinder-model-design)Model Design 模型设计

In the context of web applications, data binding involves the binding of HTTP request parameters (that is, form data or query parameters) to properties in a model object and its nested objects.
在 Web 应用程序的上下文中,数据绑定涉及将 HTTP 请求参数(即表单数据或查询参数)绑定到模型对象及其嵌套对象的属性中。

Only public properties following the JavaBeans naming conventions are exposed for data binding — for example, public String getFirstName() and public void setFirstName(String) methods for a firstName property.
仅公开遵循 JavaBeans 命名约定的 public 属性进行数据绑定——例如, public String getFirstName()public void setFirstName(String) 方法用于 firstName 属性。

The model object, and its nested object graph, is also sometimes referred to as a command object, form-backing object, or POJO (Plain Old Java Object).
模型对象及其嵌套对象图有时也被称为命令对象、表单后端对象或 POJO(纯 Java 对象)。

By default, Spring permits binding to all public properties in the model object graph.
默认情况下,Spring 允许绑定到模型对象图中所有公共属性。
This means you need to carefully consider what public properties the model has, since a client could target any public property path, even some that are not expected to be targeted for a given use case.
这意味着您需要仔细考虑模型具有哪些公共属性,因为客户端可以针对任何公共属性路径进行操作,甚至包括某些在特定用例中并不期望被针对的属性路径。

For example, given an HTTP form data endpoint, a malicious client could supply values for properties that exist in the model object graph but are not part of the HTML form presented in the browser.
例如,给定一个 HTTP 表单数据端点,恶意客户端可能会为存在于模型对象图中但不在浏览器中呈现的 HTML 表单中的属性提供值。
This could lead to data being set on the model object and any of its nested objects, that is not expected to be updated.
这可能导致在模型对象及其嵌套对象上设置的数据不是预期更新的。

The recommended approach is to use a dedicated model object that exposes only properties that are relevant for the form submission. For example, on a form for changing a user’s email address, the model object should declare a minimum set of properties such as in the following ChangeEmailForm.
建议使用一个专用的模型对象,仅暴露与表单提交相关的属性。例如,在一个用于更改用户电子邮件地址的表单中,模型对象应声明以下最小属性集,如下所示 ChangeEmailForm

public class ChangeEmailForm { private String oldEmailAddress; private String newEmailAddress; public void setOldEmailAddress(String oldEmailAddress) { this.oldEmailAddress = oldEmailAddress; } public String getOldEmailAddress() { return this.oldEmailAddress; } public void setNewEmailAddress(String newEmailAddress) { this.newEmailAddress = newEmailAddress; } public String getNewEmailAddress() { return this.newEmailAddress; } }

If you cannot or do not want to use a dedicated model object for each data binding use case, you must limit the properties that are allowed for data binding. Ideally, you can achieve this by registering allowed field patterns via the setAllowedFields() method on WebDataBinder.
如果您不能或不想为每个数据绑定用例使用专用模型对象,您必须限制允许进行数据绑定的属性。理想情况下,您可以通过在 WebDataBinder 上的 setAllowedFields() 方法中注册允许的字段模式来实现这一点。

For example, to register allowed field patterns in your application, you can implement an @InitBinder method in a @Controller or @ControllerAdvice component as shown below:
例如,为了在您的应用程序中注册允许的字段模式,您可以在以下组件中实现一个 @InitBinder 方法,如下所示:

@Controller public class ChangeEmailController { @InitBinder void initBinder(WebDataBinder binder) { binder.setAllowedFields("oldEmailAddress", "newEmailAddress"); } // @RequestMapping methods, etc. }

In addition to registering allowed patterns, it is also possible to register disallowed field patterns via the setDisallowedFields() method in DataBinder and its subclasses. Please note, however, that an "allow list" is safer than a "deny list". Consequently, setAllowedFields() should be favored over setDisallowedFields().
除了注册允许的模式外,还可以通过 DataBinder 及其子类中的 setDisallowedFields() 方法注册不允许的字段模式。请注意,然而,“允许列表”比“拒绝列表”更安全。因此,应优先考虑 setAllowedFields() 而不是 setDisallowedFields()

Note that matching against allowed field patterns is case-sensitive; whereas, matching against disallowed field patterns is case-insensitive. In addition, a field matching a disallowed pattern will not be accepted even if it also happens to match a pattern in the allowed list.
请注意,与允许的字段模式匹配是区分大小写的;而与不允许的字段模式匹配则不区分大小写。此外,即使字段恰好匹配允许列表中的模式,如果它匹配了不允许的模式,则该字段也不会被接受。

It is extremely important to properly configure allowed and disallowed field patterns when exposing your domain model directly for data binding purposes. Otherwise, it is a big security risk.
配置允许和禁止的字段模式对于直接将域模型暴露于数据绑定目的至关重要。否则,这是一个很大的安全风险。

Furthermore, it is strongly recommended that you do not use types from your domain model such as JPA or Hibernate entities as the model object in data binding scenarios.
此外,强烈建议您在数据绑定场景中不要使用来自您领域模型的类型,如 JPA 或 Hibernate 实体作为模型对象。

(#mvc-ann-exceptionhandler)1.3.6. Exceptions 1.3.6. 异常

@Controller and @ControllerAdvice classes can have @ExceptionHandler methods to handle exceptions from controller methods, as the following example shows:
@Controller 和 @ControllerAdvice 类可以拥有 @ExceptionHandler 方法来处理控制器方法抛出的异常,如下例所示:

@Controller public class SimpleController { // ... @ExceptionHandler public ResponseEntity<String> handle(IOException ex) { // ... } }
@Controller class SimpleController { // ... @ExceptionHandler fun handle(ex: IOException): ResponseEntity<String> { // ... } }

The exception may match against a top-level exception being propagated (e.g. a direct IOException being thrown) or against a nested cause within a wrapper exception (e.g. an IOException wrapped inside an IllegalStateException). As of 5.3, this can match at arbitrary cause levels, whereas previously only an immediate cause was considered.
异常可能匹配传播的顶级异常(例如,直接抛出的 IOException )或匹配包装异常内部的嵌套原因(例如,一个 IOException 被包裹在 IllegalStateException 中)。从 5.3 版本开始,这可以在任意原因级别上进行匹配,而之前只考虑了直接原因。

For matching exception types, preferably declare the target exception as a method argument, as the preceding example shows. When multiple exception methods match, a root exception match is generally preferred to a cause exception match. More specifically, the ExceptionDepthComparator is used to sort exceptions based on their depth from the thrown exception type.
对于匹配异常类型,最好将目标异常声明为方法参数,如前例所示。当多个异常方法匹配时,通常首选根异常匹配而非原因异常匹配。更具体地说, ExceptionDepthComparator 用于根据异常类型从抛出异常类型的深度对异常进行排序。

Alternatively, the annotation declaration may narrow the exception types to match, as the following example shows:
或者,注解声明可以缩小异常类型以匹配,如下例所示:

@ExceptionHandler({FileSystemException.class, RemoteException.class}) public ResponseEntity<String> handle(IOException ex) { // ... }
@ExceptionHandler(FileSystemException::class, RemoteException::class) fun handle(ex: IOException): ResponseEntity<String> { // ... }

You can even use a list of specific exception types with a very generic argument signature, as the following example shows:
您甚至可以使用具有非常通用参数签名的特定异常类型列表,如下例所示:

@ExceptionHandler({FileSystemException.class, RemoteException.class}) public ResponseEntity<String> handle(Exception ex) { // ... }
@ExceptionHandler(FileSystemException::class, RemoteException::class) fun handle(ex: Exception): ResponseEntity<String> { // ... }

The distinction between root and cause exception matching can be surprising.
根异常和原因异常匹配之间的区别可能会令人惊讶。

In the IOException variant shown earlier, the method is typically called with the actual FileSystemException or RemoteException instance as the argument, since both of them extend from IOException. However, if any such matching exception is propagated within a wrapper exception which is itself an IOException, the passed-in exception instance is that wrapper exception.
在前面展示的 IOException 变体中,通常使用实际的 FileSystemExceptionRemoteException 实例作为参数调用该方法,因为它们都扩展自 IOException 。然而,如果此类匹配异常在自身也是 IOException 的包装异常内部传播,则传入的异常实例是那个包装异常。

The behavior is even simpler in the handle(Exception) variant. This is always invoked with the wrapper exception in a wrapping scenario, with the actually matching exception to be found through ex.getCause() in that case. The passed-in exception is the actual FileSystemException or RemoteException instance only when these are thrown as top-level exceptions.
该行为在 handle(Exception) 变体中甚至更简单。在包装场景中,它始终使用包装异常调用,实际上匹配的异常可以通过 ex.getCause() 在该情况下找到。只有当这些异常作为顶级异常抛出时,传入的异常才是实际的 FileSystemExceptionRemoteException 实例。

We generally recommend that you be as specific as possible in the argument signature, reducing the potential for mismatches between root and cause exception types. Consider breaking a multi-matching method into individual @ExceptionHandler methods, each matching a single specific exception type through its signature.
我们通常建议您在参数签名中尽可能具体,以减少根异常类型与原因异常类型之间不匹配的可能性。考虑将多匹配方法拆分为单个 @ExceptionHandler 方法,每个方法通过其签名匹配一个特定的异常类型。

In a multi-@ControllerAdvice arrangement, we recommend declaring your primary root exception mappings on a @ControllerAdvice prioritized with a corresponding order. While a root exception match is preferred to a cause, this is defined among the methods of a given controller or @ControllerAdvice class. This means a cause match on a higher-priority @ControllerAdvice bean is preferred to any match (for example, root) on a lower-priority @ControllerAdvice bean.
在一个多- @ControllerAdvice 安排中,我们建议在具有相应顺序的 @ControllerAdvice 优先级上声明您的主要根异常映射。虽然根异常匹配比原因匹配更受青睐,但这是在给定控制器或 @ControllerAdvice 类的方法中定义的。这意味着在更高优先级的 @ControllerAdvice 容器上匹配原因比在较低优先级的 @ControllerAdvice 容器上匹配任何匹配(例如,根)更受青睐。

Last but not least, an @ExceptionHandler method implementation can choose to back out of dealing with a given exception instance by rethrowing it in its original form.
最后但同样重要的是,一个 @ExceptionHandler 方法实现可以选择通过以原始形式重新抛出它来退出处理给定异常实例。
This is useful in scenarios where you are interested only in root-level matches or in matches within a specific context that cannot be statically determined. A rethrown exception is propagated through the remaining resolution chain, as though the given @ExceptionHandler method would not have matched in the first place.
这在您只对根级别匹配或无法静态确定的特定上下文中的匹配感兴趣的场景中很有用。重新抛出的异常将通过剩余的解析链传播,就像给定的 @ExceptionHandler 方法从一开始就没有匹配一样。

Support for @ExceptionHandler methods in Spring MVC is built on the DispatcherServlet level, HandlerExceptionResolver mechanism.
Spring MVC 中对 @ExceptionHandler 方法的支持建立在 DispatcherServlet 级别的 HandlerExceptionResolver 机制上。

(#mvc-ann-exceptionhandler-args)Method Arguments 方法参数

@ExceptionHandler methods support the following arguments:
@ExceptionHandler 方法支持以下参数:

Method argument 方法参数

Description 描述

Exception type 异常类型

For access to the raised exception.
为了访问抛出的异常。

HandlerMethod

For access to the controller method that raised the exception.
为了访问引发异常的控制方法。

WebRequest, NativeWebRequest

Generic access to request parameters and request and session attributes without direct use of the Servlet API.
通用访问请求参数和请求及会话属性,无需直接使用 Servlet API。

javax.servlet.ServletRequest, javax.servlet.ServletResponse

Choose any specific request or response type (for example, ServletRequest or HttpServletRequest or Spring’s MultipartRequest or MultipartHttpServletRequest).
选择任何特定的请求或响应类型(例如, ServletRequestHttpServletRequest 或 Spring 的 MultipartRequestMultipartHttpServletRequest )。

javax.servlet.http.HttpSession

Enforces the presence of a session. As a consequence, such an argument is never null.
强制存在会话。因此,此类参数永远不会为 null
Note that session access is not thread-safe. Consider setting the RequestMappingHandlerAdapter instance’s synchronizeOnSession flag to true if multiple requests are allowed to access a session concurrently.
请注意,会话访问不是线程安全的。如果允许多个请求并发访问会话,请考虑将 RequestMappingHandlerAdapter 实例的 synchronizeOnSession 标志设置为 true

java.security.Principal

Currently authenticated user — possibly a specific Principal implementation class if known.
当前认证用户 — 如果已知,可能是特定的 Principal 实现类。

HttpMethod

The HTTP method of the request.
请求的 HTTP 方法。

java.util.Locale

The current request locale, determined by the most specific LocaleResolver available — in effect, the configured LocaleResolver or LocaleContextResolver.
当前请求的区域设置,由最具体的 LocaleResolver 确定——实际上,是配置的 LocaleResolverLocaleContextResolver

java.util.TimeZone, java.time.ZoneId

The time zone associated with the current request, as determined by a LocaleContextResolver.
当前请求关联的时间区域,由 LocaleContextResolver 确定。

java.io.OutputStream, java.io.Writer

For access to the raw response body, as exposed by the Servlet API.
为了访问由 Servlet API 暴露的原始响应体。

java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap

For access to the model for an error response. Always empty.
用于访问错误响应的模型。始终为空。

RedirectAttributes

Specify attributes to use in case of a redirect —(that is to be appended to the query string) and flash attributes to be stored temporarily until the request after the redirect. See Redirect Attributes and Flash Attributes.
指定在重定向时使用的属性——(将附加到查询字符串中)以及临时存储直到重定向后的请求的闪存属性。请参阅重定向属性和闪存属性。

@SessionAttribute

For access to any session attribute, in contrast to model attributes stored in the session as a result of a class-level @SessionAttributes declaration. See @SessionAttribute for more details.
为了访问任何会话属性,与由于类级别 @SessionAttributes 声明而存储在会话中的模型属性相反。有关更多详细信息,请参阅 @SessionAttribute

@RequestAttribute

For access to request attributes. See @RequestAttribute for more details.
用于访问请求属性。有关更多详细信息,请参阅 @RequestAttribute

(#mvc-ann-exceptionhandler-return-values)Return Values 返回值

@ExceptionHandler methods support the following return values:
@ExceptionHandler 方法支持以下返回值:

Return value 返回值

Description 描述

@ResponseBody

The return value is converted through HttpMessageConverter instances and written to the response. See @ResponseBody.
返回值通过 HttpMessageConverter 实例转换并写入响应。见 @ResponseBody

HttpEntity<B>, ResponseEntity<B>

The return value specifies that the full response (including the HTTP headers and the body) be converted through HttpMessageConverter instances and written to the response. See ResponseEntity.
返回值指定将完整响应(包括 HTTP 头和主体)通过 HttpMessageConverter 实例转换并写入响应。请参阅 ResponseEntity。

String

A view name to be resolved with ViewResolver implementations and used together with the implicit model — determined through command objects and @ModelAttribute methods. The handler method can also programmatically enrich the model by declaring a Model argument (described earlier).
一个用于与 ViewResolver 实现一起解析的视图名称,并用于与隐式模型一起使用——通过命令对象和 @ModelAttribute 方法确定。处理方法还可以通过声明(前面已描述) Model 参数来程序化丰富模型。

View

A View instance to use for rendering together with the implicit model — determined through command objects and @ModelAttribute methods. The handler method may also programmatically enrich the model by declaring a Model argument (descried earlier).
一个用于与隐式模型一起渲染的 View 实例 —— 通过命令对象和 @ModelAttribute 方法确定。处理方法还可以通过声明一个 Model 参数(之前描述过)来编程丰富模型。

java.util.Map, org.springframework.ui.Model

Attributes to be added to the implicit model with the view name implicitly determined through a RequestToViewNameTranslator.
属性将添加到隐式模型中,视图名称通过 RequestToViewNameTranslator 隐式确定。

@ModelAttribute

An attribute to be added to the model with the view name implicitly determined through a RequestToViewNameTranslator.
一个要添加到模型中的属性,通过 RequestToViewNameTranslator 隐式确定视图名称。

Note that @ModelAttribute is optional. See “Any other return value” at the end of this table.
请注意, @ModelAttribute 是可选的。请参阅此表末尾的“任何其他返回值”。

ModelAndView objectModelAndView 对象

The view and model attributes to use and, optionally, a response status.
要使用的视图和模型属性以及可选的响应状态。

void

A method with a void return type (or null return value) is considered to have fully handled the response if it also has a ServletResponse an OutputStream argument, or a @ResponseStatus annotation. The same is also true if the controller has made a positive ETag or lastModified timestamp check ( see Controllers for details).
一个具有 void 返回类型(或 null 返回值)的方法,如果它还有一个 ServletResponse 一个 OutputStream 参数,或一个 @ResponseStatus 注解,则被认为已完全处理了响应。如果控制器已经进行了积极的 ETaglastModified 时间戳检查(详见控制器),也是如此。

If none of the above is true, a void return type can also indicate “no response body” for REST controllers or default view name selection for HTML controllers.
如果上述情况都不成立, void 返回类型也可以表示 REST 控制器中的“无响应体”或 HTML 控制器中的默认视图名称选择。

Any other return value 任何其他返回值

If a return value is not matched to any of the above and is not a simple type (as determined by BeanUtils#isSimpleProperty), by default, it is treated as a model attribute to be added to the model. If it is a simple type, it remains unresolved.
如果返回值与上述任何一项都不匹配,并且不是简单类型(由 BeanUtils#isSimpleProperty 确定),则默认将其视为要添加到模型中的模型属性。如果是简单类型,则保持未解析状态。

(#mvc-ann-rest-exceptions)REST API exceptions REST API 异常

A common requirement for REST services is to include error details in the body of the response. The Spring Framework does not automatically do this because the representation of error details in the response body is application-specific. However, a @RestController may use @ExceptionHandler methods with a ResponseEntity return value to set the status and the body of the response. Such methods can also be declared in @ControllerAdvice classes to apply them globally.
REST 服务的一个常见需求是在响应体中包含错误详情。Spring 框架不会自动执行此操作,因为响应体中错误详情的表示是特定于应用的。然而, @RestController 可以使用 @ExceptionHandler 方法以及具有 ResponseEntity 返回值的方法来设置响应的状态和体。这些方法也可以在 @ControllerAdvice 类中声明,以全局应用。

Applications that implement global exception handling with error details in the response body should consider extending ResponseEntityExceptionHandler, which provides handling for exceptions that Spring MVC raises and provides hooks to customize the response body. To make use of this, create a subclass of ResponseEntityExceptionHandler, annotate it with @ControllerAdvice, override the necessary methods, and declare it as a Spring bean.
实现全局异常处理并在响应体中包含错误详情的应用程序应考虑扩展 ResponseEntityExceptionHandler ,它提供了对 Spring MVC 抛出的异常的处理,并提供了自定义响应体的钩子。要使用此功能,创建 ResponseEntityExceptionHandler 的子类,用 @ControllerAdvice 注解它,重写必要的方法,并将其声明为 Spring bean。

(#mvc-ann-controller-advice)1.3.7. Controller Advice

1.3.7. 控制器建议

@ExceptionHandler, @InitBinder, and @ModelAttribute methods apply only to the @Controller class, or class hierarchy, in which they are declared. If, instead, they are declared in an @ControllerAdvice or @RestControllerAdvice class, then they apply to any controller. Moreover, as of 5.3, @ExceptionHandler methods in @ControllerAdvice can be used to handle exceptions from any @Controller or any other handler.
@ExceptionHandler@InitBinder@ModelAttribute 方法仅适用于它们声明的 @Controller 类或类层次结构。如果它们在 @ControllerAdvice@RestControllerAdvice 类中声明,则它们适用于任何控制器。此外,从 5.3 版本开始, @ControllerAdvice 中的 @ExceptionHandler 方法可以用来处理来自任何 @Controller 或其他处理器的异常。

@ControllerAdvice is meta-annotated with @Component and therefore can be registered as a Spring bean through component scanning. @RestControllerAdvice is meta-annotated with @ControllerAdvice and @ResponseBody, and that means @ExceptionHandler methods will have their return value rendered via response body message conversion, rather than via HTML views.
@ControllerAdvice 被元注解为 @Component ,因此可以通过组件扫描将其注册为 Spring bean。 @RestControllerAdvice 被元注解为 @ControllerAdvice@ResponseBody ,这意味着 @ExceptionHandler 方法将通过响应体消息转换来渲染返回值,而不是通过 HTML 视图。

On startup, RequestMappingHandlerMapping and ExceptionHandlerExceptionResolver detect controller advice beans and apply them at runtime. Global @ExceptionHandler methods, from an @ControllerAdvice, are applied after local ones, from the @Controller. By contrast, global @ModelAttribute and @InitBinder methods are applied before local ones.
启动时, RequestMappingHandlerMappingExceptionHandlerExceptionResolver 检测控制器建议豆并在运行时应用它们。全局 @ExceptionHandler 方法,从 @ControllerAdvice ,在本地方法之后应用,从 @Controller 。相比之下,全局 @ModelAttribute@InitBinder 方法在本地方法之前应用。

The @ControllerAdvice annotation has attributes that let you narrow the set of controllers and handlers that they apply to. For example:
@ControllerAdvice 注解具有属性,可以缩小它们应用的控制器和处理器集合。例如:

// Target all Controllers annotated with @RestController @ControllerAdvice(annotations = RestController.class) public class ExampleAdvice1 {} // Target all Controllers within specific packages @ControllerAdvice("org.example.controllers") public class ExampleAdvice2 {} // Target all Controllers assignable to specific classes @ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class}) public class ExampleAdvice3 {}
// Target all Controllers annotated with @RestController @ControllerAdvice(annotations = [RestController::class]) class ExampleAdvice1 // Target all Controllers within specific packages @ControllerAdvice("org.example.controllers") class ExampleAdvice2 // Target all Controllers assignable to specific classes @ControllerAdvice(assignableTypes = [ControllerInterface::class, AbstractController::class]) class ExampleAdvice3

The selectors in the preceding example are evaluated at runtime and may negatively impact performance if used extensively. See the @ControllerAdvice javadoc for more details.
前一个示例中的选择器在运行时评估,如果广泛使用可能会对性能产生负面影响。请参阅 @ControllerAdvice javadoc 获取更多详细信息。

ON THIS PAGE