zoukankan      html  css  js  c++  java
  • JSR303的使用

    1、JSR303是什么?

    JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指 :向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。

    任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。

    JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现 . Hibernate Validator 提供了 JSR 303

    规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint

    image


    2、JSR303如何使用?

    1)给bean添加校验注解 :javax.validation.constraints

    @Data
    @TableName("pms_brand")
    public class BrandEntity implements Serializable {
       private static final long serialVersionUID = 1L;
    
       @TableId
       private Long brandId;
    
       @NotBlank(message = "品牌名称不能为空")
       private String name;
    
       @URL(message = "logo必须是一个合法的url")
       private String logo;
    
       private String descript;
    
       private Integer showStatus;
       //自定义校验规则
       @Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
       private String firstLetter;
    
       private Integer sort;
    
    }


    2)在congtroller总开启校验 @Valid

    @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand){
    brandService.save(brand);
          return R.ok();
      }


    校验错误后会有默认的响应

    clipboard


    3)如果不想要默认的响应,希望自己自定义校验异常返回的结果

    给校验后的bean后面紧跟一个BindingResult就可以获取到校验的结果

    @RequestMapping("/save")
      public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
          if(result.hasErrors()){
              Map<String,String> map = new HashMap<>();
              //1、获取校验的错误结果
              result.getFieldErrors().forEach((item) -> {
                  //获取到错误提示
                  String message = item.getDefaultMessage();
                  //获取错误属性的名字
                  String field = item.getField();
                  map.put(field,message);
              });
              return R.error(400,"提交的数据不合法").put("data", map);
          }
    
          brandService.save(brand);
          return R.ok();
      }

    clipboard


    4)如果每个controller都需要写这种封装数据校验异常的代码,会造成代码冗余

    此时需要进行统一异常处理,并将controller方法中的BindingResult去掉,任由其抛出异常

    @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand){
    brandService.save(brand);
          return R.ok();
    }

    添加controller统一异常处理器

    @Slf4j
    @RestControllerAdvice
    public class GulimallExceptionControllerAdvice {
    
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public R handleValidException(MethodArgumentNotValidException e){
            log.error("数据校验异常{},异常类型{}",e.getMessage(),e.getClass());
            BindingResult bindingResult = e.getBindingResult();
            HashMap<String, String> map = new HashMap<>();
            bindingResult.getFieldErrors().forEach((fieldError) -> {
                map.put(fieldError.getField(),fieldError.getDefaultMessage());
            } );
            return R.error(400,"数据校验错误").put("data",map);
        }
    }

    发送postman请求可以看到,返回的格式是我们自己封装的response格式:

    clipboard


    3、分组校验:

    给校验注解标注什么时候需要校验

    试想一下,新增和更新时,对实体的不同字段的校验是不同的,例如在新增时主键必须为空,但是修改时,主键必须不为空,此时就必须要用到分组

    校验


    1)声明分组,实际上是接口

    clipboard


    2)实体属性校验上添加分组

    注意:默认没有指定分组的校验注解,在分组校验的情况下不生效

    @Data
    @TableName("pms_brand")
    public class BrandEntity implements Serializable {
       private static final long serialVersionUID = 1L;
    
       @NotNull(message = "修改必须携带品牌id",groups = {UpdateGroup.class})
       @Null(message = "新增不能携带品牌id",groups = {AddGroup.class})
       @TableId
       private Long brandId;
    
       @NotBlank(message = "品牌名称不能为空",groups = {AddGroup.class,UpdateGroup.class})
       private String name;
    
       @NotBlank(message = "logo地址不能为空",groups = {AddGroup.class})
       @URL(message = "logo必须是一个合法的url",groups = {AddGroup.class,UpdateGroup.class})
       private String logo;
    
       private String descript;
    
       private Integer showStatus;
    
       @Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是一个字母")
       private String firstLetter;
    
       private Integer sort;
    
    }


    3)controller中添加 @Validated({AddGroup.class})

    指定需要校验的分组

    @RequestMapping("/save")
      public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
    brandService.save(brand);
          return R.ok();
      }


    4)测试

    clipboard


    4、自定义校验注解

    1)编写一个自定义的校验注解

    找到  @NotNull注解,将其上的元注解copy下来

    @Documented
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ListValue {
    
        String message() default "{com.atguigu.common.valid.ListValue.message}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        int[] vals() default {};
    }


    2)编写一个自定义的校验器

    public class ListValueContraintValidator implements ConstraintValidator<ListValue, Integer> {
    
        private Set<Integer> set = new HashSet<>();
    
        //初始化方法
        @Override
        public void initialize(ListValue constraintAnnotation) {
            int[] vals = constraintAnnotation.vals();
            for(int val : vals){
                set.add(val);
            }
        }
    
        //判断校验是否成功  value=> controller接收的值 == 等待被校验的值
        @Override
        public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
            return set.contains(value);
        }
    }


    3)将校验器和注解绑定

    @Documented
    //表明本校验注解 使用ListValueContraintValidator校验器
    @Constraint(validatedBy = {ListValueContraintValidator.class})
    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ListValue {
    
        String message() default "{com.atguigu.common.valid.ListValue.message}";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        int[] vals() default {};
    }


    4)在实体类上使用该校验注解

    @ListValue(vals = {0,1},groups = AddGroup.class)   的意思时,新增时校验showStatus,且showStatus必须是 0 / 1

    @ListValue(vals = {0,1},groups = AddGroup.class) //当新增时携带了showStatus字段
    private Integer showStatus;


    5)测试

    clipboard

  • 相关阅读:
    将图片制作数据拒
    python中PIL.Image,OpenCV,Numpy图像格式相互转换
    9、【Hive】初始化元数据库时失败,遇到org.apache.hadoop.hive.metastore.HiveMetaException: Schema initialization FAILED! Metastore state would be inconsistent
    8、【Hive Mysql】MySQL8 提示Public Key Retrieval is not allowed错误解决方法
    7.【Hive】hive启动出现权限错误 /tmp/hive on HDFS should be writable
    一、Zookeeper简明笔记
    6、System times on machines may be out of sync. Check system time and time zones
    5、利用搭建的hadoop集群计算wordcount时出现内存问题
    4、利用hadoop自带的mr 示例测试运行任务失败: Could not find or load main class org.apache.hadoop.mapreduce.v2.app.MRAppMaster
    3、hadoop运行jar包报错 : "/bin/bash: /bin/java: No such file or directory"
  • 原文地址:https://www.cnblogs.com/houchen/p/15317905.html
Copyright © 2011-2022 走看看