spring中使用@Validated,什么是JSR 303数据校验,spring boot中怎么使用数 ...

打印 上一主题 下一主题

主题 833|帖子 833|积分 2499

一、JSR 303背景数据校验

1.1 什么是 JSR303?

JSR 是 Java Specification Requests 的缩写,即 Java 规范提案。存在各种各样的 JSR,简单的理解为 JSR 是一种 Java 标准。JSR 303 是其中数据查验的一个标准(Bean Validation 1.0 (JSR 303))。
1.2 为什么使用 JSR 303?



  • 处置惩罚一段业务逻辑,起首要确保数据输入的精确性,所以必要先对数据进行检查,包管数据在语义上的精确性,再根据数据进行下一步的处置惩罚。
  • 前端可以通过 js 步伐校验数据是否合法,后端同样也必要进行校验。而后端最简单的实现就是直接在业务方法中对数据进行处置惩罚,但是差别的业务方法大概会出现同样的校验操作,这样就出现了数据的冗余。
  • 为了解决这个情况,JSR 303 出现了。JSR 303 使用 Bean Validation,即在 Bean 上添加相应的注解,去实现数据校验。这样在实行业务方法前,都会根据注解对数据进行校验,从而减少自定义的校验逻辑,减少代码冗余。
二、Spring Boot 中使用数据校验

2.1 基本注解校验

   之前在 Spring MVC 中介绍了数据校验,也例举了常用的注解。但是使注解收效必须要在 springmvc.xml 中设置,假如没有设置文件(好比在 spring boot)中怎么办?----> 下面详细介绍
  spring boot 中必要引入依赖:
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-validation</artifactId>
  4. </dependency>
复制代码
2.1.1 使用步调

