
在日常开发中,参数校验 是保障接口健壮性与数据安全的第一道防线。Spring Boot 为我们提供了基于 JSR-303/JSR-380 的强大校验机制,通过注解与 AOP 实现了灵活且高效的数据校验方式。本篇博客将详细介绍 Spring Boot 中 @Valid
、@Validated
注解的使用方法,并深入解析其背后的原理与扩展能力。
一、引入依赖
Spring Boot 项目中默认支持 javax.validation
,但建议显式引入:
xml
<!-- Hibernate Validator 是实现规范最广的一个实现 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
二、基础注解使用
在 Java Bean 上添加注解,示例:
java
public class UserDTO {
@NotBlank(message = "用户名不能为空")
private String username;
@Email(message = "邮箱格式不正确")
private String email;
@Min(value = 18, message = "年龄必须 >= 18")
@Max(value = 100, message = "年龄必须 <= 100")
private Integer age;
// Getter / Setter
}
三、在 Controller 中启用校验
1. 使用 @Valid
(javax.validation)注解:
java
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/create")
public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO user) {
return ResponseEntity.ok("创建成功");
}
}
2. 使用 @Validated
(Spring 提供)支持 分组校验:
java
public class UserDTO {
@NotBlank(message = "用户名不能为空", groups = Create.class)
private String username;
public interface Create {}
}
java
@PostMapping("/create")
public ResponseEntity<String> createUser(@Validated(UserDTO.Create.class) @RequestBody UserDTO user) {
return ResponseEntity.ok("按分组校验通过");
}
四、校验嵌套对象
java
public class OrderDTO {
@NotNull
@Valid // 注意:嵌套对象必须加 @Valid 才能触发其内部校验
private UserDTO user;
}
五、处理校验失败异常
Spring Boot 默认抛出 MethodArgumentNotValidException
(@Valid)或 ConstraintViolationException
(@Validated)。
可以通过全局异常处理捕获并格式化返回:
java
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<?> handleValidException(MethodArgumentNotValidException ex) {
String errorMsg = ex.getBindingResult().getAllErrors()
.stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining("; "));
return ResponseEntity.badRequest().body("参数错误:" + errorMsg);
}
}
六、自定义校验注解
1. 自定义注解:
java
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {PhoneValidator.class})
public @interface Phone {
String message() default "手机号格式不正确";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
2. 编写校验器:
java
public class PhoneValidator implements ConstraintValidator<Phone, String> {
private static final Pattern PATTERN = Pattern.compile("^1[3-9]\\d{9}$");
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value != null && PATTERN.matcher(value).matches();
}
}
3. 使用:
java
@Phone
private String phone;
七、常用校验注解速查表
注解 | 功能说明 |
---|---|
@NotNull |
不能为 null |
@NotEmpty |
不能为 null 且长度 > 0 |
@NotBlank |
不能为 null 且去空格后长度 > 0 |
@Email |
邮箱格式 |
@Min |
最小值限制 |
@Max |
最大值限制 |
@Pattern |
正则校验 |
@Size |
长度范围校验 |
@Future |
必须是未来时间 |
@Past |
必须是过去时间 |
八、注意事项与最佳实践
- 嵌套校验字段必须加
@Valid
。 @Validated
支持分组、@Valid
不支持。- 实体类字段建议使用包装类型(如
Integer
而非int
),避免 null 时校验器报错。 - 参数校验推荐配合统一响应结构,提升开发与调试体验。