@valid和@Validated的区别是什么?
文章目录
- @Valid 和 @Validated 的区别
- 核心区别总结
- 详细对比
- 1. 分组校验(最核心的区别)
- 2. 嵌套校验
- 3. 方法级别校验
- 4. 使用位置
- 实际应用实例
- 场景1:保存和更新用不同规则
- 场景2:嵌套对象校验
- 场景3:Service 层参数校验
- 常见校验注解
- 最佳实践建议
@Valid 和 @Validated 的区别
核心区别总结
| 特性 | @Valid | @Validated |
|---|---|---|
| 所属框架 | Java标准 (JSR-303/JSR-380) | Spring Framework |
| 分组校验 | ❌ 不支持 | ✅ 支持 |
| 嵌套校验 | ✅ 支持 | ❌ 不支持 |
| 用在类上 | ❌ 不可以 | ✅ 可以(声明组) |
| 用在方法参数 | ✅ 可以 | ✅ 可以 |
| 用在方法返回值 | ❌ 不支持 | ✅ 支持 |
详细对比
1. 分组校验(最核心的区别)
@Validated 支持分组,可以根据不同场景使用不同的校验规则:
// 定义分组接口publicinterfaceCreateGroup{}publicinterfaceUpdateGroup{}// 实体类publicclassDriverCertDTO{@NotNull(message="ID不能为空",groups={UpdateGroup.class})privateLongid;@NotBlank(message="驾驶证号不能为空",groups={CreateGroup.class,UpdateGroup.class})privateStringdriverLicenseNo;@NotNull(message="用户ID不能为空",groups={CreateGroup.class})privateLonguserId;}// Controller 使用分组@PostMapping("/create")publicResultcreate(@Validated(CreateGroup.class)@RequestBodyDriverCertDTOdto){// 只校验 CreateGroup 组的字段}@PutMapping("/update")publicResultupdate(@Validated(UpdateGroup.class)@RequestBodyDriverCertDTOdto){// 只校验 UpdateGroup 组的字段,id 不能为空}2. 嵌套校验
@Valid 支持嵌套对象校验:
publicclassDriverCertDTO{@Valid// 必须加 @Valid 才会校验嵌套对象privateUserDTOuser;// UserDTO 内部的校验注解会生效@Valid// 集合内对象校验privateList<@ValidVehicleDTO>vehicles;}publicclassUserDTO{@NotBlank(message="姓名不能为空")privateStringname;@Pattern(regexp="^1[3-9]\\d{9}$")privateStringphone;}@Validated 不支持嵌套校验:
publicclassDriverCertDTO{@Validated// 无效,不会校验 UserDTO 内部字段privateUserDTOuser;}3. 方法级别校验
@Validated 可以用在类上,开启方法参数和返回值的校验:
@Validated// 开启方法级别校验@ServicepublicclassDriverCertService{// 方法参数校验publicvoidcreate(@NotNull(message="DTO不能为空")DriverCertDTOdto){// 业务逻辑}// 返回值校验@NotNull(message="返回值不能为null")publicDriverCertDTOgetById(Longid){returndriverCertMapper.selectById(id);}}@Valid 不能用在类上。
4. 使用位置
| 使用位置 | @Valid | @Validated |
|---|---|---|
| Controller 参数 | ✅ | ✅ |
| Service 方法参数 | ✅ | ✅ |
| 实体类字段(嵌套) | ✅ | ❌ |
| Controller 类 | ❌ | ✅ |
| Service 类 | ❌ | ✅ |
实际应用实例
场景1:保存和更新用不同规则
// DTOpublicclassDriverCertRequest{@Null(groups={CreateGroup.class})@NotNull(groups={UpdateGroup.class})privateLongid;@NotBlank(groups={CreateGroup.class,UpdateGroup.class})privateStringdriverLicenseNo;@Null(groups={CreateGroup.class})@NotNull(groups={UpdateGroup.class})privateStringdriverStatus;}// Controller@RestControllerpublicclassDriverCertController{@PostMapping("/driver")publicResultcreate(@Validated(CreateGroup.class)@RequestBodyDriverCertRequestrequest){// 创建时 id 必须为 null,driverStatus 必须为 null}@PutMapping("/driver/{id}")publicResultupdate(@Validated(UpdateGroup.class)@RequestBodyDriverCertRequestrequest){// 更新时 id 和 driverStatus 不能为 null}}场景2:嵌套对象校验
// 驾驶员信息包含用户信息和车辆列表publicclassDriverCertVO{@Valid// 必须用 @Valid,不能用 @ValidatedprivateUserInfouserInfo;@Valid// 嵌套集合校验privateList<@ValidVehicleInfo>vehicles;}@PostMapping("/driver/batch")publicResultbatchCreate(@Valid@RequestBodyDriverCertVOvo){// userInfo 和 vehicles 内部的校验都会执行}场景3:Service 层参数校验
@Validated@ServicepublicclassDriverCertService{// 普通参数校验publicvoidupdateStatus(@NotNull(message="ID不能为空")Longid,@NotBlank(message="状态不能为空")Stringstatus){// 业务逻辑}// 对象参数校验publicvoidsave(@Validated(CreateGroup.class)DriverCertDTOdto){// 业务逻辑}}常见校验注解
// 空值校验@NotNull// 不能为 null@NotBlank// 不能为 null、空字符串、纯空格@NotEmpty// 不能为 null、空集合/数组/字符串// 数值校验@Min(1)// 最小值@Max(100)// 最大值@DecimalMin("0.1")@DecimalMax("99.99")@Positive// 正数@Negative// 负数// 其他校验@Size(min=1,max=10)// 长度/大小@Pattern(regexp="...")// 正则@Email// 邮箱格式@Past// 过去时间@Future// 未来时间最佳实践建议
一般场景用 @Valid 即可,简单明了
需要分组校验时用 @Validated(如创建/更新共用 DTO)
嵌套对象校验必须用 @Valid
Service 层参数校验用 @Validated(需要加在类上)
可以组合使用:Controller 用 @Validated 做分组,内部嵌套用 @Valid
// 组合使用示例publicclassOrderDTO{@Valid// 嵌套校验privateUserDTOuser;@Valid// 集合嵌套校验privateList<@ValidItemDTO>items;}@PostMapping("/order")publicResultcreate(@Validated(CreateGroup.class)@RequestBodyOrderDTOorder){// 外层用 @Validated 分组,内层用 @Valid 嵌套}