• JSR303 校验扩展(分组、按顺序校验)


    1.在spring MVC 项目中使用JSR303 校验数据合法性,一般情况下使用方法为

    (1)在接受数据的实体使用注解标添加校验规则

      1 package com.hzsj.wechatdto;
      2 
      3 import org.hibernate.validator.constraints.Length;
      4 import org.hibernate.validator.constraints.NotBlank;
      5 
      6 public class MemberApplyDto {
      7     @NotBlank(message="注册号不能为空")
      8     @Length(max=6,min=6,message="注册号必须为6位")
      9     private String registerId;
     10     
     11     @NotBlank(message="姓名不能为空")
     12     @Length(max=50,message="长度不能超过50个字符")
     13     private String name;
     14 
     15     @NotBlank(message="选择性别")
     16     private String gender;
     17 
     18     @NotBlank(message="请填写身份证号码")
     19     @Length(max = 18,message="身份证号码不能超过18个字符")
     20     private String cardNo;
     21 
     22     @NotBlank(message="请选择省")
     23     private String province;
     24     
     25     @NotBlank(message="请选择市")
     26     private String cityName;
     27 
     28     @NotBlank(message="请选择县")
     29     private String countyName;
     30 
     31     @NotBlank(message="请填写详细地址")
     32     @Length(max=50,message="不能超过50个字符")
     33     private String detailAddress;
     34 
     35     @NotBlank(message="请选择婚姻状况")
     36     private String marriage;
     37 
     38     @NotBlank(message="请填写公司名称")
     39     @Length(max=30,message="公司名称不能超过30个字符")
     40     private String companyName;
     41 
     42     @NotBlank(message="请填写公司电话")
     43     @Length(max=20,message="公司电话不能超过20个字符")
     44     private String companyTel;
     45 
     46     @NotBlank(message="请填写公司地址")
     47     @Length(max=50,message="公司地址不能超过50个字符")
     48     private String companyAddress;
     49 
     50     @NotBlank(message="请填写个人简历")
     51     @Length(max=200,message="个人简历不能超过200字符")
     52     private String persomResume;
     53 
     54     @NotBlank(message="请选择渠道平台")
     55     private String channelType;
     56 
     57     @NotBlank(message="请填写保荐人")
     58     @Length(max=20,message="保荐人不能超过20个字符")
     59     private String recommend;
     60     
     61     @NotBlank(message="uuidCode不能为空")
     62     private String uuidCode;
     63     
     64 
     65     public String getRegisterId() {
     66         return registerId;
     67     }
     68 
     69     public void setRegisterId(String registerId) {
     70         this.registerId = registerId;
     71     }
     72 
     73     public String getName() {
     74         return name;
     75     }
     76 
     77     public void setName(String name) {
     78         this.name = name;
     79     }
     80 
     81     public String getGender() {
     82         return gender;
     83     }
     84 
     85     public void setGender(String gender) {
     86         this.gender = gender;
     87     }
     88 
     89     public String getCardNo() {
     90         return cardNo;
     91     }
     92 
     93     public void setCardNo(String cardNo) {
     94         this.cardNo = cardNo;
     95     }
     96 
     97     public String getProvince() {
     98         return province;
     99     }
    100 
    101     public void setProvince(String province) {
    102         this.province = province;
    103     }
    104 
    105     public String getCityName() {
    106         return cityName;
    107     }
    108 
    109     public void setCityName(String cityName) {
    110         this.cityName = cityName;
    111     }
    112 
    113     public String getCountyName() {
    114         return countyName;
    115     }
    116 
    117     public void setCountyName(String countyName) {
    118         this.countyName = countyName;
    119     }
    120 
    121     public String getDetailAddress() {
    122         return detailAddress;
    123     }
    124 
    125     public void setDetailAddress(String detailAddress) {
    126         this.detailAddress = detailAddress;
    127     }
    128 
    129     public String getMarriage() {
    130         return marriage;
    131     }
    132 
    133     public void setMarriage(String marriage) {
    134         this.marriage = marriage;
    135     }
    136 
    137     public String getCompanyName() {
    138         return companyName;
    139     }
    140 
    141     public void setCompanyName(String companyName) {
    142         this.companyName = companyName;
    143     }
    144 
    145     public String getCompanyTel() {
    146         return companyTel;
    147     }
    148 
    149     public void setCompanyTel(String companyTel) {
    150         this.companyTel = companyTel;
    151     }
    152 
    153     public String getCompanyAddress() {
    154         return companyAddress;
    155     }
    156 
    157     public void setCompanyAddress(String companyAddress) {
    158         this.companyAddress = companyAddress;
    159     }
    160 
    161     public String getPersomResume() {
    162         return persomResume;
    163     }
    164 
    165     public void setPersomResume(String persomResume) {
    166         this.persomResume = persomResume;
    167     }
    168 
    169     public String getChannelType() {
    170         return channelType;
    171     }
    172 
    173     public void setChannelType(String channelType) {
    174         this.channelType = channelType;
    175     }
    176 
    177     public String getRecommend() {
    178         return recommend;
    179     }
    180 
    181     public void setRecommend(String recommend) {
    182         this.recommend = recommend;
    183     }
    184 
    185     public String getUuidCode() {
    186         return uuidCode;
    187     }
    188 
    189     public void setUuidCode(String uuidCode) {
    190         this.uuidCode = uuidCode;
    191     }
    192 
    193     
    194 }

    (2)在Controller中使用BindResult 接收校验的结果

    @RequestMapping(value="/apply",method=RequestMethod.POST)
        @ResponseBody
        public ResultVo memberApply(@Valid MemberApplyDto dto,BindingResult bindingResult,Errors errors){
            ResultVo<Object> resultVo = new ResultVo<>();
            if(errors.hasErrors()){
                List<FieldError> errorsList = bindingResult.getFieldErrors();
                Map<String, String> map = new HashMap<>();
                for(FieldError fieldError:errorsList){
                    map.put(fieldError.getField(), fieldError.getDefaultMessage());
                }
                resultVo.setCode(StatusEnums.DATAVALID_ERROR.getCode());
                resultVo.setData(map);
                resultVo.setMsg(StatusEnums.DATAVALID_ERROR.getMsg());
                return resultVo;
            }
            LoginVo vo = memberApplyService.submitApply(dto);
            resultVo.setCode(StatusEnums.SUCCESS.getCode());
            resultVo.setMsg(StatusEnums.SUCCESS.getMsg());
            resultVo.setData(vo);
            return resultVo;
        }

    2.如果没有特殊需求的情况下使用上面的校验即可。但是遇到其他情况上面的校验就不能满足或者不能灵活应对了。例如

    (1)实体中的字段校验按照顺序进行,如果第一个字段校验失败,则接下来的校验不再进行。

    (2)实体的字段校验按情况分类,分组校验,再不同方法中校验的字段和顺序不同。

    (3)自定义校验规则。

    刚好今天遇到上面的三种情况,接下来用实例一一解答。针对上面的需求,JSR303校验中专门提供了group (验证规则所属组)和 @GroupSequence(验证组的顺序) 来实现。

    我的需求是表单中的字段按个按顺序校验,如果有前面的字段校验失败,则中断校验并返回校验结果。我的表单中有十几个字段,我的想法是为每个字段定义一个组,然后按照组的顺序进行校验(如果字段很多会比较麻烦,暂时不知道有什么更好的办法, 如果有人知道的话请指教。)于是上面的实体类就变成了下面的样子

    package com.hzsj.wechatdto;
    
    import java.io.Serializable;
    
    import org.hibernate.validator.constraints.Length;
    import org.hibernate.validator.constraints.NotBlank;
    
    import com.hzsj.common.util.annotation.IsUndefined;
    public class MemberApplyDto implements Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = -7063091764413674200L;
    
        @NotBlank(message="注册号不能为空",groups={Default.class})
        @Length(max=6,min=6,message="注册号必须为6位",groups={Default.class})
        private String registerId;
        
        @NotBlank(message="请填写姓名",groups={Validate1.class})
        @Length(max=50,message="长度不能超过50个字符",groups={Validate1.class})
        private String name;
    
        @NotBlank(message="选择性别",groups={Validate2.class})
        private String gender;
    
        @NotBlank(message="请填写身份证号码",groups={Validate3.class})
        @Length(max = 18,message="身份证号码不能超过18个字符",groups={Validate3.class})
        private String cardNo;
    
        @NotBlank(message="请选择户籍地区",groups={Validate4.class})
        @IsUndefined(message="请选择户籍地区",groups={Validate4.class})
        private String province;
        
        @NotBlank(message="请选择户籍地区",groups={Validate5.class})
        @IsUndefined(message="请选择户籍地区",groups={Validate5.class})
        private String cityName;
    
        @NotBlank(message="请选择户籍地区",groups={Validate6.class})
        @IsUndefined(message="请选择户籍地区",groups={Validate6.class})
        private String countyName;
    
        @NotBlank(message="请填写详细地址",groups={Validate7.class})
        @Length(max=50,message="不能超过50个字符",groups={Validate7.class})
        private String detailAddress;
    
        @NotBlank(message="请选择婚姻状况",groups={Validate8.class})
        private String marriage;
    
        @NotBlank(message="请填写公司名称",groups={Validate9.class})
        @Length(max=30,message="公司名称不能超过30个字符",groups={Validate9.class})
        private String companyName;
    
        @NotBlank(message="请填写公司电话",groups={Validate10.class})
        @Length(max=20,message="公司电话不能超过20个字符",groups={Validate10.class})
        private String companyTel;
    
        @NotBlank(message="请填写公司地址",groups={Validate11.class})
        @Length(max=50,message="公司地址不能超过50个字符",groups={Validate11.class})
        private String companyAddress;
    
        @NotBlank(message="请填写个人履历",groups={Validate12.class})
        @Length(max=200,message="个人履历不能超过200字符",groups={Validate12.class})
        private String persomResume;
    
        @NotBlank(message="请选择渠道平台",groups={Validate13.class})
        private String channelType;
    
        @NotBlank(message="请填写保荐人",groups={Validate14.class})
        @Length(max=20,message="保荐人不能超过20个字符",groups={Validate14.class})
        private String recommend;
        
        @NotBlank(message="uuidCode不能为空",groups={Default.class})
        private String uuidCode;
        
    
        public String getRegisterId() {
            return registerId;
        }
    
        public void setRegisterId(String registerId) {
            this.registerId = registerId;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public String getCardNo() {
            return cardNo;
        }
    
        public void setCardNo(String cardNo) {
            this.cardNo = cardNo;
        }
    
        public String getProvince() {
            return province;
        }
    
        public void setProvince(String province) {
            this.province = province;
        }
    
        public String getCityName() {
            return cityName;
        }
    
        public void setCityName(String cityName) {
            this.cityName = cityName;
        }
    
        public String getCountyName() {
            return countyName;
        }
    
        public void setCountyName(String countyName) {
            this.countyName = countyName;
        }
    
        public String getDetailAddress() {
            return detailAddress;
        }
    
        public void setDetailAddress(String detailAddress) {
            this.detailAddress = detailAddress;
        }
    
        public String getMarriage() {
            return marriage;
        }
    
        public void setMarriage(String marriage) {
            this.marriage = marriage;
        }
    
        public String getCompanyName() {
            return companyName;
        }
    
        public void setCompanyName(String companyName) {
            this.companyName = companyName;
        }
    
        public String getCompanyTel() {
            return companyTel;
        }
    
        public void setCompanyTel(String companyTel) {
            this.companyTel = companyTel;
        }
    
        public String getCompanyAddress() {
            return companyAddress;
        }
    
        public void setCompanyAddress(String companyAddress) {
            this.companyAddress = companyAddress;
        }
    
        public String getPersomResume() {
            return persomResume;
        }
    
        public void setPersomResume(String persomResume) {
            this.persomResume = persomResume;
        }
    
        public String getChannelType() {
            return channelType;
        }
    
        public void setChannelType(String channelType) {
            this.channelType = channelType;
        }
    
        public String getRecommend() {
            return recommend;
        }
    
        public void setRecommend(String recommend) {
            this.recommend = recommend;
        }
    
        public String getUuidCode() {
            return uuidCode;
        }
    
        public void setUuidCode(String uuidCode) {
            this.uuidCode = uuidCode;
        }
    
        public interface Validate1{};
        public interface Validate2{};
        public interface Validate3{};
        public interface Validate4{};
        public interface Validate5{};
        public interface Validate6{};
        public interface Validate7{};
        public interface Validate8{};
        public interface Validate9{};
        public interface Validate10{};
        public interface Validate11{};
        public interface Validate12{};
        public interface Validate13{};
        public interface Validate14{};
        public interface Default{};
    }

    其中特别说明:实体类中的这些 interface 用来定义一个验证组,类似一个标识。然后为每个字段指定相应的验证组,其余字段使用默认的验证组。

    接下来声明一个验证序列,指定这个序列需要验证哪些组和验证的顺序。

    package com.hzsj.wechatdto;
    
    import javax.validation.GroupSequence;
    
    @GroupSequence(value={MemberApplyDto.Validate1.class,
            MemberApplyDto.Validate2.class,
            MemberApplyDto.Validate3.class,
            MemberApplyDto.Validate4.class,
            MemberApplyDto.Validate5.class,
            MemberApplyDto.Validate6.class,
            MemberApplyDto.Validate7.class,
            MemberApplyDto.Validate8.class,
            MemberApplyDto.Validate9.class,
            MemberApplyDto.Validate10.class,
            MemberApplyDto.Validate11.class,
            MemberApplyDto.Validate12.class,
            MemberApplyDto.Validate13.class,
            MemberApplyDto.Validate14.class,
            MemberApplyDto.Default.class,
    
    })
    public interface ApplySequence {
    
    }

    我指定的是验证所有组,并按照组的顺序验证。如果在某些情况下只需要验证其中部分字段的话,可重新定义一个验证序列,在接下的Controller中去使用这个序列。

    @RequestMapping(value="/apply",method=RequestMethod.POST)
        @ResponseBody
        public ResultVo memberApply(@Validated({ApplySequence.class}) MemberApplyDto dto,BindingResult bindingResult,Errors errors){
            ResultVo<Object> resultVo = new ResultVo<>();
            if(errors.hasErrors()){
                List<FieldError> errorsList = bindingResult.getFieldErrors();
                Map<String, String> map = new HashMap<>();
                for(FieldError fieldError:errorsList){
                    map.put(fieldError.getField(), fieldError.getDefaultMessage());
                }
                resultVo.setCode(StatusEnums.DATAVALID_ERROR.getCode());
                resultVo.setData(map);
                resultVo.setMsg(StatusEnums.DATAVALID_ERROR.getMsg());
                return resultVo;
            }
            LoginVo vo = memberApplyService.submitApply(dto);
            resultVo.setCode(StatusEnums.SUCCESS.getCode());
            resultVo.setMsg(StatusEnums.SUCCESS.getMsg());
            resultVo.setData(vo);
            return resultVo;
        }

    在Controller中需要的注意的是将原来的@Valid 替换成@Validated 。同时指定了我所需要的验证序列是按照自己定义的验证序列。

    @Valid是javax.validation里的。

    @Validated是@Valid 的一次封装,是Spring提供的校验机制使用。

    相比@Valid  @Validated 提供了几个新功能

    (1)可以通过groups对验证进行分组

    (2)按照序列组来验证

    (3)验证多个实体

    到此基本实现了按照顺序按个验证字段的合法性,但是同时发现了另外的一种情况,前端字段为空的时候会传过来的undefined,导致原来的验证规则失效。所有我们需要自己去定义一个验证规则去验证undefined。上面的实体使用的 @IsUndefined 就是我自行定义的。

    首先定义一个注解,同时指定实现校验规则的类 validatedBy = {UndefinedValiadator.class}

    package com.hzsj.common.util.annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER,ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Constraint(validatedBy = {UndefinedValiadator.class})
    public @interface IsUndefined {
        
            //提示信息
            String message() default "";
    
            Class<?>[] groups() default {};
    
            Class<? extends Payload>[] payload() default {};
    }

    其次,实现这个校验规则

    package com.hzsj.common.util.annotation;
    
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    import org.springframework.util.StringUtils;
    
    public class UndefinedValiadator implements ConstraintValidator<IsUndefined,String>{
        
        
        @Override
        public void initialize(IsUndefined constraintAnnotation) {
        }
    
        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            if(StringUtils.isEmpty(value)){
                return false;
            }
            if("undefined".equals(value)){
                return false;
            }else{
                return true;
            }
        }
    
    }

    至此完成了一个自定义的规则,可以在自己的实体类中去使用了

  • 相关阅读:
    提高.NET编程水平的50个要点(转载)
    动态生成Menu
    C#实现二叉树外带中序遍历(转载)
    我的XML学习笔记<续>
    泛型的排序问题
    我的XML学习笔记
    动态存储过程分页
    排序算法汇总(转载收藏)
    中兴u880e刷机root教程(含刷第三方recover)
    如何清理ipod touch iPhone ipad的“其他”文件
  • 原文地址:https://www.cnblogs.com/li-zhi-long/p/10530321.html
Copyright © 2020-2023  润新知