Spring Boot 中 JSR-303 配合 Hibernate Validator 实现全自动化校验,依赖注解驱动、框架自动触发与统一异常拦截;需引入 spring-boot-starter-validation,DTO 字段加约束注解,@RequestBody 参数用 @Valid,@RequestParam 用 @Validated,再通过 @ControllerAdvice 统一处理异常。

Spring Boot 项目中,JSR-303(即 Jakarta Bean Validation)配合 Hibernate Validator 可以在 Controller 层实现业务实体类的全自动化校验,无需手写 if 判断,也不依赖手动调用验证器。核心在于“注解驱动 + 框架自动触发 + 统一异常拦截”三者协同。
基础依赖与默认支持
Spring Boot 2.3.x 及以后版本已将 spring-boot-starter-validation 设为独立 starter,需显式引入:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
低于 2.3.x 的版本,该依赖由 spring-boot-starter-web 自动传递,可不额外声明。Hibernate Validator 是其默认实现,开箱即用。
实体类添加校验注解
在 DTO 或请求体对象(如 UserRegisterDTO)的字段上直接标注约束注解:
-
@NotBlank(message = "用户名不能为空")—— 非 null、非空串、非纯空白 -
@Email(message = "邮箱格式不正确")—— 来自 Hibernate Validator 扩展,非 JSR 原生 @Min(value = 18, message = "年龄不能小于18")@Size(min = 6, max = 20, message = "密码长度必须为6~20位")@Pattern(regexp = "^1[3-9]\d{9}$", message = "手机号格式错误")
注意:@NotEmpty 允许空格和空字符串,@NotBlank 更严格;@Size 对字符串校验的是字符长度,对集合校验的是元素个数。
Controller 方法启用自动校验
对 @RequestBody 参数,只需在参数前加 @Valid:
@PostMapping("/register")
public Result register(@RequestBody @Valid UserRegisterDTO dto) {
return userService.register(dto);
}
框架会在绑定请求体后、进入方法前自动执行校验。若失败,不会执行方法体,而是抛出 MethodArgumentNotValidException。
对 @RequestParam 或 @PathVariable 参数,需在 Controller 类上加 @Validated,并在参数上直接标注约束(如 @Min(1)),此时抛出的是 ConstraintViolationException。
统一异常处理返回友好提示
通过 @ControllerAdvice 拦截两类校验异常,提取所有错误消息并聚合返回:
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleBodyValidation(MethodArgumentNotValidException e) {
List<String> errors = e.getBindingResult()
.getAllErrors()
.stream()
.map(ObjectError::getDefaultMessage)
.collect(Collectors.toList());
return Result.fail("参数校验失败:" + String.join(";", errors));
}
@ExceptionHandler(ConstraintViolationException.class)
public Result handleParamValidation(ConstraintViolationException e) {
String msg = e.getConstraintViolations().stream()
.map(v -> v.getMessage())
.collect(Collectors.joining(";"));
return Result.fail("请求参数异常:" + msg);
}
这样前端收到的是结构化错误信息,而非 500 或堆栈,体验更可控。
整个流程不需要 new Validator、不调用 validate() 方法、不写校验逻辑分支——只要注解到位、触发方式正确、异常兜底完整,就是真正的“全自动化校验”。


















