zoukankan      html  css  js  c++  java
  • springboot-使用validator进行参数校验

    参数校验

    在日常的项目开发中,我们为了数据的正确性,后端都会单独对数据进行校验,比如说用户信息中的年龄校验,用户名长度校验,用户性别校验等。

    校验方式分类

    我们常见的校验方式分为俩种,一种是使用校验类来进行校验,另外一种是使用spring validator或者hibernate validator。使用手动方式进行校验,虽然可以将常用逻辑的校验抽取成方式,但是代码中还是会存在很多校验方法的调用,显得不那么简洁。

    使用validator

    博主这里主要介绍一下如何使用hibernate validator来进行参数的校验,其中也包含了一些spring validator的内容。

    pom依赖

    因为我们使用了hibernate validator,我们需要先导入maven依赖。

    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.5.Final</version>
    </dependency>
    

    常用注解

    @Null 被注释的元素必须为 null
    @NotNull 被注释的元素必须不为 null
    @AssertTrue 被注释的元素必须为 true
    @AssertFalse 被注释的元素必须为 false
    @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
    @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
    @Size(max=, min=) 被注释的元素的大小必须在指定的范围内
    @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
    @Past 被注释的元素必须是一个过去的日期
    @Future 被注释的元素必须是一个将来的日期
    @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
    Hibernate Validator 附加的 constraint
    @NotBlank(message =) 验证字符串非null,且长度必须大于0
    @Email 被注释的元素必须是电子邮箱地址
    @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
    @NotEmpty 被注释的字符串的必须非空
    @Range(min=,max=,message=) 被注释的元素必须在合适的范围内

    入参校验

    一般在入参比较少的情况下,比如说只有一俩个参数的情况下,可以使用入参校验的方式。
    而这种入参校验,我们需要在控制器上添加validated注解,然后在方法入参上添加校验注解,validated注解是spring validator的。

    @RestController
    @RequestMapping("/user")
    @Validated
    public class UserController {
        @GetMapping("/get")
        public User getUser(@Min(1) int id){
            return null;
        }
    }
    

    模型校验

    在控制器方法入参比较多的情况下,我们一般选用模型校验的方式。这时候我们需要在被校验的模型前面添加@Validated注解,在模型的属性上添加校验注解。

    @PostMapping("/update")
    public boolean updateUser(@Validated User user)
    {
        boolean success = false;
        return success;
    }
    
    @Data
    public class User {
        @NotBlank(message = "用户名不能为空")
        private String name;
    
        @Min(value = 1)
        private int age;
    
        @Min(value = 1)
        private int id;
    }
    

    嵌套校验

    嵌套校验就是校验组合对象,组合对象在数据库中一般都对应为主从表,比如说订单主表 和 订单细表。这里我们方便起见,直接在之前的User对象中嵌套一个Book对象进行嵌套校验的测试。

    @Data
    public class User {
        @NotBlank(message = "用户名不能为空")
        private String name;
    
        @Min(value = 1)
        private int age;
    
        @Min(value = 1)
        private int id;
    
        @Valid
        Book book;
    }
    
    @Data
    public class Book {
    
        @Min(1)    
        private int id;
        
        @Size(min=3, max = 10)
        private String name;
    }
    
    

    分组校验

    分组校验就是将校验规则进行分组,比如说user对象的新增来说,不需要校验id的范围,而对于user对象的更新来说,需要校验id的范围。如果不用分组校验的话,我们则可能需要创建俩个对象分别进行校验。

    首先,我们先创建一个名为UpdateGroup.class,并且将其作用于id属性上,默认的校验分组为Default.class。

    @Data
    public class User {
        @NotBlank(message = "用户名不能为空")
        private String name;
    
        @Min(value = 1)
        private int age;
    
        @Min(value = 1, groups = UpdateGroup.class)
        private int id;
    }
    

    然后,我们需要修改校验模型前的@Validated注解。

      @PostMapping("/add")
      public boolean addUser(@Validated({UpdateGroup.class}) User user)
      {
          return true;
      }
    

    自定义校验

    如果之前的常用注解,不能满足我们的要求,我们则需要自定义注解,我们这里使用自定义枚举类型的注解作为例子。

    @Target({ElementType.FIELD})
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy = {EnumValueValidator.class})
    public @interface EnumValue {
        //默认错误消息
        String message() default "必须为指定值";
        int[] values() default {};
        //分组
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
        //指定多个时使用
        @Target({ElementType.FIELD})
        @Retention(RetentionPolicy.RUNTIME)
        @Documented
        @interface List {
            EnumValue[] value();
        }
    }
    
    //枚举校验类
    public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {
        private int[] values;
        @Override
        public void initialize(EnumValue constraintAnnotation) {
            values = constraintAnnotation.values();
        }
    
        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
            if(o instanceof Integer) {
                Integer integer = (Integer) o;
                for (int value : values) {
                    if(value == integer){
                        return true;
                    }
                }
            }
            return false;
        }
    }
    

    异常捕捉

    在定义好我们的校验规则之后,如果校验失败,我们怎么将失败信息统格式后返回给前端?博主这里使用了全局异常捕捉的方式。

    @ControllerAdvice
    public class ExceptionIntercept {
    
    	//模型校验失败会产生这个异常
        @ExceptionHandler(value = { ConstraintViolationException.class })
        @ResponseBody
        public BaseResponse handleException(ConstraintViolationException exception){
            return BaseResponse.error(exception.getMessage());
        }
    	
    	//入参校验失败会产生这个异常
        @ExceptionHandler(value = { BindException.class })
        @ResponseBody
        public BaseResponse handleException(BindException exception){
            BindingResult bindingResult = exception.getBindingResult();
            return getResponse(bindingResult);
        }
    
    	//异常兜底
        @ExceptionHandler(value = { Exception.class })
        @ResponseBody
        public BaseResponse handleException(Exception exception){
            return BaseResponse.error(exception.getMessage());
        }
    
        private BaseResponse getResponse(BindingResult bindingResult){
            StringBuilder errorInfo = new StringBuilder();
            for (ObjectError allError : bindingResult.getAllErrors()) {
                errorInfo.append(allError.toString());
            }
            return BaseResponse.error(errorInfo.toString());
        }
    }
    

    进行了全局异常捕捉的配置之后,我们来简单的查看一下异常信息的返回。

    查看异常信息

    博主微信公众号

  • 相关阅读:
    checkpoint threat cloud 更改中国区更新库
    2021关于算法的“想象”
    安装Hadoop
    BUG:@RabbitListener的concurrency属性
    Redisson使用01
    spring boot项目整合mybatis访问数据源
    MyBatis Generator使用记录
    spring boot集成Swagger
    PostgreSQL常用命令(持续更新)
    2021Y12M学技术感悟
  • 原文地址:https://www.cnblogs.com/chenhaoblog/p/13532602.html
Copyright © 2011-2022 走看看