优雅的参数验证@Validated@Validated参数校验的使用及注解详解——你还在用if做条件验证?

Posted A-Itfuture

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了优雅的参数验证@Validated@Validated参数校验的使用及注解详解——你还在用if做条件验证?相关的知识,希望对你有一定的参考价值。

@Validated参数校验的使用及注解详解

你还在用if做条件验证吗?

请先看看下面代码:(简单举个例子,代码并不规范)

    @ApiOperation("新增用户")
    @PostMapping("/addUser")
    public ResultVo insert(@ApiParam("用户信息实体") @RequestBody User user)
        if(user.getUserName!=null)
           throw new BusinessException("用户名称不能为空");
        
        if(user.getUserPhone!=null)
           throw new BusinessException("用户电话不能为空");
        
        if( user.getUserPhone().length())
           throw new BusinessException("用户电话格式不规范");
        
        return new ResultVo(userService.insert(user));
    

以上代码主要是为了对用户user实体进行条件验证。
但是那么多的if, 写得纯纯得小白一个,也使得代码显得臃肿不美观不优雅!
接下来,让我们学习使用优雅的参数验证@Validated!

一、优雅的参数验证@Validated

@Valid和@Validated是Spring Validation框架提供的参数验证功能。

1.@Valid和@Validated的用法(区别)

二者主要作用在于 都作为标准JSR-303规范,在检验Controller的入参是否符合规范时,使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同:

@Valid:
@Valid注解用于校验,所属包为:javax.validation.Valid。

用在方法入参上无法单独提供嵌套验证功能。**能够用在成员属性(字段)**上,提示验证框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

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

用在方法入参上无法单独提供嵌套验证功能。不能用在成员属性(字段)上,也无法提示框架进行嵌套验证。能配合嵌套验证注解@Valid进行嵌套验证。

2.引入并使用@Validated参数验证

  1. 引入校验的依赖包
        <!--第一种方式导入校验依赖:使用springboot时,在org\\springframework\\spring-context\\5.2.1.RELEASE\\spring-context-5.2.1.RELEASE.jar-->
		<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!--第二种方式导入校验依赖-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>
        <!--第三种方式导入校验依赖-->
        <dependency>
            <groupId>org.hibernate.validator</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>
  1. 找到自己的实体类定义自己要校验的参数

3.在controller的入参处添加@Validated注解(@Validated可以指定groups区别验证,@Valid不可以指定groups,见上面二者区别)

@Validated(addGroup.class)就是给参数进行了分组校验

    @ApiOperation("新增用户")
    @PostMapping("/addUser")
    public ResultVo insert(@ApiParam("用户信息实体") @Validated(addUser.class) @RequestBody User user)
        return new ResultVo(userService.insert(user));
    

那么addGroup.class是哪里来的??什么作用?
addGroup.class:是一个接口类,简单的来说:就是用来给参数做标记的(里面不需要写任何代码)

到这里基本的使用就结束了!

二、javax.validation.constraints下参数条件注解详解

实现参数验证功能,我们需要@Validated注解配合 在实体类的的参数加上条件验证注解(设置具体的条件限制规则)一起实现参数验证功能。

而这些参数条件注解是由javax.validation.constraints包下提供,主要如下:

  1. @NotNull :被注解的元素必须不为null

  2. @NotBlank注解 :验证注解的元素值不为空(不为null、去除首位空格后长度为0) ,并且类型为String。

  3. @NotEmpty注解 :验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) ,并且类型为String。

  4. @AssertTrue注解 :被注解的元素必须为true,并且类型为boolean。

  5. @AssertFalse注解 :被注解的元素必须为false,并且类型为boolean。

  6. @Min注解 :被注解的元素其值必须大于等于最小值,并且类型为int,long,float,double。

  7. @Max注解:被注解的元素其值必须小于等于最小值,并且类型为int,long,float,double。

  8. @DecimalMin注解 :验证注解的元素值大于等于@DecimalMin指定的value值,并且类型为BigDecimal。

  9. @DecimalMax注解 :验证注解的元素值小于等于@DecimalMax指定的value值 ,并且类型为BigDecimal。

  10. @Range注解 :验证注解的元素值在最小值和最大值之间,并且类型为BigDecimal,BigInteger,CharSequence,byte,short,int,long。

  11. @Past注解 :被注解的元素必须为过去的一个时间,并且类型为java.util.Date。

  12. @Future注解 :被注解的元素必须为未来的一个时间,并且类型为java.util.Date。

  13. @Size注解 :被注解的元素的长度必须在指定范围内,并且类型为String,Array,List,Map。

  14. @Length注解 :验证注解的元素值长度在min和max区间内 ,并且类型为String。

  15. @Digits注解 :验证注解的元素值的整数位数和小数位数上限 ,并且类型为float,double,BigDecimal。

  16. @Pattern注解 :被注解的元素必须符合指定的正则表达式,并且类型为String。

  17. @Email注解: 验证注解的元素值是Email,也可以通过regexp和flag指定自定义的email格式,类型为String。

