验证
Spring MVC 为 @RequestMapping 方法(包括 Java Bean Validation)提供了内置的验证。验证可以在两个级别之一应用:
-
Java Bean Validation 单独应用于通过
@jakarta.validation.Valid或 Spring 的@Validated注解的 @ModelAttribute、@RequestBody 和 @RequestPart 方法参数,只要它是一个命令对象而不是Map或Collection等容器,并且在方法签名中紧随其后没有Errors或BindingResult,并且不以其他方式需要方法验证(参见下一段)。当单独验证方法参数时,会抛出MethodArgumentNotValidException异常。 -
当
@Constraint注解(如@Min、@NotBlank等)直接在方法参数上声明,或为返回值在方法上声明时,Java Bean Validation 将应用于该方法。它会取代任何原本将单独应用于方法参数的验证,因为方法验证涵盖了方法参数约束和通过@Valid的嵌套约束。当验证应用于方法时,会抛出HandlerMethodValidationException异常。
应用程序应处理 MethodArgumentNotValidException 和 HandlerMethodValidationException,因为根据控制器方法的签名,两者都可能被抛出。然而,这两个异常设计得非常相似,并且可以用几乎相同的代码来处理。主要区别在于前者针对单个对象,而后者针对方法参数列表。
@Valid 不是一个约束注解,而是用于对象内部的嵌套约束。因此,单独使用 @Valid 不会导致方法验证。另一方面,@NotNull 是一个约束,将其添加到 @Valid 参数会导致方法验证。对于空值检查,您也可以使用 @RequestBody 或 @ModelAttribute 的 required 标志。 |
方法验证可以与 Errors 或 BindingResult 方法参数结合使用。但是,只有当所有验证错误都发生在紧随其后带有 Errors 的方法参数上时,才会调用控制器方法。如果任何其他方法参数存在验证错误,则会抛出 HandlerMethodValidationException。
您可以通过 WebMvc 配置全局配置 Validator,或通过 @Controller 或 @ControllerAdvice 中的 @InitBinder 方法局部配置。您也可以使用多个验证器。
如果控制器具有类级别的 @Validated,则 方法验证将通过 AOP 代理应用。为了利用 Spring Framework 6.1 中添加的 Spring MVC 内置方法验证支持,您需要从控制器中删除类级别的 @Validated 注解。 |
错误响应部分提供了关于 MethodArgumentNotValidException 和 HandlerMethodValidationException 如何处理的更多详细信息,以及如何通过 MessageSource 和特定于区域设置和语言的资源包来自定义它们的呈现。
为了进一步自定义处理方法验证错误,您可以扩展 ResponseEntityExceptionHandler 或在控制器或 @ControllerAdvice 中使用 @ExceptionHandler 方法,并直接处理 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) {
// ...
}
})