Spring Boot @Validated 和@Valid 区别

在 Spring Boot 应用程序中,@Validated@Valid 都是用于数据校验的注解,但它们之间存在一些关键的区别。总的来说,@Validated 是 Spring 框架提供的对标准 JSR-303 @Valid 注解的增强。

主要区别概览

特性 @Valid (JSR-303) @Validated (Spring)
来源 Java Bean Validation 规范 (JSR-303/JSR-380) 的一部分,是标准 Java EE 注解。 Spring 框架提供的注解,作为 @Valid 的一个变体。
功能 提供基本的校验功能,可以递归地校验嵌套对象。 继承了 @Valid 的所有功能,并增加了分组校验的功能。
应用位置 主要用于方法参数、成员变量和构造函数参数。 可以用在类、方法和方法参数上。当用在类上时,可以支持对方法参数的约束校验。
分组校验 不支持。 支持。可以根据不同的场景(如创建、更新)选择性地触发一部分校验规则。
嵌套校验 支持。在需要校验的嵌套对象字段上添加 @Valid 注解即可。 同样支持嵌套校验,用法与 @Valid 相同。

示例

1. 来源和基本功能
  • @Valid 是 Java 标准规范的一部分,任何兼容 JSR-303/JSR-380 的实现都可以识别它。 Spring Boot 默认集成了 Hibernate Validator 作为其实现。 @Valid 注解能够触发对其所标注对象的整个对象图进行校验。

  • @Validated 是 Spring 框架特有的注解,它在 @Valid 的基础上进行了扩展,最核心的增强就是支持校验分组。

2. 分组校验:@Validated 的核心优势

在实际开发中,同一个数据传输对象(DTO)可能在不同的业务场景下有不同的校验规则。例如,在创建用户时,用户名和密码是必填的;而在更新用户信息时,用户ID是必填的,但密码可能不是。这种情况下,使用 @Validated 的分组功能就非常方便。

示例:使用 @Validated 进行分组校验

首先,定义两个标记接口作为校验分组:

java 复制代码
public interface CreateGroup {}
public interface UpdateGroup {}

然后,在 DTO 的字段上使用 groups 属性来指定校验规则属于哪个分组:

java 复制代码
public class UserDTO {

    @NotNull(message = "用户ID不能为空", groups = UpdateGroup.class)
    private Long id;

    @NotBlank(message = "用户名不能为空", groups = {CreateGroup.class, UpdateGroup.class})
    private String username;

    @NotBlank(message = "密码不能为空", groups = CreateGroup.class)
    private String password;

    // Getters and Setters
}

最后,在 Controller 的方法上使用 @Validated 注解并指定要生效的分组:

java 复制代码
@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public ResponseEntity<String> createUser(@Validated(CreateGroup.class) @RequestBody UserDTO userDTO) {
        // 处理创建用户的逻辑
        return ResponseEntity.ok("用户创建成功");
    }

    @PutMapping
    public ResponseEntity<String> updateUser(@Validated(UpdateGroup.class) @RequestBody UserDTO userDTO) {
        // 处理更新用户的逻辑
        return ResponseEntity.ok("用户更新成功");
    }
}

在这个例子中:

  • 当调用 createUser 接口时,只会校验 CreateGroup 分组的规则,即 usernamepassword 不能为空。
  • 当调用 updateUser 接口时,只会校验 UpdateGroup 分组的规则,即 idusername 不能为空。
3. 嵌套校验:@Valid 的常用场景

当一个对象包含了另一个需要校验的对象时,就需要进行嵌套校验。@Valid 在这种场景下非常实用。

示例:使用 @Valid 进行嵌套校验

假设有一个订单 Order 对象,它包含一个需要校验的 User 对象:

java 复制代码
public class User {
    @NotBlank(message = "用户名不能为空")
    private String name;

    @Email(message = "邮箱格式不正确")
    private String email;

    // Getters and Setters
}

public class Order {
    @NotBlank(message = "订单号不能为空")
    private String orderNumber;

    @NotNull(message = "用户信息不能为空")
    @Valid // 关键点:在这里添加@Valid注解
    private User user;

    // Getters and Setters
}

在 Controller 中,直接在 Order 参数前使用 @Valid@Validated 即可触发嵌套校验:

java 复制代码
@RestController
@RequestMapping("/orders")
public class OrderController {

    @PostMapping
    public ResponseEntity<String> createOrder(@Valid @RequestBody Order order) {
        // 如果Order中的User信息不合法,请求将无法进入该方法
        return ResponseEntity.ok("订单创建成功");
    }
}

createOrder 方法被调用时,校验框架不仅会校验 Order 对象的 orderNumber 字段,还会因为 user 字段上的 @Valid 注解,进而校验 User 对象内部的 nameemail 字段。

4. 应用在非 JavaBean 参数上

@Validated 还可以用在类级别,以便能够校验方法中非 JavaBean 的参数,例如路径变量 (@PathVariable) 和请求参数 (@RequestParam)。要实现这一点,需要在 Controller 类上添加 @Validated 注解。

示例:

java 复制代码
@RestController
@RequestMapping("/items")
@Validated // 放在类级别
public class ItemController {

    @GetMapping("/{id}")
    public ResponseEntity<String> getItemById(@PathVariable("id") @Min(1) Long id) {
        return ResponseEntity.ok("获取物品成功,ID: " + id);
    }
}

在这个例子中,如果请求的 id 小于1,将会触发一个 ConstraintViolationException

总结

  • 如果只需要简单的校验,不涉及复杂的分组场景,使用 @Valid 就足够了。
  • 当需要根据不同的业务场景应用不同的校验规则时,@Validated 的分组功能是最佳选择。
  • 在进行嵌套对象校验时,务必在嵌套对象的字段上使用 @Valid 注解。
  • 若要校验 @PathVariable@RequestParam 这类方法参数,需要在对应的类上标注 @Validated 注解。
相关推荐
用户849137175471628 分钟前
JDK 17 实战系列(第7期):迁移指南与最佳实践
java·jvm
duration~32 分钟前
SpringAI实现Reread(Advisor)
java·人工智能·spring boot·spring
我们从未走散38 分钟前
面试题-----微服务业务
java·开发语言·微服务·架构
YuforiaCode40 分钟前
24SpringCloud黑马商城微服务整合Seata重启服务报错的解决办法
java·spring·微服务
北方有星辰zz1 小时前
线程的同步与互斥
数据库
考虑考虑1 小时前
JDK21中的Sequenced Collections(序列集合)
java·后端·java ee
goyeer1 小时前
【MYSQL】MySQL中On duplicate key update
数据库·mysql
一 乐2 小时前
心理咨询|学生心理咨询评估系统|基于Springboot的学生心理咨询评估系统设计与实现(源码+数据库+文档)
java·数据库·spring boot·后端·论文·毕设·学生心理咨询评估系统
Java技术小馆2 小时前
Gemini Storybook AI驱动的交互式故事创作
java·程序员·架构
TDengine (老段)2 小时前
TDengine IDMP 基本功能(1.界面布局和操作)
大数据·数据库·物联网·ai·时序数据库·tdengine·涛思数据