日常使用chatgpt - 参数校验注解 - @Valid和@Validated的区别

241 阅读7分钟

实际开发中一直使用的是@Valid,心血来潮使用chatgpt搜索了一下@Valid和@Validated的区别


问1: @Valid和@Validated的区别

答1:

@Valid和@Validated都是Spring框架中用来验证参数和对象的注解。它们的区别如下:

  1. 验证粒度不同:@Validated用于方法和类型级别的验证,@Valid只用于方法参数验证。
  2. 支持的验证框架不同:@Valid支持JSR 303(Bean Validation 1.0),而@Validated支持JSR 303和JSR 349(Bean Validation 1.1)。
  3. 对注解的处理方式不同:@Valid是标准的JSR 303注解,而@Validated是Spring框架提供的注解,它除了支持JSR 303和JSR 349规范中的约束之外,还提供了自己的一些特殊功能。
  4. 对分组验证的支持不同:@Validated支持分组验证,而@Valid不支持。
  5. 验证失败时抛出的异常不同:@Validated会抛出ConstraintViolationException异常,@Valid会抛出MethodArgumentNotValidException异常。

问2: 请给出完整的示例

答2:

假设有一个User类:

public class User {
    @NotEmpty(message = "姓名不能为空")
    private String name;
    @Min(value = 18, message = "年龄不能小于18岁")
    private Integer age;

    // getter和setter方法
}

现在我们要用@Valid和@Validated来验证User类的参数:

  1. 使用@Validated注解
@RestController
@Validated
public class UserController {
    @PostMapping("/user")
    public String addUser(@Validated @RequestBody User user) {
        // 处理新增用户请求
        return "新增用户成功";
    }
}
  1. 使用@Valid注解
@RestController
public class UserController {
    @PostMapping("/user")
    public String addUser(@RequestBody @Valid User user) {
        // 处理新增用户请求
        return "新增用户成功";
    }
}

在两个示例中,我们都是在方法参数中使用@Validated或@Valid注解,用来验证传入的User对象是否合法。如果参数验证失败,Spring框架会自动抛出异常并返回错误消息。如果参数验证成功,则继续执行方法处理逻辑。


问3: 再来一个

答3:

好的,再举一个分组验证的示例。假设User类中有一个字段需要在不同的场景下验证不同的规则,我们就可以使用分组验证来实现。我们可以定义两个不同的分组:Add,Update,分别表示新增和修改时需要验证的规则。代码示例如下:

public class User {
    @NotEmpty(message = "姓名不能为空", groups = {Add.class, Update.class})
    private String name;

    @NotNull(message = "年龄不能为空")
    @Min(value = 18, message = "年龄不能小于18岁", groups = {Add.class})
    @Max(value = 60, message = "年龄不能大于60岁", groups = {Update.class})
    private Integer age;

    // getter和setter方法
}

// 定义分组接口
interface Add {}
interface Update {}

在上面的代码中,我们使用groups属性来指定验证规则所属的分组。在新增用户时需要验证name非空,同时验证age大于18岁;在修改用户时需要验证name非空,同时验证age小于等于60岁。现在我们来看如何使用分组验证:

@RestController
@Validated
public class UserController {
    @PostMapping("/user/create")
    public String createUser(@RequestBody @Validated(value = Add.class) User user) {
        // 处理新增用户请求
        return "新增用户成功";
    }

    @PutMapping("/user/update")
    public String updateUser(@RequestBody @Validated(value = Update.class) User user) {
        // 处理修改用户请求
        return "修改用户成功";
    }
}

在上面的代码中,我们在@Validated注解中指定了值为Add.class或者Update.class,表示当前验证属于哪个分组。这样就可以根据不同场景下的需求来进行验证了。

问4: 再来一个get方式的

答4:

好的,接下来是一个使用GET请求的参数验证示例。假设我们的接口路径为/user,需要接收一个名为id的参数表示用户的ID,我们希望对这个参数进行验证,判断其是否为正整数。代码示例如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping
    public String getUser(@RequestParam("id") @Positive(message = "用户ID必须为正整数") Integer id) {
        // 处理获取用户请求
        return "用户信息";
    }
}

在上面的代码中,我们使用@RequestParam注解来接收请求参数id,并在其上面添加@Positive注解,表示要求id必须为正整数,如果传入的不是正整数则抛出异常并返回错误消息。


问5: 再来一个

答5:

好的,接下来是一个使用@PathVariable注解进行验证的示例。假设我们的接口路径为/user/{id},需要接收一个名为id的路径参数表示用户的ID,我们希望对这个参数进行验证,判断其是否为正整数。代码示例如下:

@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/{id}")
    public String getUser(@PathVariable("id") @Positive(message = "用户ID必须为正整数") Integer id) {
        // 处理获取用户请求
        return "用户信息";
    }
}

