在 Spring Boot 中,参数校验是保证数据合法性的重要手段。除了前面提到的@NotNull、@Size等基础注解外,JSR-303(Bean Validation 1.0)、JSR-349(Bean Validation 1.1)和 JSR-380(Bean Validation 2.0)规范还提供了大量常用的校验注解。下面详细介绍这些注解及其应用场景:
一、基础校验注解
1. 空值校验
|-----------|----------------------------------------------|
| 注解 | 作用 |
| @NotNull | 验证对象不为null,但允许为空字符串("")或空集合。 |
| @Null | 验证对象必须为null。 |
| @NotEmpty | 验证字符串、集合、数组、Map 等不为null且长度 / 大小大于 0(忽略空白字符)。 |
| @NotBlank | 验证字符串不为null且至少包含一个非空白字符(如" "会校验失败)。 |
示例:
public class User {
@NotNull(message = "ID不能为空")
private Long id;
@NotEmpty(message = "姓名不能为空")
private String name;
@NotBlank(message = "用户名不能为空")
private String username;
}
2. 数值校验
|------------------------------|--------------------------------------------|
| 注解 | 作用 |
| @Min(value) | 验证数值(包括基本类型和包装类)必须大于或等于指定最小值。 |
| @Max(value) | 验证数值必须小于或等于指定最大值。 |
| @DecimalMin(value) | 验证 BigDecimal 或字符串表示的数值必须大于或等于指定值(支持精确小数)。 |
| @DecimalMax(value) | 验证 BigDecimal 或字符串表示的数值必须小于或等于指定值(支持精确小数)。 |
| @Digits(integer=, fraction=) | 验证数值的整数部分和小数部分的位数是否符合要求。 |
| @Positive | 验证数值必须为正数(不包括 0)。 |
| @PositiveOrZero | 验证数值必须为正数或 0。 |
| @Negative | 验证数值必须为负数(不包括 0)。 |
| @NegativeOrZero | 验证数值必须为负数或 0。 |
示例:
public class Product {
@Min(value = 1, message = "价格不能低于1")
private double price;
@DecimalMax(value = "1000.00", message = "价格不能超过1000")
private BigDecimal maxPrice;
@Digits(integer = 3, fraction = 2, message = "折扣必须为最多3位整数和2位小数")
private double discount;
}
3. 长度 / 大小校验
|---------------------|-------------------------------------------|
| 注解 | 作用 |
| @Size(min=, max=) | 验证字符串、集合、数组、Map 等的长度或大小必须在指定范围内。 |
| @Length(min=, max=) | 验证字符串长度必须在指定范围内(常用于 Hibernate Validator)。 |
示例:
public class User {
@Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
private String password;
@Size(max = 5, message = "爱好不能超过5个")
private List<String> hobbies;
}
4. 格式校验
|-------------------|------------------------------------------|
| 注解 | 作用 |
| @Email | 验证字符串是否为合法的邮箱格式(默认正则较宽松,可通过regexp参数自定义)。 |
| @Pattern(regexp=) | 验证字符串是否符合指定的正则表达式。 |
| @URL | 验证字符串是否为合法的 URL 格式。 |
示例:
public class Contact {
@Email(message = "邮箱格式不正确")
private String email;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
@URL(message = "网址格式不正确")
private String website;
}
二、高级校验注解
1. 日期 / 时间校验
|------------------|--------------------------------------------|
| 注解 | 作用 |
| @Past | 验证日期 / 时间必须是过去的时间(如.util.Date、LocalDate等)。 |
| @PastOrPresent | 验证日期 / 时间必须是过去或当前时间。 |
| @Future | 验证日期 / 时间必须是未来的时间。 |
| @FutureOrPresent | 验证日期 / 时间必须是未来或当前时间。 |
示例:
public class Event {
@Past(message = "创建时间必须是过去的时间")
private LocalDateTime createTime;
@Future(message = "活动开始时间必须是未来的时间")
private LocalDate startTime;
}
2. 条件校验
|--------------|----------------|
| 注解 | 作用 |
| @AssertTrue | 验证布尔值必须为true。 |
| @AssertFalse | 验证布尔值必须为false。 |
示例:
public class Agreement {
@AssertTrue(message = "必须同意用户协议")
private boolean agreed;
}
- 自定义校验
当内置注解无法满足需求时,可以通过@Constraint自定义校验注解:
// 自定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PasswordValidator.class)public
@interface ValidPassword {
String message() default "密码必须包含大小写字母和数字,长度8-20位";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
// 校验器实现
public class PasswordValidator implements ConstraintValidator<ValidPassword, String> {
private static final Pattern PASSWORD_PATTERN =
Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,20}$");
@Override
public boolean isValid(String password, ConstraintValidatorContext context) {
return password != null && PASSWORD_PATTERN.matcher(password).matches();
}
}
三、分组校验与级联校验
1. 分组校验
通过定义分组接口,为不同场景(如创建、更新)应用不同的校验规则:
// 定义分组接口
public interface CreateGroup {}
public interface UpdateGroup {}
// 实体类中指定分组
public class User {
@NotNull(groups = UpdateGroup.class) // 更新时ID不能为空
private Long id;
@NotBlank(groups = {CreateGroup.class, UpdateGroup.class}) // 创建和更新时都需要
private String username;
}
// 控制器方法中指定分组
@PostMappingpublic User createUser(@Validated(CreateGroup.class) @RequestBody User user) {
return userService.createUser(user);
}
2. 级联校验
当对象包含嵌套属性时,使用@Valid触发嵌套校验:
public class Order {
@NotNull
private Long id;
@Valid // 触发嵌套校验
@NotNull
private User user;
}
四、Hibernate Validator 扩展注解
Hibernate Validator 是 JSR 规范的常用实现,提供了一些额外的校验注解:
|--------------------|---------------------------------------|
| 注解 | 作用 |
| @CreditCardNumber | 验证字符串是否为合法的信用卡号(通过 Luhn 算法校验)。 |
| @Currency | 验证货币金额是否符合指定的货币代码(如@Currency("CNY"))。 |
| @EAN | 验证字符串是否为合法的商品条形码(如 EAN-13)。 |
| @ISBN | 验证字符串是否为合法的 ISBN 编号。 |
| @Range(min=, max=) | 验证数值是否在指定范围内(类似于@Min+@Max)。 |
示例:
public class Payment {
@CreditCardNumber(message = "信用卡号格式不正确")
private String cardNumber;
@Range(min = 1, max = 12, message = "月份必须在1-12之间")
private int month;
}
五、使用注意事项
依赖引入:确保项目中包含spring-boot-starter-validation依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
全局异常处理:添加全局异常处理器捕获校验失败异常:
@ExceptionHandler(MethodArgumentNotValidException.class)public ResponseEntity<Map<String, String>> handleValidationExceptions(
MethodArgumentNotValidException ex) {
// 处理校验错误
}
国际化支持:校验错误信息可通过message.properties实现国际化。