Data Validation数据校验机制与内容

好的,我们来全面、系统、深入 地梳理 Java 生态(尤其是 Spring Boot)中数据校验(Data Validation)的完整机制。内容涵盖:

  1. 默认校验依赖(JAR 包)
  2. 标准规范演进(JSR-303 → JSR-380 → Jakarta Bean Validation)
  3. 所有内置校验注解(分门别类,含说明与示例)
  4. 校验分组(Groups)
  5. 级联校验(@Valid on nested objects)
  6. 自定义校验注解开发
  7. 与 Spring Boot 的集成方式
  8. 异常处理机制
  9. 正则表达式在校验中的核心作用
  10. 与其他校验工具对比(如 Guava Preconditions、Apache Commons Validator)

一、默认校验 JAR 包(Spring Boot 环境)

Spring Boot 3.x(基于 Jakarta EE 9+)默认使用:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

该 starter 会自动引入:

  • jakarta.validation:jakarta.validation-api规范接口
  • org.hibernate.validator:hibernate-validator官方参考实现
  • org.glassfish:jakarta.el → 支持错误消息中的表达式(如 ${validatedValue}

Spring Boot 2.x 使用的是 javax.validation,3.x 起包名改为 jakarta.validation


二、规范演进

规范 JSR 版本 主要特性
Bean Validation 1.0 JSR-303 2009 基础注解(@NotNull, @Min 等)
Bean Validation 2.0 JSR-380 2017 支持容器元素校验(List<@Email String>)、Java 8 时间类型、自定义注解增强
Jakarta Bean Validation 3.0+ - 2020+ 包名从 javaxjakarta,兼容 Jakarta EE 9+

三、所有内置校验注解(按类别)

1. 空值校验
注解 适用类型 说明
@Null 任意 必须为 null
@NotNull 任意 不能为 null(但可为空字符串)
@NotEmpty String, Collection, Map, Array 不能为 nullsize() > 0
@NotBlank String 不能为 nulltrim() 后长度 > 0
2. 数值校验
注解 说明
@Min(value) ≥ value(支持 long、int、BigDecimal 等)
@Max(value) ≤ value
@DecimalMin(value) 字符串或数值 ≥ value(可指定 inclusive)
@DecimalMax(value) 字符串或数值 ≤ value
@Positive > 0(JSR-380)
@PositiveOrZero ≥ 0
@Negative < 0
@NegativeOrZero ≤ 0
3. 长度与大小校验
注解 适用类型 说明
@Size(min, max) String, Collection, Map, Array 元素个数或字符串长度在 [min, max]
@Digits(integer, fraction) 数值或字符串 整数部分最多 integer 位,小数部分最多 fraction 位(用于金额校验)
4. 格式校验(含正则)
注解 说明
@Email 邮箱格式(底层用正则)
@Pattern(regexp, flags) 自定义正则表达式校验(核心!)
@URL URL 格式(可指定协议、主机等)
5. 时间校验
注解 说明
@Past 时间在当前时间之前
@PastOrPresent ≤ 当前时间
@Future > 当前时间
@FutureOrPresent ≥ 当前时间

支持 java.util.Date, java.time.*(LocalDateTime, ZonedDateTime 等)

6. 布尔校验
注解 说明
@AssertTrue boolean/Boolean 必须为 true
@AssertFalse 必须为 false
7. 容器元素校验(JSR-380 新增)
java 复制代码
public class User {
    // 校验 List 中的每个 email
    private List<@Email String> emails;

    // 校验 Map 的 value
    private Map<String, @NotBlank String> metadata;
}

四、校验分组(Groups)

用于不同场景使用不同校验规则,例如:

  • 新增时:id 可为空
  • 更新时:id 必须存在
java 复制代码
public interface CreateGroup {}
public interface UpdateGroup {}

public class UserDTO {
    @NotNull(groups = UpdateGroup.class)
    private Long id;

    @NotBlank(groups = {CreateGroup.class, UpdateGroup.class})
    private String name;
}

// Controller
@PostMapping("/create")
public void create(@Validated(CreateGroup.class) @RequestBody UserDTO user) { }

@PutMapping("/update")
public void update(@Validated(UpdateGroup.class) @RequestBody UserDTO user) { }

五、级联校验(@Valid)

校验嵌套对象:

java 复制代码
public class Order {
    @Valid
    private User buyer; // 会递归校验 User 内部的字段
}

public class User {
    @NotBlank
    private String name;
}

六、自定义校验注解

步骤:

  1. 定义注解
  2. 实现 ConstraintValidator
java 复制代码
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
    String message() default "身份证格式错误";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class IdCardValidator implements ConstraintValidator<IdCard, String> {
    @Override
    public boolean isValid(String value, ConstraintValidationContext context) {
        if (value == null) return true;
        return value.matches("^\\d{17}[\\dXx]$"); // 简化版
    }
}

七、Spring Boot 集成方式

  • Controller 参数校验@Valid / @Validated
  • Service 层校验 :手动调用 Validator
  • 配置文件启用/禁用spring.jpa.properties.javax.persistence.validation.mode=none(如需关闭 JPA 自动校验)

八、异常处理

校验失败时抛出:

  • MethodArgumentNotValidException(Controller 参数校验失败)
  • ConstraintViolationException(手动调用 Validator 失败)

建议全局异常处理:

java 复制代码
@RestControllerAdvice
public class ValidationExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidation(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(error ->
            errors.put(error.getField(), error.getDefaultMessage())
        );
        return ResponseEntity.badRequest().body(errors);
    }
}