1、在相干的 Bean 上标注必要处置惩罚的注解,并指定必要提示的信息(若不指定,会从默认设置文件中读取默认的信息)。
2、在相干的方法上,使用 @Valid 注解(大概 @Validated 指定组名)标记必要被校验的数据,否则会不收效。
注意:检测到数据非常后,系统会向外抛出非常,如果做了统一非常处置惩罚,可以根据 postman 测试的结果,找到控制台打印出的相应的非常,并处置惩罚。
3、处置惩罚非常。


  • 使用 BindingResult 处置惩罚;
  • 也可以使用 全局统一非常 处置惩罚(@RestControllerAdvice 与 @ExceptionHandler
           全局统一非常处置惩罚后续会讲
2.1.2 举例

1、在相干的 Bean 上标注注解,并写上指定信息。
  1. @Data
  2. public class Emp {
  3.     @NotNull(message = "id 不能为 null")
  4.     private Integer id;
  5.     @NotNull(message = "name 不能为 null")
  6.     private String name;
  7. }
复制代码
@Valid注解

2、Controller层中使用 @Valid 注解标记必要检测的数据。
  1. @RestController
  2. public class EmpController {
  3.    
  4.     @PostMapping("/emp")
  5.     public String createEmp(@Valid @RequestBody Emp emp) {
  6.        return "ok";
  7.     }
  8. }
复制代码
3、测试时,假如不传 id、name,会抛出 MethodArgumentNotValidException 非常。使用 BindingResult 可以处置惩罚非常信息,但 通常使用统一非常处置惩罚
① 使用 BindingResult:
  1. @RestController
  2. public class EmpController {
  3.     @PostMapping("/emp")
  4.     public Map createEmp(@Valid @RequestBody Emp emp, BindingResult result) {
  5.         if (result.hasErrors()) {
  6.             Map<String, String> map = new HashMap<>();
  7.             // 获取校验结果,遍历获取捕获到的每个校验结果
  8.             result.getFieldErrors().forEach(item -> {
  9.                 // 获取校验的信息
  10.                 String message = item.getDefaultMessage(); // 也获取message的值
  11.                 String field = item.getField(); //获取属性名
  12.                 // 存储得到的校验结果
  13.                 map.put(field, message);
  14.             });
  15.             return map;
  16.         }
  17.         return "ok";
  18.     }
  19. }
复制代码
题目:通过上面的步调,已经可以捕获非常、处置惩罚非常,但是每次都是在业务方法中手动处置惩罚逻辑,这样的实现,代码肯定会冗余。可以将其抽出,使用 统一非常处置惩罚,每次非常发生时,将其捕获。
全局统一非常处置惩罚

② 全局统一非常处置惩罚:@RestControllerAdvice、@ExceptionHandler
  1. @RestControllerAdvice
  2. public class GlobalExceptionHandler {
  3.    
  4.     @ExceptionHandler(MethodArgumentNotValidException.class)
  5.     public Map handlerValidException(MethodArgumentNotValidException e) {
  6.         BindingResult result = e.getBindingResult();
  7.         Map<String, String> map = new HashMap<>();
  8.         // 获取校验结果,遍历获取捕获到的每个校验结果
  9.         result.getFieldErrors().forEach(item ->{
  10.             // 存储得到的校验结果
  11.             map.put(item.getField(), item.getDefaultMessage());
  12.         });
  13.         return map;
  14.     }
  15. }
复制代码
Controller 中不必要再用 BindingResult 去处置惩罚数据了。
2.2 分组校验

1、为什么使用 分组校验?
上面的过程,如果出现多个方法,都必要校验 Bean,且校验规则差别的时候,怎么办呢?分组校验就可以去解决该题目,每个分组指定差别的校验规则,差别的方法实行差别的分组,就可以得到差别的校验结果。
2、JSR 303 的每个注解都默认具备三个属性


  • message 用来定义数据校验失败后的提示消息,默认读取设置文件的内容。idea 全局搜索 ValidationMessages.properties,可以看到默认的信息。
  • groups 用来定义分组,它是一个 class 数组,可以指定多个分组。
  • payload()
  1. String message() default "{javax.validation.constraints.NotNull.message}";
  2. Class<?>[] groups() default { };
  3. Class<? extends Payload>[] payload() default { };
复制代码
2.2.1 使用步调

1、定义一个空接口,用于指定分组,内部不必要任何实现。
2、指定 注解时,通过 groups 指定分组。用于指定在某个分组条件下,才去实行校验规则。
3、在 Controller 中通过 @Validated 注解指定分组,去指定校验。
注:使用分组校验后,Bean 注解上若不指定分组,则不会实行校验规则。
2.2.2 举例

1、如:创建两个分组接口 AddGroup、UpdateGroup。
   AddGroup 用于指定 添加数据 时的校验规则(好比:id、name 均不为 null)。
  UpdateGroup 用于指定 修改数据 时的校验规则(好比:name 不允许为 null)。
  2、给 Bean 添加注解,并指定分组信息。
  1. @Data
  2. public class Emp {
  3.   
  4.     @NotNull(message = "id 不能为 null", groups = {AddGroup.class})
  5.     private Integer id;
  6.     @NotNull(message = "name 不能为 null", groups = {AddGroup.class, UpdateGroup.class})
  7.     private String name;
  8. }
复制代码
@Validated注解

3、通过 @Validated 注解指定分组,去指定校验
  1. @RestController
  2. public class EmpController {
  3.     @PostMapping("/emp")
  4.     public void createEmp(@Validated({AddGroup.class}) @RequestBody Emp emp) {
  5.       
  6.     }
  7.     @PutMapping("/emp")
  8.     public void UpdateEmp(@Validated({UpdateGroup.class}) @RequestBody Emp emp) {
  9.       
  10.     }
  11. }
复制代码
@Validated和@Valid的区别



  • @Validated:

    • Spring 框架特有的注解,是标准 JSR-303 的一个变种,提供了一个分组功能。
    • 作用在类上、方法上、方法参数上,不能作用于成员属性上。

  • @Valid:

    • 标准 JSR-303 规范的标记型注解。
    • 作用在方法、构造函数、方法参数、成员属性上。

2.3 自定义校验注解

上面的注解满意不了业务需求时,可以自定义校验注解、然后自定义校验规则
2.3.1 使用步调

1、自定义一个校验注解。可以创建一个 ValidationMessages.properties 用于保存默认的 message 信息。
2、自定义一个校验器(即自定义校验规则):实现 ConstraintValidator 接口,并重写相干方法。


  • initialize :初始化,可以获取 自定义的属性的值。
  • isValid :校验,可以获取到现实的值,然后与自定义的属性值进行比较。
3、将校验注解 与 校验器 关联起来。@Constraint(validatedBy = {校验器类.class})
2.3.2 举例

自定义一个校验规则,判断数据长度是否合法。
1、自定义一个校验注解:(好比这里是@TestValid)
  1. @Target({FIELD})
  2. @Retention(RUNTIME)
  3. @Documented
  4. @Constraint(validatedBy={JiaoYan.class})
  5. public @interface TestValid {
  6.     // 提示信息
  7.     String message() default "{本自定义注解的全类名.message}";
  8.           
  9.     class<?>[] groups() default {};
  10.    
  11.     Class<? extends Payload>[] payload() default {};
  12.    
  13.     /**
  14.      * 返回一个长度
  15.      * @return 默认为 5
  16.      */
  17.     int length() default 5;
  18. }
复制代码

设置文件内容为:
  1. 自定义注解的全类名.message=值不能为 Null,且长度不超过 5
复制代码
2、自定义一个校验器(好比这里是 JiaoYan)
  1. /**
  2. * 实现 ConstraintValidator 接口,
  3. * 其中 ConstraintValidator 的泛型,一个需要指定自定义的注解,一个需要指定需要获取的值的类型。
  4. * 比如:
  5. *  ConstraintValidator<TestValid, String> 中
  6. *      TestValid   表示自定义注解
  7. *      String      表示获取的值的类型
  8. * 即定义规则,判断一个 String 的值的长度是否满足条件
  9. */
  10. public class JiaoYan implements ConstraintValidator<TestValid, String> {
  11.     /**
  12.      * 用于保存自定义的(默认)长度
  13.      */
  14.     private int length;
  15.    
  16.     /**
  17.      * 初始化方法,获取默认数据
  18.      * @param test 注解对象
  19.      */
  20.     @Override
  21.     public void initialize(TestValid test) {
  22.         length = test.length();
  23.     }
  24.    
  25.     /**
  26.      * 自定义校验规则,如果 String 为 Null 或者 长度大于 5,则校验失败(返回 false)
  27.      * @param value 需要校验的值
  28.      * @param context
  29.      * @return true 表示校验成功,false 表示校验失败
  30.      */
  31.     @Override
  32.     public boolean isValid(String value, ConstraintValidatorContext context) {
  33.         return value == null ? false : length > value.length();
  34.     }
  35. }
复制代码
3、使用注解
  1. @Data
  2. public class Emp {
  3.    
  4.     @NotNull(message = "id 不能为 null", groups = {AddGroup.class})
  5.     private Integer id;
  6.    
  7.     // 默认
  8.     @TestValid()
  9.     @NotNull(message = "name 不能为 null", groups = {AddGroup.class, UpdateGroup.class})
  10.     private String name;
  11.     // 自定义
  12.     @TestValid(length = 10, message = "值不能为 Null 且长度不超过 10", groups = {AddGroup.class})
  13.     private String email;
  14. }
复制代码
2.4 相干注解

2.4.1 空检查相干注解

注解注解详情@Null被指定的注解元素必须为 Null@NotNull任意类型,不能为 Null,但可以为空,好比:空数组[]、空字符串""@NotBlank针对字符串,不能为 Null,且去除前后空格后的字符串长度要大于 0@NotEmpty针对字符串、聚集、数组,针对字符串时,不能为 Null,且长度要大于 0 2.4.2 长度检查

注解注解详情@Size针对字符串、聚集、数组,判断长度是否在给定范围内@Length针对字符串,判断长度是否在给定范围内 2.4.3 布尔值检查

注解注解详情@AssertTrue针对布尔值,用来判断布尔值是否为 true@AssertFalse针对布尔值,用来判断布尔值是否为 false 2.4.4 日期检查

注解注解详情@Past针对日期,用来判断当前日期是否为 过去的日期@Future针对日期,用来判断当前日期是否为 未来的日期 2.4.5 数值检查

注解注解详情@Max(value)针对字符串、数值,用来判断是否小于等于某个指定值@Min(value)针对字符串、数值,用来判断是否大于等于某个指定值 2.4.6 其他

注解注解详情@Pattern验证字符串是否满意正则表达式@Email验证字符串是否满意邮件格式@Url验证是否满意 url 格式@Digits验证数字整数和小数位数,如:@Digits(integer=6, fraction=2)   文章竣事!恭喜你又学会了一个知识点!!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

玛卡巴卡的卡巴卡玛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表