zoukankan      html  css  js  c++  java
  • JSR303后端校验详细笔记

    JSR303

    使用步骤

    1.依赖

     <!--数据校验-->
     <dependency>
         <groupId>javax.validation</groupId>
         <artifactId>validation-api</artifactId>
         <version>2.0.1.Final</version>
     </dependency>
    

    2.在entity类的属性上添加注解

    3.开启校验功能:在controller类的方法的参数上加上@Valid属性

    4.校验失败的处理:

    • 第一种:单独处理
    public R save(@Valid @RequestBody BrandEntity brand,BindingResult result){
            if(result.hasErrors()){
                Map<String,String> map = new HashMap<>();
                //1、获取校验的错误结果
                result.getFieldErrors().forEach((item)->{
                    //FieldError 获取到错误提示
                    String message = item.getDefaultMessage();
                    //获取错误的属性的名字
                    String field = item.getField();
                    map.put(field,message);
                });
                return R.error(400,"提交的数据不合法").put("data",map);
            }else {
    			brandService.save(brand);
            }
            return R.ok();
        }
    
    • 第二种,抛出异常后统一处理
    1. 定义@RestControllerAdvice处理请求异常类
    2. @ExceptionHandler(value= xxx.class)注解根据异常类型标注在方法上,编写处理逻辑
    @Slf4j
    @RestControllerAdvice
    public class ExceptionControllerAdvice {
    
        @ExceptionHandler(value= MethodArgumentNotValidException.class)
        public R handleValidException(MethodArgumentNotValidException e){
            log.error("数据校验出现问题{},异常类型:{}",e.getMessage(),e.getClass());
            BindingResult bindingResult = e.getBindingResult();
            Map<String,String> errorMap = new HashMap<>();
            bindingResult.getFieldErrors().forEach((error)->{
                //存储校验字段名,以及校验字段失败提示
                errorMap.put(error.getField(),error.getDefaultMessage());
            });
            return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",errorMap);
        }
    
        @ExceptionHandler(value = Throwable.class)
        public R handleException(Throwable throwable){
    
            log.error("错误:",throwable);
            return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
        }
    }
    
    1. 定义异常枚举类
    public enum BizCodeEnume {
        UNKNOW_EXCEPTION(10000,"系统未知异常"),
        VAILD_EXCEPTION(10001,"参数格式校验失败");
        private int code;
        private String msg;
        BizCodeEnume(int code,String msg){
            this.code = code;
            this.msg = msg;
        }
    
        public int getCode() {
            return code;
        }
    
        public String getMsg() {
            return msg;
        }
    }
    
    

    关于不为空

    1. @NotNull

      只要不为空,校验任意类型

      The annotated element must not be {@code null}.

      Accepts any type.

    2. @NotBlank

      至少有一个非空字符,校验字符

      The annotated element must not be {@code null} and must contain at least one

      non-whitespace character. Accepts {@code CharSequence}.

    3. @NotEmpty

      非空,也不能内容为空,校验字符,集合,数组

      The annotated element must not be {@code null} nor empty. Supported types are:

      {@code CharSequence} (length of character sequence is evaluated)

      {@code Collection} (collection size is evaluated)

      {@code Map} (map size is evaluated)

      Array (array length is evaluated)

    分组校验

    步骤:

    1. 在校验注解上加上groups = {xxx.class, ...}属性,值可以是任意interface接口,例如

      @URL(message = "logo必须是一个合法的url地址",groups={AddGroup.class,UpdateGroup.class})

    2. 在开启校验处,将@Valid注解改为@Validated({xxx.class}),例如@Validated({AddGroup.class})就表示只校验该组的属性;

      注意:未添加任何分组的校验将会无效,开启娇艳的时候i如果添加了分组信息,那么只会校验同样页添加了该分组的属性。

    自定义校验

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

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

    2)、编写配置文件ValidationMessages.properties,给自定义的校验配置校验失败的信息

    com.lx.common.valid.ListValue.message=显示状态只能为1或0
    

    3)、编写一个自定义的校验器 ConstraintValidator

    ​ 实现ConstraintValidator接口,第一个参数为绑定的校验注解名,第二个参数为校验的属性类型,完成初始化与判断方法。

    public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
    
        private Set<Integer> set = new HashSet<>();
        /**
         * @Description: 根据注解中的属性初始化
         * @Param0: constraintAnnotation
         **/
        @Override
        public void initialize(ListValue constraintAnnotation) {
            int[] vals = constraintAnnotation.vals();
            for (int val:vals) {
                set.add(val);
            }
        }
    
        /**
         * @Description: 判断校验是否成功
         * @Param0: value 被校验值
         * @Param1: context
         **/
        @Override
        public boolean isValid(Integer value, ConstraintValidatorContext context) {
            return set.contains(value);
        }
    }
    

    4)、关联自定义的校验器和自定义的校验注解

    @Constraint(validatedBy = { ListValueConstraintValidator.class })
    

    5)、使用

    @NotNull(groups = {AddGroup.class, UpdateGroup.class})
    @ListValue(vals = {0,1},groups = {AddGroup.class,UpdateGroup.class})
    private Integer showStatus;
    

    完整代码

    controller

    /**
     * 保存
     */
    @RequestMapping("/save")
    public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
        brandService.save(brand);
    
        return R.ok();
    }
    
    /**
     * 修改
     */
    @RequestMapping("/update")
    public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand){
        brandService.updateById(brand);
    
        return R.ok();
    }
    

    entity

    @Data
    @TableName("pms_brand")
    public class BrandEntity implements Serializable {
    	private static final long serialVersionUID = 1L;
    
    	/**
    	 * 品牌id
    	 */
    	@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;
    	/**
    	 * 品牌logo地址
    	 */
    	@URL(message = "logo必须是一个合法的url地址",groups={AddGroup.class,UpdateGroup.class})
    	private String logo;
    	/**
    	 * 介绍
    	 */
    	private String descript;
    	/**
    	 * 显示状态[0-不显示;1-显示]
    	 */
    	@NotNull(groups = {AddGroup.class, UpdateGroup.class})
    	@ListValue(vals = {0,1},groups = {AddGroup.class,UpdateGroup.class})
    	private Integer showStatus;
    	/**
    	 * 检索首字母
    	 */
    	@NotEmpty(groups={AddGroup.class})
    	@Pattern(regexp="^[a-zA-Z]$",message = "检索首字母必须是一个字母",groups={AddGroup.class,UpdateGroup.class})
    	private String firstLetter;
    	/**
    	 * 排序
    	 */
    	@NotNull(groups={AddGroup.class})
    	@Min(value = 0,message = "排序必须大于等于0",groups={AddGroup.class,UpdateGroup.class})
    	private Integer sort;
    
    }
    
    

    测试1:

    image-20200520180447340

    测试2:

    image-20200520180816926

  • 相关阅读:
    福大软工1816 · 第三次作业
    福大软工1816 · 第二次作业
    2018福大软工第一次作业
    20180823-软工实践第一次作业-自我介绍
    福大软工1816 · 第一次作业
    开博之作 · 简单的自我介绍
    2018软件工程实践第一次作业
    系列最终篇!
    含继承多态思想的四则运算器和简单工厂模式初步
    作业六 栈的使用和界面编程探索
  • 原文地址:https://www.cnblogs.com/jklixin/p/12925234.html
Copyright © 2011-2022 走看看