Java 参数校验之 @Valid vs @Validated 速查笔记
1. 来源与定位
| 维度 |
@Valid |
@Validated |
| 规范 |
JSR-303/JSR-380(javax.validation) |
Spring Framework 扩展 |
| 所在包 |
javax.validation.Valid |
org.springframework.validation.annotation.Validated |
| 核心定位 |
标准校验触发器 |
带“分组”特性的校验触发器 |
2. 功能差异速览
| 功能 |
@Valid |
@Validated |
| 触发标准校验 |
✅ |
✅ |
| 支持分组(groups) |
❌ |
✅ |
| 支持嵌套校验 |
✅ |
❌(仅能写在类/方法/参数上,不能递归) |
| 使用位置 |
字段、构造器、方法参数、返回值 |
类、方法、方法参数 |
| 需要配合 Spring AOP |
❌ |
✅(类上必须加 @Validated 才能激活方法参数校验) |
3. 使用场景对照
| 场景 |
推荐注解 |
原因 |
| Controller 入参是 复杂 Bean
|
@Valid 或 @Validated
|
简单、语义清晰 |
| Controller 入参是 简单类型(String、int…) |
@Validated 必须写在 类 上,再对参数加约束注解 |
只有 Spring 的方法级校验支持 |
| 需要 分组校验(新增/更新不同规则) |
@Validated(Group.class) |
分组是 Spring 扩展 |
| 需要 嵌套校验(对象里还有对象) |
@Valid 写在属性或集合上 |
支持递归 |
4. 代码示例
4.1 基本 Bean 校验(无分组)
// Bean
public class UserDTO {
@NotBlank
private String name;
@Min(18)
private int age;
}
// Controller
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public String add(@Valid @RequestBody UserDTO dto) { // @Validated 亦可
return "saved";
}
}
4.2 分组校验(新增/更新)
// 1. 定义分组标记接口
public interface Create {}
public interface Update {}
// 2. Bean 中指定分组
public class UserDTO {
@NotNull(groups = Update.class)
private Long id;
@NotBlank(groups = {Create.class, Update.class})
private String name;
@Min(value = 18, groups = Create.class)
private int age;
}
// 3. Controller
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping // 新增
public String create(@Validated(Create.class) @RequestBody UserDTO dto) {
return "created";
}
@PutMapping // 更新
public String update(@Validated(Update.class) @RequestBody UserDTO dto) {
return "updated";
}
}
4.3 方法参数为简单类型(String)
@RestController
@RequestMapping("/hello")
@Validated // ✅ 必须加在类上,才能激活方法参数校验
public class HelloController {
@GetMapping
public String hi(
@NotBlank(message = "name 不能为空") @RequestParam String name) {
return "Hi, " + name;
}
}
@Valid 写在简单参数上 无效;@Validated 放在方法上也 无效。
4.4 嵌套校验(三层结构)
// 最内层
public class Stock {
@Min(value = 1, message = "库存必须大于0")
private int quantity;
}
// 第二层
public class Item {
@NotBlank
private String name;
@DecimalMin("0.01")
private BigDecimal price;
@Valid // 递归校验
@NotNull
private Stock stock;
// 更推荐这样写
// @NotNull
// private @Valid Stock stock;
}
// 最外层
public class OrderDTO {
@NotBlank
private String orderNo;
@Valid // List 中每个元素都校验
@NotEmpty
private List<Item> items;
// 更推荐这样写
// @NotEmpty
// private List<@Valid Item> items;
}
// Controller
@RestController
@RequestMapping("/orders")
public class OrderController {
@PostMapping
public String create(@Valid @RequestBody OrderDTO dto) { // @Validated 亦可
return "order created";
}
}
5. 常见误区提醒
-
@Valid 无法指定分组;需要分组请用 @Validated(Group.class)。
- 简单参数(String、int…)的校验必须把
@Validated 写在 类 上,再对参数加约束注解。
-
@Validated 不支持嵌套校验;嵌套请用 @Valid(放在类名上和放在属性上效果一样,前者更推荐,如 private @Valid Stock stock;)。
-
@Valid 可以放在 List<@Valid Item> 上,Spring 会逐条校验(放在泛型上和放在属性上效果一样,前者更推荐,如 private List<@Valid Item> items;)。
6. 一句话速记
-
复杂对象 →
@Valid(@Validated 亦可)
-
简单参数 → 类上加
@Validated
-
不同规则 →
@Validated(Group.class)
-
嵌套对象 → 属性上加
@Valid
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。