对于最新稳定版本,请使用 Spring Framework 7.0.6spring-doc.cadn.net.cn

验证

Spring WebFlux 为 xref page 方法提供了内置的验证(Validation)功能,包括Java Bean 验证(Java Bean Validation)。 验证可以在以下两个级别之一应用:spring-doc.cadn.net.cn

  1. @ModelAttribute@RequestBody@RequestPart 参数解析器会在方法参数标注了 Jakarta @Valid 或 Spring 的 @Validated并且其后没有紧跟着 ErrorsBindingResult 参数,并且不需要方法验证(稍后讨论)时,单独验证该方法参数。此种情况下抛出的异常是 WebExchangeBindExceptionspring-doc.cadn.net.cn

  2. @Constraint 注解(例如 @Min@NotBlank 等)直接声明在方法参数上,或声明在方法上(用于返回值)时,必须应用方法级验证。此时,方法级验证将取代方法参数级别的验证,因为方法级验证通过 @Valid 同时覆盖了方法参数约束和嵌套约束。在这种情况下抛出的异常是 HandlerMethodValidationExceptionspring-doc.cadn.net.cn

应用程序必须同时处理 WebExchangeBindExceptionHandlerMethodValidationException,因为根据控制器方法签名的不同,可能会抛出其中任意一个异常。不过,这两种异常的设计非常相似,几乎可以用完全相同的代码进行处理。主要区别在于,前者针对单个对象,而后者针对方法参数列表。spring-doc.cadn.net.cn

@Valid 不是一个约束注解,而是用于对象内部的嵌套约束。因此,单独使用 @Valid 并不会触发方法验证。@NotNull 则是一个约束注解,将其添加到带有 @Valid 的参数上会触发方法验证。对于可空性(nullability)问题,你也可以使用 required@RequestBody 注解中的 @ModelAttribute 标志。

方法验证可与 ErrorsBindingResult 方法参数结合使用。然而,只有当所有验证错误都出现在紧随其后的带有 Errors 的方法参数上时,控制器方法才会被调用。如果任何其他方法参数上存在验证错误,则会抛出 HandlerMethodValidationExceptionspring-doc.cadn.net.cn

你可以通过WebFlux 配置全局配置一个../config.html#webflux-config-validation,也可以在xref pageann-initbinder.html中通过@InitBinder方法进行局部配置。你还可以使用多个验证器。spring-doc.cadn.net.cn

如果控制器类上使用了 @Validated 注解,那么 方法级验证将通过 AOP 代理应用。 为了利用 Spring Framework 6.1 中新增的 Spring MVC 内置方法验证支持, 你需要从控制器类上移除 @Validated 注解。

错误响应部分进一步详细说明了如何处理 WebExchangeBindExceptionHandlerMethodValidationException,以及如何通过 MessageSource 及与区域(locale)和语言相关的资源包(resource bundles)来自定义它们的渲染方式。spring-doc.cadn.net.cn

如需对方法验证错误进行更进一步的自定义处理,您可以扩展 ResponseEntityExceptionHandler,或在控制器(controller)或 @ExceptionHandler 中使用 @ControllerAdvice 方法,直接处理 HandlerMethodValidationException。 该异常包含一个 ParameterValidationResult 列表,其中按方法参数对验证错误进行了分组。您可以遍历这些结果,也可以提供一个访问者(visitor),通过针对控制器方法参数类型的回调方法进行处理:spring-doc.cadn.net.cn

HandlerMethodValidationException ex = ... ;

ex.visitResults(new HandlerMethodValidationException.Visitor() {

	@Override
	public void requestHeader(RequestHeader requestHeader, ParameterValidationResult result) {
			// ...
	}

	@Override
	public void requestParam(@Nullable RequestParam requestParam, ParameterValidationResult result) {
			// ...
	}

	@Override
	public void modelAttribute(@Nullable ModelAttribute modelAttribute, ParameterErrors errors) {

	// ...

	@Override
	public void other(ParameterValidationResult result) {
			// ...
	}
});
// HandlerMethodValidationException
val ex

ex.visitResults(object : HandlerMethodValidationException.Visitor {

	override fun requestHeader(requestHeader: RequestHeader, result: ParameterValidationResult) {
			// ...
       }

	override fun requestParam(requestParam: RequestParam?, result: ParameterValidationResult) {
			// ...
       }

	override fun modelAttribute(modelAttribute: ModelAttribute?, errors: ParameterErrors) {
			// ...
       }

	// ...

	override fun other(result: ParameterValidationResult) {
			// ...
       }
})