SpringWebFlux
-2(5.3.12版学习笔记2021.11.09)
1.4 Annotated Controllers(带注释的控制器)
Spring WebFlux 提供了一个基于 Comments 的编程模型,其中
@Controller
和@RestController
组件使用 Comments 来表达请求 Map,请求 Importing,处理异常等。带 Comments 的控制器具有灵活的方法签名,无需扩展 Base Class 或实现特定的接口。以下 Lists 显示了一个基本示例:
@RestController
public class HelloController {
@GetMapping("/hello")
public String handle() {
return "Hello WebFlux";
}
}
1.4.1. @Controller
您可以使用标准的 Spring bean 定义来定义控制器 bean。
@Controller
原型允许自动检测,并且与 Spring 常规支持保持一致,以支持在 Classpath 中检测@Component
类并为其自动注册 Bean 定义。它还充当带 Comments 类的构造型,表明其作为 Web 组件的作用。要启用对此类
@Controller
bean 的自动检测,可以将组件扫描添加到 Java 配置中,如以下示例所示:
@Configuration
@ComponentScan("org.example.web") (1)
public class WebConfig {
// ...
}
@RestController
是本身由@Controller
和@ResponseBody
进行元 Comments 的composed annotation,表示其每个方法都继承了类型级别@ResponseBody
Comments 的控制器,因此直接将其写入响应主体(与视图分辨率和 HTML 模板渲染相比)。
1.4.2. 请求映射
@RequestMapping
注解用于将请求 Map 到控制器方法。它具有各种属性,可以通过 URL,HTTP 方法,请求参数,Headers 和媒体类型进行匹配。您可以在类级别使用它来表示共享的 Map,也可以在方法级别使用它来缩小到特定的端点 Map。也有
@RequestMapping
的 HTTP 方法特定的快捷方式:
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
提供前面的 Comments 是Custom Annotations,因为可以说,大多数控制器方法应该 Map 到特定的 HTTP 方法,而不是使用
@RequestMapping
,默认情况下,@RequestMapping
匹配所有 HTTP 方法。同时,在类级别仍需要@RequestMapping
来表示共享 Map。以下示例使用类型和方法级别的 Map:
@RestController
@RequestMapping("/persons")
class PersonController {
@GetMapping("/{id}")
public Person getPerson(@PathVariable Long id) {
// ...
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void add(@RequestBody Person person) {
// ...
}
}
URI Patterns (url模式)
您可以使用全局模式和通配符来 映射请求:
通配符 | 描述 | 例子 |
---|---|---|
? | 匹配一个字符 | "/pages/t?st.html" 匹配"/pages/test.html" 和"/pages/t3st.html" |
* | 匹配路径段中的零个或多个字符 | "/resources/*.png" 火柴 "/resources/file.png"``"/projects/*/versions" 匹配"/projects/spring/versions" 但不匹配"/projects/spring/boot/versions" |
** | 匹配零个或多个路径段直到路径结束 | "/resources/**" 匹配"/resources/file.png" 和"/resources/images/file.png"``"/resources/**/file.png" 无效,因为** 只允许在路径的末尾。 |
{name} | 匹配路径段并将其捕获为名为“name”的变量 | "/projects/{project}/versions" 匹配"/projects/spring/versions" 和捕获project=spring |
{name:[a-z]+} | 将正则表达式匹配"[a-z]+" 为名为“name”的路径变量 | "/projects/{project:[a-z]+}/versions" 匹配"/projects/spring/versions" 但不匹配"/projects/spring1/versions" |
{*path} | 匹配零个或多个路径段,直到路径结束并将其捕获为名为“path”的变量 | "/resources/{*file}" 匹配"/resources/images/file.png" 和捕获file=/images/file.png |
您还可以声明 URI 变量并使用
@PathVariable
访问其值,如以下示例所示:
@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
您可以在类和方法级别声明 URI 变量,如以下示例所示:
@Controller
@RequestMapping("/owners/{ownerId}") (1 = 类级url映射)
public class OwnerController {
@GetMapping("/pets/{petId}") (2 = 方法级 url映射)
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
// ...
}
}
URI 变量会自动转换为适当的类型,或者引发
TypeMismatchException
。默认情况下支持简单类型(int
,long
,Date
等),您可以注册对任何其他数据类型的支持。参见Type Conversion和DataBinder。URI 变量可以显式命名(例如
@PathVariable("customId")
),但是如果名称相同,则可以省略该详细信息,并使用调试信息或 Java 8 上的-parameters
编译器标志编译代码。语法
{*varName}
声明了一个与零个或多个剩余路径段匹配的 URI 变量。例如,/resources/{*path}
匹配所有文件/resources/
,并且"path"
变量捕获完整的相对路径。语法
{varName:regex}
声明带有正则表达式的 URI 变量,语法为{varName:regex}
。例如,给定 URL/spring-web-3.0.5 .jar
,以下方法将提取名称,版本和文件 extensions:
@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String ext) {
// ...
}
URI 路径模式也可以嵌入
${…}
占位符,这些占位符在启动时通过PropertyPlaceHolderConfigurer
会针对本地,系统,环境和其他属性源进行解析。您可以使用它来例如基于某些外部配置参数化基本 URL。Spring WebFlux 使用
PathPattern
和PathPatternParser
来获得 URI 路径匹配支持。这两个类都位于spring-web
中,并且专门设计用于 Web 应用程序中的 HTTP URL 路径,在 Web 应用程序中,在运行时会匹配大量 URI 路径模式。Spring WebFlux 不支持后缀模式匹配-与 Spring MVC 不同,在 Spring MVC 中,诸如
/person
的 Map 也匹配到/person.*
。对于基于 URL 的内容协商,如果需要,我们建议使用查询参数,该参数更简单,更明确,并且不易受到基于 URL 路径的攻击。
Pattern Comparison (模式比较)
当多个模式与 URL 匹配时,必须将它们进行比较以找到最佳匹配。这是通过
PathPattern.SPECIFICITY_COMPARATOR
完成的,该PathPattern.SPECIFICITY_COMPARATOR
查找更具体的模式。对于每个模式,都会根据 URI 变量和通配符的数量计算得分,其中 URI 变量的得分低于通配符。总得分较低的模式将获胜。如果两个模式的分数相同,则选择更长的时间。
包罗万象的模式(例如
**
,{*varName}
)不计入评分,而是始终排在最后。如果两种模式都适用,则选择较长的模式。
可消费媒体类型
您可以根据请求的
Content-Type
缩小请求 Map,如下例所示:
@PostMapping(path = "/pets", consumes = "application/json")
public void addPet(@RequestBody Pet pet) {
// ...
}
消耗属性还支持否定表达式-例如,
!text/plain
表示text/plain
以外的任何 Content Type。您可以在类级别声明共享的
consumes
属性。但是,与大多数其他请求 映射 属性不同,在类级别使用时,方法级别的consumes
属性会覆盖而不是扩展类级别的声明。
MediaType
提供常用媒体类型的常量,例如APPLICATION_JSON_VALUE
和APPLICATION_XML_VALUE
。
可生产的媒体类型
您可以根据
Accept
请求 Headers 和控制器方法生成的 Content Type 列表来缩小请求 映射,如下例所示:
@GetMapping(path = "/pets/{petId}", produces = "application/json;charset=UTF-8")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
// ...
}
媒体类型可以指定字符集。支持否定的表达式。例如,
!text/plain
表示text/plain
以外的任何 Content Type。 您可以produces
在类级别声明共享属性。然而,与大多数其他请求映射属性不同,当在类级别使用时,方法级别的produces
属性会覆盖而不是扩展类级别的声明。
参数和标题
您可以根据查询参数条件来缩小请求 映射。您可以测试是否存在查询参数(
myParam
),查询参数是否不存在(!myParam
)或特定值(myParam=myValue
)。以下示例测试具有值的参数:
@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") // (1 = 检查myParam等于myValue。)
public void findPet(@PathVariable String petId) {
// ...
}
您还可以将其与请求 Headers 条件一起使用,如以下示例所示:
@GetMapping(path = "/pets", headers = "myHeader=myValue") // (1 =检查myHeader等于myValue。)
public void findPet(@PathVariable String petId) {
// ...
}
HTTP 头,选项
@GetMapping
和@RequestMapping(method=HttpMethod.GET)
透明地支持 HTTP HEAD,以进行请求 映射。控制器方法无需更改。HttpHandler
服务器适配器中应用的响应包装器可确保将Content-Length
Headers 设置为写入的字节数,而无需实际写入响应。默认情况下,通过将
Allow
响应 Headers 设置为所有具有匹配 URL 模式的@RequestMapping
方法中列出的 HTTP 方法列表来处理 HTTP OPTIONS。对于没有 HTTP 方法声明的
@RequestMapping
,Allow
Headers 设置为GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS
。控制器方法应始终声明支持的 HTTP 方法(例如,使用 HTTP 方法特定的变体@GetMapping
,@PostMapping
等)。您可以将
@RequestMapping
方法显式 Map 到 HTTP HEAD 和 HTTP OPTIONS,但这在通常情况下不是必需的。
自定义注解
Spring WebFlux 支持使用composed annotations进行请求 映射。这些注解本身用
@RequestMapping
进行元注解,并组成它们以更狭窄,更具体的用途重新声明@RequestMapping
属性的子集(或全部)。
@GetMapping
,@PostMapping
,@PutMapping
,@DeleteMapping
和@PatchMapping
是组合 Comments 的示例。之所以提供它们,是因为大多数控制器方法应该 Map 到特定的 HTTP 方法,而不是使用@RequestMapping
,默认情况下,@RequestMapping
匹配所有 HTTP 方法。如果需要组合 Comments 的示例,请查看如何声明它们。Spring WebFlux 还支持具有自定义请求匹配逻辑的自定义请求 映射 属性。这是一个更高级的选项,它需要子类化
RequestMappingHandlerMapping
并覆盖getCustomMethodCondition
方法,您可以在其中检查 custom 属性并返回自己的RequestCondition
。
Explicit Registrations (显式注册)
您可以以编程方式注册 Handler 方法,这些方法可用于动态注册或高级用例,例如同一处理程序在不同 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.4.3 处理程序方法
@RequestMapping
处理程序方法具有灵活的签名,可以从一系列受支持的控制器方法参数和返回值中进行选择。
方法参数
需要解析 I/O(例如,读取请求正文)的参数支持 Reactive 类型(Reactor,RxJava,or other)。这在“描述”列中进行了标记。不需要阻塞的参数不应使用 Reactive 类型。
支持 JDK 1.8 的
java.util.Optional
作为方法参数,并与具有required
属性(例如@RequestParam
,@RequestHeader
等)的注解结合使用,并且与required=false
等效。下表显示了受支持的控制器方法参数。
控制器方法参数 | 描述 |
---|---|
ServerWebExchange | 访问完整的ServerWebExchange — 用于 HTTP 请求和响应、请求和会话属性、checkNotModified 方法等的容器。 |
ServerHttpRequest , ServerHttpResponse | 访问 HTTP 请求或响应。 |
WebSession | 访问会话。除非添加属性,否则这不会强制启动新会话。支持反应式。 |
java.security.Principal | 当前经过身份验证的用户 -Principal 如果已知,可能是特定的实现类。支持反应式。 |
org.springframework.http.HttpMethod | 请求的 HTTP 方法。 |
java.util.Locale | 当前请求区域设置,由最具体的LocaleResolver 可用确定- 实际上是配置的LocaleResolver / LocaleContextResolver 。 |
java.util.TimeZone + java.time.ZoneId | 与当前请求关联的时区,由 确定LocaleContextResolver 。 |
@PathVariable | 用于访问 URI 模板变量。请参阅URI 模式。 |
@MatrixVariable | 用于访问 URI 路径段中的名称-值对。请参阅矩阵变量。 |
@RequestParam | 用于访问 Servlet 请求参数。参数值被转换为声明的方法参数类型。见@RequestParam 。请注意,使用@RequestParam 是可选的——例如,设置其属性。请参阅此表后面的“任何其他参数”。 |
@RequestHeader | 用于访问请求标头。标头值转换为声明的方法参数类型。见@RequestHeader 。 |
@CookieValue | 用于访问 cookie。Cookie 值被转换为声明的方法参数类型。见@CookieValue 。 |
@RequestBody | 用于访问 HTTP 请求正文。正文内容通过使用HttpMessageReader 实例转换为声明的方法参数类型。支持反应式。见@RequestBody 。 |
HttpEntity<B> | 用于访问请求标头和正文。身体是用HttpMessageReader 实例转换的。支持反应式。见HttpEntity 。 |
@RequestPart | 用于访问multipart/form-data 请求中的一部分。支持反应式。请参阅多部分内容和多部分数据。 |
java.util.Map 、org.springframework.ui.Model 、 和org.springframework.ui.ModelMap 。 | 用于访问在 HTML 控制器中使用的模型,并作为视图呈现的一部分公开给模板。 |
@ModelAttribute | 用于访问模型中的现有属性(如果不存在则实例化)并应用数据绑定和验证。见@ModelAttribute 以及Model 和DataBinder 。请注意,使用@ModelAttribute 是可选的——例如,设置其属性。请参阅此表后面的“任何其他参数”。 |
Errors , BindingResult | 用于访问来自命令对象(即@ModelAttribute 参数)的验证和数据绑定的错误 。一种Errors 或BindingResult 参数必须立即有效的方法论证后声明。 |
SessionStatus + 班级 @SessionAttributes | 用于标记表单处理完成,这会触发对通过类级@SessionAttributes 注释声明的会话属性的清理。有关@SessionAttributes 更多详细信息,请参阅。 |
UriComponentsBuilder | 用于准备相对于当前请求的主机、端口、方案和上下文路径的 URL。请参阅URI 链接。 |
@SessionAttribute | 用于访问任何会话属性 - 与作为类级@SessionAttributes 声明的结果存储在会话中的模型属性相反。有关@SessionAttribute 更多详细信息,请参阅 。 |
@RequestAttribute | 用于访问请求属性。有关@RequestAttribute 更多详细信息,请参阅。 |
任何其他论点 | 如果方法参数与上述任何一个都不匹配,则默认情况下,@RequestParam 如果它是简单类型,则解析为 a ,由BeanUtils#isSimpleProperty确定 @ModelAttribute ,否则解析为 a 。 |
返回值
下表显示了受支持的控制器方法返回值。请注意,所有返回值通常都支持 Reactor,RxJava,or other之类的库中的反应类型。
控制器方法返回值 | 描述 |
---|---|
@ResponseBody | 返回值通过HttpMessageWriter 实例编码并写入响应。见@ResponseBody 。 |
HttpEntity<B> , ResponseEntity<B> | 返回值指定完整的响应,包括 HTTP 标头,主体通过HttpMessageWriter 实例编码并写入响应。见ResponseEntity 。 |
HttpHeaders | 用于返回带有标题但没有正文的响应。 |
String | 要与ViewResolver 实例解析并与隐式模型一起使用的视图名称- 通过命令对象和@ModelAttribute 方法确定。处理程序方法还可以通过声明一个Model 参数(前面描述过)以编程方式丰富模型。 |
View | 甲View 实例以使用用于与所述隐式模型一起渲染-通过命令对象和确定@ModelAttribute 方法。处理程序方法还可以通过声明一个Model 参数(前面描述过)以编程方式丰富模型。 |
java.util.Map , org.springframework.ui.Model | 要添加到隐式模型的属性,根据请求路径隐式确定视图名称。 |
@ModelAttribute | 要添加到模型的属性,视图名称根据请求路径隐式确定。请注意,这@ModelAttribute 是可选的。请参阅此表后面的“任何其他返回值”。 |
Rendering | 用于模型和视图渲染场景的 API。 |
void | 如果方法具有void ,可能是异步的(例如,Mono<Void> ),返回类型(或null 返回值),则被视为已完全处理响应,如果它也有ServerHttpResponse ,ServerWebExchange 参数或@ResponseStatus 注释。如果控制器进行了正面的 ETag 或lastModified 时间戳检查,情况也是如此。// TODO:有关详细信息,请参阅控制器。如果以上都不为真,则void 返回类型还可以指示 REST 控制器的“无响应正文”或 HTML 控制器的默认视图名称选择。 |
Flux<ServerSentEvent> , Observable<ServerSentEvent> , 或其他反应式 | 发出服务器发送的事件。的ServerSentEvent 可以在将要写入的数据仅需要被省略包装物(但是,text/event-stream 必须要求或在通过映射声明produces 属性)。 |
任何其他返回值 | 如果返回值与上述任何一项都不匹配,则默认情况下将其视为视图名称,如果是String 或void (适用默认视图名称选择),或作为要添加到模型的模型属性,除非它是一个简单类型,由BeanUtils#isSimpleProperty确定 ,在这种情况下它仍未解析。 |
类型转换
如果参数声明为
String
以外的其他内容,则表示基于字符串的请求 Importing 的某些带 Comments 的控制器方法参数(例如@RequestParam
,@RequestHeader
,@PathVariable
,@MatrixVariable
和@CookieValue
)可能需要类型转换。在这种情况下,将根据配置的转换器自动应用类型转换。默认情况下,支持简单类型(例如
int
,long
,Date
等)。可以通过WebDataBinder
(请参见[mvc-ann-initbinder])或通过向FormattingConversionService
注册Formatters
(请参见Spring 字段格式)来自定义类型转换。类型转换中的一个实际问题是空字符串源值的处理。如果
null
作为类型转换的结果,则将此类值视为缺失值。这可能是对的情况下Long
,UUID
其他目标类型,和。如果要允许null
注入,请required
在参数注释上使用标志,或将参数声明为@Nullable
.
矩阵变量
与 Spring MVC 中的相同, 需要的自己去官网自行观看, 使用场景很少
@RequestParam
Servlet API“请求参数”概念将查询参数、表单数据和多部分合二为一。但是,在 WebFlux 中,每个都通过
ServerWebExchange
. 虽然@RequestParam
仅绑定到查询参数,但您可以使用数据绑定将查询参数、表单数据和多部分应用于 命令对象。
@RequestParam
默认情况下,使用注释的方法参数是必需的,但您可以通过设置 a 的 required 标志@RequestParam
tofalse
或通过使用java.util.Optional
包装器声明参数来指定方法参数是可选的。如果目标方法参数类型不是 ,则自动应用类型转换
String
。请参阅类型转换。在or 参数
@RequestParam
上声明注释时,映射将填充所有查询参数。Map<String, String>``MultiValueMap<String, String>
请注意,使用
@RequestParam
是可选的——例如,设置其属性。默认情况下,任何属于简单值类型(由BeanUtils#isSimpleProperty确定 )且未被任何其他参数解析器解析的参数都被视为使用@RequestParam
.
@RequestHeader
您可以使用
@RequestHeader
注解将请求 Headers 绑定到控制器中的方法参数。以下示例显示了带有 Headers 的请求:
Host localhost:8080
Accept-Encoding gzip,deflate
........
// 下面的示例获取Accept-Encoding和Host 的值:
@GetMapping("/demo")
public void handle(
@RequestHeader("Accept-Encoding") String encoding, (1)
@RequestHeader("Host") long keepAlive) { (2)
//...
}
如果目标方法参数类型不是
String
,则会自动应用类型转换。参见[mvc-ann-typeconversion]。在
Map<String, String>
,MultiValueMap<String, String>
或HttpHeaders
参数上使用@RequestHeader
Comments 时,将使用所有 Headers 值填充 Map。内置支持可用于将逗号分隔的字符串转换为数组或字符串集合或类型转换系统已知的其他类型。例如,带有
@RequestHeader("Accept")
Comments 的方法参数可以是String
类型,也可以是String[]
或List<String>
类型。
@CookieValue
您可以使用
@CookieValue
注解将 HTTP cookie 的值绑定到控制器中的方法参数。如果目标方法参数类型不是
String
,则会自动应用类型转换。参见[mvc-ann-typeconversion]。
// 带有 cookie 的请求: JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84
@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { (1)
//...
}
@ModelAttribute
您可以在方法参数上使用
@ModelAttribute
注解来访问模型中的属性,或将其实例化(如果不存在)。 model 属性还覆盖了查询参数的值和名称与字段名称匹配的表单字段。这称为数据绑定,它使您不必处理解析和转换单个查询参数和表单字段的工作。下面的示例绑定Pet
的实例:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } (1)
上例中的Pet
实例按以下方式解析:
- 从模型(如果已通过Model添加)。
- 从 HTTP 会话通过@SessionAttributes。
- 从默认构造函数的调用开始。
- 从带有匹配查询参数或表单字段的参数的“主要构造函数”的调用开始。参数名称是通过 JavaBeans
@ConstructorProperties
或字节码中运行时保留的参数名称确定的。
获取模型属性实例后,将应用数据绑定。
WebExchangeDataBinder
类将查询参数和表单字段的名称与目标Object
上的字段名称匹配。在必要时应用类型转换后,将填充匹配字段。有关数据绑定(和验证)的更多信息,请参见Validation。有关自定义数据绑定的更多信息,请参见DataBinder。数据绑定可能会导致错误。默认情况下,引发
WebExchangeBindException
,但是,要检查 controller 方法中的此类错误,可以在@ModelAttribute
的紧后面添加BindingResult
参数,如以下示例所示:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { (1)
if (result.hasErrors()) {
return "petForm";
}
// ...
}
您可以在数据绑定之后通过添加
javax.validation.Valid
Comments 或 Spring 的@Validated
Comments 来自动应用验证(另请参见Bean validation和Spring validation)。与 Spring MVC 不同,Spring WebFlux 在模型 supports 中支持反应类型,例如
Mono<Account>
或io.reactivex.Single<Account>
。您可以声明带有或不带有 Reactive 类型包装器的@ModelAttribute
参数,并将根据需要将其解析为实际值。但是,请注意,要使用BindingResult
参数,您必须在@ModelAttribute
参数之前声明它而不使用反应式类型包装器,如先前所示。另外,您可以通过反应式处理任何错误,如以下示例所示:
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public Mono<String> processSubmit(@Valid @ModelAttribute("pet") Mono<Pet> petMono) {
return petMono
.flatMap(pet -> {
// ...
})
.onErrorResume(ex -> {
// ...
});
}
请注意,使用
@ModelAttribute
是可选的,例如用于设置其属性。默认情况下,任何不是简单值类型(由BeanUtils#isSimpleProperty确定)且未被其他任何参数解析器解析的参数都将被视为已用@ModelAttribute
Comments。
@SessionAttributes
@SessionAttributes
用于在两次请求之间的WebSession
中存储模型属性。它是类型级别的 Comments,用于声明特定控制器使用的会话属性。这通常列出应透明地存储在会话中以供后续访问请求的模型属性名称或模型属性类型。以下示例:
@Controller
@SessionAttributes("pet") // (1使用@SessionAttributesComments。)
public class EditPetForm {
// ...
}
在第一个请求中,将名称为
pet
的模型属性添加到模型后,该属性会自动提升为WebSession
并保存在其中。它会一直保留在那里,直到另一个控制器方法使用SessionStatus
方法参数来清除存储,如以下示例所示:
@Controller
@SessionAttributes("pet") // (1 使用@SessionAttributesComments。)
public class EditPetForm {
// ...
@PostMapping("/pets/{id}")
public String handle(Pet pet, BindingResult errors, SessionStatus status) { // (2 使用SessionStatus变量。)
if (errors.hasErrors) {
// ...
}
status.setComplete();
// ...
}
}
}
@SessionAttribute
如果您需要访问全局存在(例如,在控制器外部(例如,通过过滤器)Management)并且可能存在或可能不存在的预先存在的会话属性,则可以在方法参数上使用
@SessionAttribute
Comments,作为以下示例显示:
@GetMapping("/")
public String handle(@SessionAttribute User user) { (1 使用@SessionAttribute)
// ...
}
对于需要添加或删除会话属性的用例,请考虑将
WebSession
注入控制器方法。要将模型属性临时存储在会话中作为控制器工作流的一部分,请考虑使用
SessionAttributes
,如@SessionAttributes中所述。
@RequestAttribute
与
@SessionAttribute
相似,您可以使用@RequestAttribute
注解来访问先前创建的预先存在的请求属性(例如WebFilter
),如以下示例所示:
@GetMapping("/")
public String handle(@RequestAttribute Client client) { (1使用@RequestAttribute)
// ...
}
Multipart Content (文件上传)
如Multipart Data中所述,
ServerWebExchange
提供对 Multipart 内容的访问。在控制器中处理文件上传表单(例如,从浏览器)的最佳方法是通过将数据绑定到command object,如以下示例所示:
class MyForm {
private String name;
private MultipartFile file;
// ...
}
@Controller
public class FileUploadController {
@PostMapping("/form")
public String handleFormUpload(MyForm form, BindingResult errors) {
// ...
}
}
您还可以在 RESTful 服务方案中从非浏览器 Client 端提交 Multipart 请求。以下示例将文件与 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 ...
您可以使用
@RequestPart
来访问各个部分,如以下示例所示:
@PostMapping("/")
public String handle(@RequestPart("meta-data") Part metadata, (1-使用@RequestPart获取元数据)
@RequestPart("file-data") FilePart file) { (2-使用@RequestPart获取文件)
// ...
}
要反序列化原始 Component 的内容(例如,类似于
@RequestBody
的 JSON),可以声明一个具体的目标Object
,而不是Part
,如以下示例所示:
@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata) { (1-使用@RequestPart获取元数据)
// ...
}
您可以
@RequestPart
与javax.validation.Valid
或 Spring 的@Validated
注解结合使用,这会导致应用标准 Bean 验证。验证错误导致WebExchangeBindException
400 (BAD_REQUEST) 响应。异常包含BindingResult
错误详细信息,也可以在控制器方法中通过使用异步包装器声明参数然后使用与错误相关的运算符来处理:
@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") Mono<MetaData> metadata){ (1-使用@ValidComments)
// use one of the onError* operators... // account.onError
}
要以
MultiValueMap
的形式访问所有 Multipart 数据,可以使用@RequestBody
,如以下示例所示:
@PostMapping("/")
public String handle(@RequestBody Mono<MultiValueMap<String, Part>> parts) { (1-使用@RequestBody)
// ...
}
要以流方式 Sequences 访问 Multipart 数据,可以将
@RequestBody
与Flux<Part>
结合使用,如以下示例所示:
@PostMapping("/")
public String handle(@RequestBody Flux<Part> parts) { (1-使用@RequestBody)
// ...
}
@RequestBody
您可以使用
@RequestBody
注解将请求正文读取并通过HttpMessageReader反序列化为Object
。与 Spring MVC 不同点,在 WebFlux 中,
@RequestBody
方法参数支持响应类型以及完全无阻塞的读取和(Client 端到服务器)流。以下示例使用Mono
:
@PostMapping("/accounts")
public void handle(@RequestBody Mono<Account> account) {
// ...
}
您可以使用WebFlux Config的HTTP 消息编解码器选项来配置或自定义消息阅读器。
您可以将
@RequestBody
与javax.validation.Valid
或 Spring 的@Validated
注解结合使用,这将导致应用标准 Bean 验证。这会导致应用标准 Bean 验证。验证错误会导致WebExchangeBindException
,从而导致 400 (BAD_REQUEST) 响应。异常包含BindingResult
错误详细信息,可以通过使用异步包装器声明参数然后使用与错误相关的运算符在控制器方法中进行处理:
@PostMapping("/accounts")
public void handle(@Valid @RequestBody Mono<Account> account) {
// use one of the onError* operators... // account.onError
}
HttpEntity (请求参数)
HttpEntity
与使用@RequestBody大致相同,但基于一个容器对象,该对象公开了请求 Headers 和正文。以下示例使用HttpEntity
:
@PostMapping("/accounts")
public void handle(HttpEntity<Account> entity) {
// ...
@ResponseBody
您可以在方法上使用
@ResponseBody
注解,以使返回值通过HttpMessageWriter序列化到响应主体。以下示例显示了如何执行此操作:
@ResponseBody
在类级别上也受支持,在这种情况下,它被所有控制器方法继承。这就是@RestController
的效果,它不过是用@Controller
和@ResponseBody
标记的元 Comments。
@ResponseBody
支持反应式类型,这意味着您可以返回 Reactor 或 RxJava 类型,并将它们产生的异步值呈现给响应。有关更多详细信息,请参见Streaming和JSON rendering。您可以将
@ResponseBody
方法与 JSON 序列化视图结合使用。有关详情,请参见Jackson JSON。您可以使用WebFlux Config的HTTP 消息编解码器选项来配置或自定义消息编写。
ResponseEntity (响应参数)
ResponseEntity
类似于@ResponseBody,但具有状态和标题。例如:
@GetMapping("/something")
public ResponseEntity<String> handle() {
String body = ... ;
String etag = ... ;
return ResponseEntity.ok().eTag(etag).build(body);
}
WebFlux支持使用单个值的反应性类型,以产生
ResponseEntity
异步,和/或单和多值的反应性类型的本体。这允许各种异步响应ResponseEntity
如下:
ResponseEntity<Mono<T>>
或者ResponseEntity<Flux<T>>
在稍后异步提供主体时立即知道响应状态和标头。使用Mono
如果身体由0…1值,或者Flux
如果它可以产生多个值。Mono<ResponseEntity<T>>
提供所有三个 - 响应状态、标头和正文,稍后异步提供。这允许响应状态和标头根据异步请求处理的结果而变化。Mono<ResponseEntity<Mono<T>>>
或者Mono<ResponseEntity<Flux<T>>>
是另一种可能,尽管不太常见的选择。它们首先异步提供响应状态和标头,然后是响应正文,也是异步的,其次。
Jackson JSON
Spring 提供了对 Jackson JSON 库的支持。
Jackson 序列化视图
Spring WebFlux 提供对Jackson 的序列化视图的内置支持,该支持仅渲染
Object
中所有字段的一部分。要将它与@ResponseBody
或ResponseEntity
控制器方法一起使用,可以使用 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;
}
}
@JsonView
允许一组视图类,但每个控制器方法只能指定一个。如果需要激活多个视图,请使用复合界面。
1