在上面的代码中,我们使用@PathVariable注解来接收路径参数id,并在其上面添加@Positive注解,表示要求id必须为正整数,如果传入的不是正整数则抛出异常并返回错误消息。


问6: 继续

答6:

好的,下面再介绍一个针对对象属性进行验证的示例。假设我们有一个User类,其中包含一个包含电话号码和邮箱的Contact类,我们需要对电话号码和邮箱进行验证,判断其是否符合规范。代码示例如下:

public class Contact {
    @Pattern(regexp = "1\\d{10}", message = "手机号码格式不正确")
    private String phoneNumber;

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

    // getter和setter方法
}

public class User {
    @NotNull(message = "用户名不能为空")
    private String username;

    @NotNull(message = "联系方式不能为空")
    @Valid
    private Contact contact;

    // getter和setter方法
}

在上面的代码中,我们在Contact类的phoneNumber字段上使用@Pattern注解来验证手机号码格式是否正确,在email字段上使用@Email注解来验证邮箱地址格式是否正确。在User类中,我们使用@Valid注解来表示要对contact对象进行验证。现在我们来看如何使用这些注解进行验证:

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping
    public String createUser(@RequestBody @Valid User user) {
        // 处理新增用户请求
        return "新增用户成功";
    }
}

在上面的代码中,我们在@RequestBody注解上添加@Valid注解,可以使得Spring对传入的用户对象进行验证,并在验证失败时抛出异常并返回错误消息。在实际业务场景中,我们可以在控制层捕获这个异常,然后将错误信息返回给调用方。


问7: @Validated都可以放在什么地方?

答7:

@Validated 是 Spring 框架提供的一个参数校验注解,它与@Valid相比,支持更多的参数校验场景(例如分组校验等)。@Validated可以使用在类、方法参数和参数内部的字段、getter方法、setter方法上。

具体来说,@Validated可以放置在以下几个位置:

  1. 作用于Controller层类上

    @RestController
    @RequestMapping("/user")
    @Validated
    public class UserController { 
        ...
    }
    
  2. 作用于Controller层的方法上

    @RestController
    @RequestMapping("/user")
    public class UserController { 
    
        @PostMapping
        public User createUser(
            @RequestBody @Validated User user) { 
            ...
        }
    }
    
  3. 作用于方法参数上

    @RestController
    @RequestMapping("/user")
    public class UserController { 
    
        @GetMapping("/{id}")
        public User getUser(
            @PathVariable Integer id,
            @NotBlank(message = "用户名不能为空") String username) { 
            ...
        }
    }
    
  4. 作用于方法参数内部的字段上

    @RestController
    @RequestMapping("/user")
    public class UserController { 
    
        @GetMapping("/{id}")
        public User getUser(
            @PathVariable Integer id,
            @Validated(User.UserUpdate.class) UserUpdateForm form) { 
            ...
        }
    
        public static class UserUpdateForm {
            @NotBlank(message = "用户名不能为空", groups = {User.UserUpdate.class})
            private String username;
            ...
        }
    }
    
  5. 作用于方法参数内部的getter方法和setter方法上

    @RestController
    @RequestMapping("/user")
    public class UserController { 
    
        @PostMapping("/{id}")
        public User updateUser(
            @PathVariable Integer id,
            @Validated(User.UserUpdate.class) UserUpdateForm form) { 
            ...
        }
    
        public static class UserUpdateForm {
            private String username;
            ...
    
            @NotBlank(message = "用户名不能为空", groups = {User.UserUpdate.class})
            public String getUsername() {
               return username;
            }
            
            public void setUsername(String username) {
               this.username = username;
            }
        }
    }
    

需要注意的是,使用@Validated注解进行参数校验时需要在Spring配置文件开启对它的支持。可以通过在Spring Boot应用的配置类上添加@EnableValidated注解开启支持,也可以手动配置LocalValidatorFactoryBean和MethodValidationPostProcessor。


问8: 请总结一下@Validated

答8:

@Validated是Spring框架提供的一种参数校验注解,可以用于对Controller层中的方法参数进行校验。与@Valid相比,@Validated支持更多的参数校验场景,例如分组校验、级联校验等。

@Validated注解可以放置在类、方法参数和参数内部的字段、getter方法、setter方法上,具体用法如下:

  • 作用于Controller层类上
  • 作用于Controller层的方法上
  • 作用于方法参数上
  • 作用于方法参数内部的字段上
  • 作用于方法参数内部的getter方法和setter方法上

需要注意的是,在使用@Validated注解进行参数校验时,需要先开启Spring对其的支持。

总的来说,@Validated注解是Spring框架提供的一个方便而且功能强大的参数校验工具,能够帮助我们在程序开发中更方便地进行参数校验。