九、正则表达式与校验的关系(核心)

  • @Pattern(regexp = "...")唯一允许你写任意正则的内置注解。
  • 正则表达式用于精确控制字符串格式 ,例如:
    • 手机号:^1[3-9]\d{9}$
    • 身份证:^\d{17}[\dXx]$
    • 强密码:^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*#?&]{8,}$

注意:正则性能、安全性(避免 ReDoS)需谨慎。


十、与其他校验工具对比

工具 定位 特点
Jakarta Bean Validation 标准、声明式、与框架集成 注解驱动,支持分组、级联、国际化
Guava Preconditions 运行时参数校验 用于方法内部 checkNotNull()不用于 DTO 校验
Apache Commons Validator 传统工具类 手动调用 EmailValidator.getInstance().isValid(email),无注解支持
Spring Assert Spring 内部工具 Assert.hasText(),常用于私有方法参数校验

结论 :在 Spring Boot Web 项目中,Jakarta Bean Validation 是首选,其他工具用于特定场景。


总结图谱

复制代码
数据校验体系
├── 规范:Jakarta Bean Validation (JSR-380+)
├── 实现:Hibernate Validator(默认)
├── 校验方式
│   ├── 内置注解(40+种,覆盖空值、数值、格式、时间等)
│   ├── 正则表达式(@Pattern 核心)
│   ├── 自定义注解(ConstraintValidator)
│   ├── 分组校验(Create/Update 场景)
│   └── 级联校验(@Valid 嵌套对象)
├── 框架集成:Spring Boot(@Valid + 全局异常)
└── 补充工具:Guava / Commons(非主流 Web 校验)

如果你需要 完整可运行的示例项目(含分组、自定义注解、正则、异常处理),我可以为你生成。是否需要?

相关推荐
爱吃山竹的大肚肚2 小时前
优化SQL:如何使用 EXPLAIN
java·数据库·spring boot·sql·spring
Kiyra2 小时前
Spring Boot Starter 自定义开发:封装中间件配置
spring boot·redis·后端·缓存·中间件·性能优化·rocketmq
码界奇点3 小时前
基于Spring Boot和微信小程序的小程序商城系统设计与实现
spring boot·微信小程序·小程序·毕业设计·源代码管理
+VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue英语学习系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
伯明翰java3 小时前
【无标题】springboot项目yml中使用中文注释报错的解决方法
java·spring boot·后端
码界奇点4 小时前
基于Spring Boot和Vue.js的视频点播管理系统设计与实现
java·vue.js·spring boot·后端·spring·毕业设计·源代码管理
廋到被风吹走4 小时前
【Spring】Spring Boot详细介绍
java·spring boot·spring
czlczl200209254 小时前
基于 Spring Boot 权限管理 RBAC 模型
前端·javascript·spring boot
计算机毕设指导64 小时前
基于微信小程序的智慧社区娱乐服务管理系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·娱乐