zoukankan      html  css  js  c++  java
  • JSR-303 实现参数校验

    参考:https://blog.csdn.net/qq_45076180/article/details/106219684
    参考:https://zhuanlan.zhihu.com/p/97555913
    参考:https://blog.csdn.net/u013934408/article/details/108872775
    参考:https://blog.csdn.net/adparking/article/details/112918333

    公众号文章:https://mp.weixin.qq.com/s/VNrs1zGPgx9GsIqXEDZP0Q

    1. 什么是JSR-303

    JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。

    它是一个hibernete独立的jar包,所以使用这个jar包并不需要一定要集成Hibernete框架。

    JSR-303 用于对 Java Bean 中的字段的值进行验证。

    Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。

    JSR-303官网



    2. JSR-303内置校验规则





    3. SpringBoot整合JSR-303

    3.1 导入依赖

    <dependency> 
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    

    3.2 在类的属性上加上相应校验注解

    @NotNull(message="名字不能为空")
    private String userName;
    
    @Max(value=120,message="年龄最大不能查过120")
    private int age;
    
    @Email(message="邮箱格式错误")
    private String email;
    

    3.3 实现校验

    在Controller的处理方法的参数前,加@Validated注解,出错后,错误信息会放置在 Errors或BindingResult 的对象参数中

    @RequestMapping("/login")
    public String testValid(@Validated User user, BindingResult result){
        if (result.hasErrors()){
             List<ObjectError> errorList = result.getAllErrors();
             for(ObjectError error : errorList){
             System.out.println(error.getDefaultMessage());
          }
        }           
      return "test";
    }
    

    3.4 通过全局统一异常替换BindingResult写法

    3.3那种做法给controller后的需要校验的bean后加一个BindingResult类就可以获得校验的结果,但是相对麻烦,每次都要写BindingResult。在大项目中一般使用统一异常处理校验结果,返回json格式,如下所示。这样就不需要在controller加一个BindingResult类。

    //后端校验异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public  RtnResult handValidException(MethodArgumentNotValidException e){
    	BindingResult bindingResult = e.getBindingResult();
    	Map<String, Object> map = new HashMap<>();
    	bindingResult.getFieldErrors().forEach(fieldError -> {
    		map.put(fieldError.getField(),fieldError.getDefaultMessage());
    	});
    	return RtnResult.fail(map);
    }
    








    3.5 分组校验(多场景的复杂校验)

    分组校验应用场景:添加和更新需要不同的校验规则时,且你更新和添加用的实体都是同一个时。有些项目会要求必须新增实体是一个,更新实体是一个,那么这种情况下就不考虑这种。

    3.5.1 先在你的实体上创建添加和更新的接口,该接口仅仅是多场景的一个标识,接口内容为空即可。
    public interface AddGroup {
    }
    
    public interface UpdateGroup {
    }
    
    3.5.2 在 @NotBlank(message = “密码不能为空”) 后加上groups 用于表示给校验注解标注什么情况下需要校验(添加/更新)
    //AddGroup.class是添加的标识组,可以有多个
    @NotBlank(message = "密码不能为空", groups = {AddGroup.class})
    private String password;
    
    @NotBlank(message = "姓名不能为空", groups = {AddGroup.class,UpdateGroup.class})
    private String name;
    
    3.5.3 必须使用@Validated注解制定只是用哪个操作,否则不生效。
    //添加用户   @Validated指定哪个操作使用校验
    @PostMapping("/addUser")
    public RtnResult addUser(@Validated(AddGroup.class) @RequestBody ClaimUser claimUser){
         return  claimUserService.addUser(claimUser);
    }
    
    如果使用分组校验,校验注解没有使用groups,则校验不生效,一定要使用groups!!
    


    4. 自定义校验注解

    当给出的校验规则不能满足需求,可以通过自定义校验来实现,如某个字段只能为0或1。
    举例场景:当显示和隐藏的属性showStatus只能时0或1,需要自定义校验注解和自定义校验器

    4.1 导入依赖

    <dependency>
         <groupId>javax.validation</groupId>
         <artifactId>validation-api</artifactId>
         <version>2.0.1.Final</version>
    </dependency>
    

    4.2 编写自定义校验注解

    PS:可以参考JSR-303原本的校验

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
    @Retention(RUNTIME)   //运行环境
    @Repeatable(List.class)
    @Documented
    @Constraint(validatedBy = { })  // 指定自定义校验器,可以适配多个校验器,一个注解完成多种校验
    public @interface NotNull {
          String message() default "{javax.validation.constraints.NotNull.message}"; // 校验失败的提示信息
          Class<?>[] groups() default { };
          Class<? extends Payload>[] payload() default { };
          int[]  vals() default {};  //标注在属性上的vals={0,1}
            
    }
    

    4.3 编写自定义校验注解

    //自定义校验器 必须实现ConstraintValidator
    //ConstraintValidator中的 泛型1:绑定的泛型注解   泛型2:校验的数据类型
    public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
    
        private Set<Integer> set = new HashSet<>();
    
        //初始化方法,获取在Entity类的属性上标注的符合条件的Integer的值:{0,1}
        @Override
        public void initialize(ListValue constraintAnnotation) {
            int[] vals = constraintAnnotation.vals();
            for (int val : vals) {
                set.add(val);
            }
        }
    
        //判断是否校验成功方法
        //integer:传进来的值
        //判断依据:看integer是否在初始化方法的数组中
        @Override
        public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
            if (set.contains(integer)) {
                return true;
            }
            return false;
        }
    }
    

    4.4 在需要校验的属性上添加自定义注解

    @ListValue(vals={0,1},message = "开关状态只能是0或1")
    private Integer showStatus;
    

    4.5 自定义参数校验(这边以校验手机号为例)

    1. 编写注解类
    //说明该注解将被包含在javadoc中
    @Documented
    // 注解的作用目标 类上、方法上、属性上
    @Target({ElementType.FIELD, ElementType.PARAMETER})
    // 注解的保留位置  
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = {IsMobileValidator.class }) // 与约束注解关联的验证器
    public @interface IsMobile {
    
        boolean required() default true;
    
        String message() default "手机号不正确";
    
        Class<?>[] groups() default { };
    
        Class<? extends Payload>[] payload() default { };
    
    }
    
    1. 编写校验规则
    public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
        private boolean required;
    
        /**
         * 重写initialize方法获取注解实例
         * @param ca
         */
        @Override
        public void initialize(IsMobile ca) {
            // 重注解实例中获信息
            required = ca.required();
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            // value就是要校验的数据了
            if (value != null && required) {
                // 手机号校验规则
                System.out.println(value);
                String regexp= "^(((\+\d{2}-)?0\d{2,3}-\d{7,8})|((\+\d{2}-)?(\d{2,3}-)?([1][3,4,5,7,8][0-9]\d{8})))$";
                boolean matches = Pattern.matches(regexp, value);
                System.out.println(matches);
                return matches;
            }
            return false;
        }
    }
    
    1. 使用自定义校验注解
        /**
         * 手机号
         */
        @IsMobile(message = "用户手机号不正确")
        private String tel;
    
  • 相关阅读:
    20201216-1 文件读与写详解3
    20201214-4 文件读与写详解2
    20201214-3 文件读与写详解1
    20201214 集合及其运算
    3月17日:毕业设计计划
    3月16日:毕业设计计划
    3月15日:毕业设计计划
    3月14日:毕业设计计划
    3月13日:毕业设计计划
    3月12日:毕业设计计划
  • 原文地址:https://www.cnblogs.com/itlihao/p/14280903.html
Copyright © 2011-2022 走看看