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 校验)

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

相关推荐
打工的小王43 分钟前
Spring Boot(三)Spring Boot整合SpringMVC
java·spring boot·后端
毕设源码-赖学姐1 小时前
【开题答辩全过程】以 高校体育场馆管理系统为例,包含答辩的问题和答案
java·spring boot
vx_Biye_Design1 小时前
【关注可免费领取源码】房屋出租系统的设计与实现--毕设附源码40805
java·spring boot·spring·spring cloud·servlet·eclipse·课程设计
翱翔-蓝天1 小时前
为什么“看起来很规范”的后端项目反而臃肿且性能下降
spring boot
80530单词突击赢2 小时前
JavaWeb进阶:SpringBoot核心与Bean管理
java·spring boot·后端
long3163 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
独断万古他化3 小时前
【SSM开发实战:博客系统】(三)核心业务功能开发与安全加密实现
spring boot·spring·mybatis·博客系统·加密
rannn_1114 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
qq_12498707534 小时前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
倒流时光三十年4 小时前
SpringBoot 数据库同步 Elasticsearch 性能优化
数据库·spring boot·elasticsearch