验证
Spring WebFlux 为 @RequestMapping 方法提供了内置的 验证,包括 Java Bean 验证。验证可以在两个级别之一应用:
-
@ModelAttribute、@RequestBody 和 @RequestPart 参数解析器会单独验证方法参数,如果方法参数被 Jakarta
@Valid或 Spring 的@Validated注解标注,并且 后面没有Errors或BindingResult参数,并且 不需要方法验证(将在下文讨论)。在这种情况下引发的异常是WebExchangeBindException。 -
当
@Constraint注解如@Min、@NotBlank等直接声明在方法参数上,或在方法上(针对返回值)时,则必须应用方法验证,这将优先于方法参数级别的验证,因为方法验证涵盖了方法参数约束和通过@Valid的嵌套约束。在这种情况下引发的异常是HandlerMethodValidationException。
应用程序必须处理 WebExchangeBindException 和 HandlerMethodValidationException,因为根据控制器方法的签名,可能会引发这两种异常。然而,这两种异常的设计非常相似,可以用几乎相同的代码进行处理。主要区别在于前者用于单个对象,而后者用于一组方法参数。
@Valid 不是一个约束注解,而是用于对象内部的嵌套约束。因此,单独使用 @Valid 并不会导致方法验证。另一方面,@NotNull 是一个约束,将其添加到 @Valid 参数上会导致方法验证。特别针对可空性,您还可以使用 @RequestBody 或 @ModelAttribute 的 required 标志。
方法验证可以与 Errors 或 BindingResult 方法参数结合使用。然而,只有当所有验证错误都在紧接着的 Errors 方法参数上时,控制器方法才会被调用。如果其他任何方法参数上存在验证错误,则会引发 HandlerMethodValidationException。
您可以通过 WebFlux 配置 全局配置 Validator,或通过 @Controller 或 @ControllerAdvice 中的 @InitBinder 方法进行本地配置。您还可以使用多个验证器。
如果一个控制器具有类级别的 @Validated,那么 方法验证将通过 AOP 代理应用。为了利用 Spring Framework 6.1 中新增的 Spring MVC 内置方法验证支持,您需要从控制器中移除类级别的 @Validated 注解。
错误响应 部分提供了有关 WebExchangeBindException 和 HandlerMethodValidationException 如何处理的更多细节,以及如何通过 MessageSource 和特定于区域和语言的资源包自定义它们的渲染。
为了进一步自定义方法验证错误的处理,您可以扩展 ResponseEntityExceptionHandler 或在控制器中使用 @ExceptionHandler 方法,或者在 @ControllerAdvice 中直接处理 HandlerMethodValidationException。该异常包含一个 ParameterValidationResult 的列表,这些结果按方法参数分组验证错误。您可以遍历这些结果,或者根据控制器方法参数类型提供一个带有回调方法的访问者:
- Java
- Kotlin
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) {
// ...
}
})