跳到主要内容

验证

DeepSeek V3 中英对照 Validation

Spring MVC 内置了对 @RequestMapping 方法的验证支持,包括 Java Bean Validation。验证可以在以下两个层级之一应用:

  1. @ModelAttribute@RequestBody@RequestPart 参数解析器会单独验证方法参数,如果方法参数使用了 Jakarta 的 @Valid 或 Spring 的 @Validated 注解,并且 后面没有紧跟 ErrorsBindingResult 参数,并且 不需要方法验证(接下来会讨论)。在这种情况下抛出的异常是 MethodArgumentNotValidException

  2. @Constraint 注解(如 @Min@NotBlank 等)直接声明在方法参数上或方法上(针对返回值)时,必须应用方法验证,这会取代方法参数级别的验证,因为方法验证通过 @Valid 涵盖了方法参数约束和嵌套约束。在这种情况下抛出的异常是 HandlerMethodValidationException

应用程序必须同时处理 MethodArgumentNotValidExceptionHandlerMethodValidationException,因为根据控制器方法的签名,可能会抛出其中任何一个异常。然而,这两种异常的设计非常相似,可以用几乎相同的代码来处理。主要区别在于前者是针对单个对象的,而后者是针对方法参数列表的。

备注

@Valid 不是一个约束注解,而是用于对象内部的嵌套约束。因此,单独使用 @Valid 不会触发方法验证。而 @NotNull 是一个约束注解,将其添加到带有 @Valid 的参数上会触发方法验证。对于空值检查,你也可以使用 @RequestBody@ModelAttributerequired 标志。

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

你可以通过 WebMvc 配置 全局配置一个 Validator,或者通过 @Controller@ControllerAdvice 中的 @InitBinder 方法进行局部配置。你也可以使用多个验证器。

备注

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

错误响应 部分提供了关于如何处理 MethodArgumentNotValidExceptionHandlerMethodValidationException 的更多详细信息,以及如何通过 MessageSource 和特定语言环境的资源包来自定义它们的渲染方式。

为了进一步自定义处理方法验证错误,你可以扩展 ResponseEntityExceptionHandler 或者在控制器或 @ControllerAdvice 中使用 @ExceptionHandler 方法,并直接处理 HandlerMethodValidationException。该异常包含一个 ParameterValidationResult 列表,这些结果按方法参数分组了验证错误。你可以遍历这些结果,或者根据控制器方法参数类型提供一个带有回调方法的访问器:

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) {
// ...
}
});
java