在真实项目开发场景中代码任意位置对参数进行javax自定义校验

在开发中,我们常常使用javax.validation包下提供的注解来对前端传过来的字段进行校验,这种方法大大降低了我们反复书写常见校验的代码。

传统写法:

实体侧:

@Data
@Accessors(chain = true)
@ApiModel(value = "People",description = "人")
public class People{
    @ApiModelProperty(value = "姓名")
    private String name;
    
    @ApiModelProperty(value = "性别")
    private String sex;
    
    @ApiModelProperty(value = "年龄")
    private Integer age;
    
    @ApiModelProperty(value = "孩子")
    private List<Child> chidren;
    
}

请求校验测:

@Api(value = "人",tags = "人")
@RestController
@RequestMapping("/people")
public class PeopleController{
  
    boolean validateParams(People peopleRequest,String type){
                //提交时必须不为空,如果作为草稿保存时可以为空
        if(StrUtil.isBlank(peopleRequest.getName()))
      {
        return false;
      }
      if(StrUtil.isBlank(peopleRequest.getSex())){
        return false;
      }
      if(ObjectUtil.isNull(peopleRequest.getAge())){
        return false;
      }
      if(CollectionUtil.isEmpty(children)){
        return false;
      }
      
      return true;
    }
  
    /**
    * 保存草稿
    */
    @ApiOperation(value = "保存人草稿信息")
    public BaseResponse<void> draft(@RequestBody @Validated(People.draft.class) People peopleRequst){
    }
    
    
    /**
    * 提交
    */
    @ApiOperation(value = "提交人信息")
    public BaseResponse<void> submit(@RequestBody @Validated(People.submit.class) People peopleRequst){
            if(!validateParams(peopleRequest,"submit")){
          BaseResponse.error("参数错误");
      }
    }
}

javax.validation注解简化后:

实体测:

@Data
@Accessors(chain = true)
@ApiModel(value = "People",description = "人")
public class People{
    @NotBlank(message = "姓名不能为空",groups = {People.submit.class})
    @ApiModelProperty(value = "姓名",required = true)
    private String name;
    
    @NotBlank(message = "性别不能为空",groups = {People.submit.class})
    @ApiModelProperty(value = "性别",required = true)
    private String sex;
    
    @NotNull(message = "年龄不能为空",groups = {People.submit.class})
    @ApiModelProperty(value = "年龄",required = true)
    private Integer age;
    
    @NotEmpty(message = "孩子不能为空",groups = {People.submit.class})
    @ApiModelProperty(value = "孩子",required = true)
    private List<Child> chidren;
    
    //构建不同情况(分组)
    
    //提交
    public @interface submit{}
    
    //保存草稿
    public @interface draft{}
    
    
}

请求校验测:

@Api(value = "人",tags = "人")
@RestController
@RequestMapping("/people")
public class PeopleController{
    /**
    * 保存草稿
    */
    @ApiOperation(value = "保存人草稿信息")
    public BaseResponse<void> draft(@RequestBody @Validated(People.draft.class) People peopleRequst){}
    
    
    /**
    * 提交
    */
    @ApiOperation(value = "提交人信息")
    public BaseResponse<void> submit(@RequestBody @Validated(People.submit.class) People peopleRequst){}
}

使用到的注解:

@NotNull(message = "") //适用于除了基本数据类型的其他类型数据进行空校验
@NotBlank(message = "")//适用于字符串类型数据,除了会校验为空,还会校验是否为空字符
@NotEmpty(message = "")//适用于集合类型数据,会校验是否为空,还会校验集合长度是否为0,即集合是否有元素
​
@Validate //一般在控制器方法参数前加,表示进行校验


特殊情况:

这种情况保存草稿和提交接口是分开的,所以使用javax.validation注解@Validated可以很好的解决不同场景进行不同校验的要求,但是若是这两个接口需要合并成一个接口呢?

这种情况可能又必须使用传统的方法了,专门编写一个函数对每个字段进行校验!!!

这样实在是太麻烦了,那我们为什么不专门写一个工具类对字段进行javax的校验呢?

最终代码:

实体类:

@Data
@Accessors(chain = true)
@ApiModel(value = "People",description = "人")
public class People{
    @NotBlank(message = "姓名不能为空")
    @ApiModelProperty(value = "姓名")
    private String name;
    
    @NotBlank(message = "性别不能为空")
    @ApiModelProperty(value = "性别")
    private String sex;
    
    @NotNull(message = "年龄不能为空")
    @ApiModelProperty(value = "年龄")
    private Integer age;
    
    @NotEmpty(message = "孩子不能为空")
    @ApiModelProperty(value = "孩子")
    private List<Child> chidren;
}

控制器:

@Api(value = "人",tags = "人")
@RestController
@RequestMapping("/people")
public class PeopleController{
    /**
    * 保存草稿
    */
    @ApiOperation(value = "保存或提交人信息")
    public BaseResponse<void> draftOrSubmit(@RequestBody People peopleRequst,String type){
      if("submit".equals(type)){
          CommonUtils.validateData(peopleRequest);
      }
    }
    
}

工具类:

public class CommonUtils{
    
    @SneakyThrows
    public static void validateData(Object obj){
        //获取对象的Class类型
        Class<?> clazz = obj.getClass();
        //获取对象的所有字段
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields){
            //设置字段可访问
            field.setAccessible(true);
            //获取字段的值
            Object value = field.get(obj);
            //NOT NULL 校验
            if(field.isAnnotationPresent(NotNull.class) && ObjectUtils.isEmpty(value)){
                throw new CommonException(900009,field.getAnnotation(NotNull.class).message());
            }
            //NOT Blank校验
            else if(field.isAnnotationPresent(NotBlank.class)&& StringUtils.isEmpty(String.valueOf(value))){
                throw new CommonException(900009,field.getAnnotation(NotBlank.class).message());
            }
            //LIST SIZE 校验
            else if(field.isAnnotationPresent(Size.class)){
                Size sizeAnnotation = field.getAnnotation(Size.class);
                if(sizeAnnotation.min()>((Collection<?>) value).size() || sizeAnnotation.max() < ((Collection<?>) value).size()){
                    throw new CommonException(900009,sizeAnnotation.message());
                }
            }
            //MAX校验
            else if(field.isAnnotationPresent(Max.class)){
                if(field.getAnnotation(Max.class).value() < (Integer) value){
                    throw new CommonException(900009,field.getAnnotation(Max.class).message());
                }
            }
            //MIN校验
            else if(field.isAnnotationPresent(Min.class)){
                if(field.getAnnotation(Min.class).value()< (Integer) value){
                    throw new CommonException(900009,field.getAnnotation(Min.class).message());
                }
            }
            //LENGTH校验
            else if(field.isAnnotationPresent(Length.class)){
                if(ObjectUtils.isEmpty(value)){
                    return;
                }
                Length lengthAnnotation = field.getAnnotation(Length.class);
                if(lengthAnnotation.min()> String.valueOf(value).length() || lengthAnnotation.max()<String.valueOf(value).length()){
                    throw new CommonException(900009,lengthAnnotation.message());
                }
            }
        }
    }
    
}

工具类主要使用了java反射完成对加上javax.validation注解的字段的校验。

之后在代码的任何位置我们都可以使用CommonUtils.validateData()对请求类进行校验了,这样就自由了需要,不要再受到@Validation注解的限制了。我们也可以通过在validateData方法中编写自己的逻辑对某些注解进行自定义校验。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值