三、自定义条件注解

如果在写项目的过程中,参数需要的条件注解满足不上,则我们需要自定义注解来完成

步骤:

1.创建一个自定义的注解类

/**自定义条件注解
 * @author: wxh
 * @version:v1.0
 * @date: 2022/11/14 22:39
 */
@Target(ElementType.FIELD,ElementType.METHOD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER,ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ListValueConstraintValidator.class)
public @interface ListValue 
    //配置路径,后端传递信息
    String message() default "com.itfuture.e.valid.ListValue.message";
    
    Class<?>[] groups() default ;

    Class<? extends Payload>[] payload() default ;

    //自定义一个类型来存放数据(数组)
    int[] values() default ;


2.创建一个逻辑处理数据的方法

/**自定义显示状态
 * @author: wxh
 * @version:v1.0
 * @date: 2022/11/14 22:49
 */
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> 
    //set存储
    private Set<Integer> set = new HashSet<>();

    //初始化数据
    //listValue拿到的是注解中的数据
    @Override
    public void initialize(ListValue constraintAnnotation) 
        //拿到注解中自定义的数据,且是数组型的
        int[] values = constraintAnnotation.values();
        //放在数组里,遍历判断
        for(int value:values)
            set.add(value);
        
    

    //判断数据是否相同
    @Override
    public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) 
        if(set.contains(integer))
            return true;
        
        return false;
    

3.String message() default “com.atguigu.common.valid.ListValue.message”;

这个消息:message() default "com.atguigu.common.valid.ListValue.message"也可以通过配置文件去配置:

4.在实体类的参数条件中来调用:

至此,参数验证基本完述!

3-7 公共请求对象封装及优雅验证数据实现

这是提前准备好的接口文档
技术图片
技术图片
新建UserController
技术图片

技术图片
接收的参数用对象的形式
技术图片
controller下新建vo的包,然后新建登陆接口需要的对象类LoginReqVO
技术图片

技术图片

技术图片

下面这个时候就要写数据的验证了,一般都要几十行的验证代码。
技术图片
提供另外一种方法
技术图片
这个方法只能做一些基础的验证。因为没有办法注入逻辑层啊数据层啊这些。所以只能做一些公共的基础验证。
技术图片
这样我们的loginVO继承BaserRequestVO然后去实现这个方法
技术图片

这样你的controller里面这一行代码就去验证数据源的合法性
技术图片
自定义exception
技术图片

技术图片

两个属性一个全参的构造方法
技术图片 
如果出错了就抛出异常
技术图片
这样我们的loginVO也需要抛出这个异常
技术图片
controller内的方法也直接抛出去
技术图片

新建基础工具类

技术图片

技术图片


技术图片
404就是未找到资源,username和password有一个为空就抛出异常。
技术图片
改成中文
技术图片
异常一直往上抛出,最后抛到UserController
技术图片


结束

以上是关于优雅的参数验证@Validated@Validated参数校验的使用及注解详解——你还在用if做条件验证?的主要内容,如果未能解决你的问题,请参考以下文章

优雅的方式来校验spring-boot的form表单参数和json的body参数合法性验证方式

Preconditions优雅的检验参数

3-7 公共请求对象封装及优雅验证数据实现

SpringBoot - 优雅的实现参数分组校验高级进阶

SpringBoot - 优雅的实现参数校验高级进阶

SpringBoot - 优雅的实现业务校验高级进阶