• 【java框架】SpringBoot(9) -- Springboot中如何优雅的进行字段校验


    参数校验放置位置:一般推荐与业务无关的放在Controller层中进行校验,而与业务有关的放在Service层中进行校验。如果项目中都在Controller层中进行的校验,则按照项目的规范要求参照进行校验即可。

    1.1.常用的校验工具类

    使用Hiberbate Validate

    引入依赖:

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

    常用注解说明

    注解说明
    @Length(min=,max=) 检查所属的字段的长度是否在min和max之间,只能用于字符串
    @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
    @Max 该字段的值只能小于或等于该值
    @Min 该字段的值只能大于或等于该值
    @NotNull 不能为null
    @NotBlank 不能为空,检查时会将空格忽略
    @NotEmpty 不能为空,这里的空是指空字符串
    @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式

     使用姿势

    需要搭配在Controller中搭配@Validated或@Valid注解一起使用,@Validated和@Valid注解区别不是很大,一般情况下任选一个即可,区别如下:

    注解@Validated@Valid
    所属的包 属于org.springframework.validation.annotation包下的,是spring提供的 属于javax.validation包下,是jdk给提供的
    是否支持分组和排序

     虽然@Validated比@Valid更加强大,在@Valid之上提供了分组功能和验证排序功能,不过在实际项目中一直没有用到过 Hibernate-validate框架中的注解是需要加在实体中一起使用的

    • 定义一个实体
    public class DataSetSaveVO {
        //唯一标识符为空
        @NotBlank(message = "user uuid is empty")
        //用户名称只能是字母和数字
        @Pattern(regexp = "^[a-z0-9]+$", message = "user names can only be alphabetic and numeric")
        @Length(max = 48, message = "user uuid length over 48 byte")
        private String userUuid;
    
        //数据集名称只能是字母和数字
        @Pattern(regexp = "^[A-Za-z0-9]+$", message = "data set names can only be letters and Numbers")
        //文件名称过长
        @Length(max = 48, message = "file name too long")
        //文件名称为空
        @NotBlank(message = "file name is empty")
        private String name;
    
        //数据集描述最多为256字节
        @Length(max = 256, message = "data set description length over 256 byte")
        //数据集描述为空
        @NotBlank(message = "data set description is null")
        private String description;
    }

    说明:message字段为不符合校验规则时抛出的异常信息

    • Controller层中的方法
    @PostMapping
    public ResponseVO createDataSet(@Valid @RequestBody DataSetSaveVO dataSetVO) {
        return ResponseUtil.success(dataSetService.saveDataSet(dataSetVO));
    }

    说明:在校验的实体DataSetSaveVO旁边添加@Valid或@Validated注解

    1.2.使用commons-lang3

    引入依赖

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>

    常用方法说明

    方法说明
    CollectionUtils.isEmpty 判断集合是否为空,为null或者size==0,返回true
    CollectionUtils.isNotEmpty 判断集合是否为非空
    StringUtils.isEmpty 判断字符串是否为空
    StringUtils.isNotEmpty 判断字符串是否非空
    StringUtils.isBlank 判断字符串是否为空,为null或者size==0或者只存在空白字符(如" "),则返回true
    StringUtils.isNotBlank 判断字符串是否为非空

     测试代码

    //StringUtils.isEmpty
    System.out.println(StringUtils.isEmpty(""));  //true
    System.out.println(StringUtils.isEmpty("  "));  //false
    //StringUtils.isNotEmpty
    System.out.println(StringUtils.isNotEmpty(""));  //false
    
    //StringUtils.isBlank
    System.out.println(StringUtils.isBlank(""));  //true
    System.out.println(StringUtils.isBlank(" "));  //true
    //StringUtils.isNotBlank
    System.out.println(StringUtils.isNotBlank(" "));  //false
    
    List<Integer> emptyList = new ArrayList<>();
    List<Integer> nullList = null;
    List<Integer> notEmptyList = new ArrayList<>();
    notEmptyList.add(1);
    
    //CollectionUtils.isEmpty
    System.out.println(CollectionUtils.isEmpty(emptyList));   //true
    System.out.println(CollectionUtils.isEmpty(nullList));   //true
    System.out.println(CollectionUtils.isEmpty(notEmptyList));   //false
    
    //CollectionUtils.isNotEmpty
    System.out.println(CollectionUtils.isNotEmpty(emptyList));   //false
    System.out.println(CollectionUtils.isNotEmpty(nullList));   //false
    System.out.println(CollectionUtils.isNotEmpty(notEmptyList));   //true

    1.3. Controller中统一异常拦截处理

    以下是两个简单的在Controller中可以设置的异常捕获类,当代码在Service层中可以throw或者异常抛出的时候进行拦截处理:

    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public JsonResponse<Object> resloveConstraintViolationExcption(ConstraintViolationException ex, HttpServletResponse response){
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if(!CollectionUtils.isEmpty(constraintViolations)){
            StringBuilder msgBuilder = new StringBuilder();
            for (ConstraintViolation<?> constraintViolation : constraintViolations) {
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if(errorMessage.length() > 1){
                errorMessage = errorMessage.substring(0, errorMessage.length()-1);
            }
            LOGGER.error("ConstranintViolationException:error{}", errorMessage);
            response.setStatus(JsonResponse.FAILED_STATUS);
            return new JsonResponse<>(JsonResponse.FAILED_STATUS, "请求参数有误:" + errorMessage);
        }
    
        LOGGER.error("ConstranintViolationException:error{}", ex.getMessage());
        response.setStatus(JsonResponse.FAILED_STATUS);
        return new JsonResponse<>(JsonResponse.FAILED_STATUS, "请求参数有误:" + ex.getMessage());
    }
    @ExceptionHandler(NumberFormatException.class)
    @ResponseBody
    public JsonResponse<Object> resolveNumberFormatException(NumberFormatException ex, HttpServletResponse response){
        LOGGER.error("NumberFormatException:error{}", ex.getMessage());
        response.setStatus(JsonResponse.FAILED_STATUS);
        return new JsonResponse<>(JsonResponse.FAILED_STATUS, "转换Number处理问题有误:" + ex.getMessage());
    }

    1.4.使用Validated与@Valid做参数校验 

    @Valid是使用Hibernate validation的时候使用;@Validated是Spring Validator做校验机制时使用

    说明:java的JSR303声明了@Valid这类接口,而Hibernate-validator对其进行了实现。

    注解位置:

    @Validated:用在类、方法和方法参数上,但不能用于成员属性(fileld)上,会编译报错,嵌套校验必须使用@Valid一起加在成员属性上。

    @Valid:可以用在方法、构造函数、方法参数和成员属性(field)上,用在类上面编译不报错,但是没用。

    分组校验

    @Validated:提供分组功能,可以在参数验证时,根据不同的分组采用不同的验证机制

    @Valid:没有分组功能

    @Getter
    @Setter
    public class RequestParam {
        @NotBlank(groups = {Insert.class})
        private String paramInsert;
        @NotBlank(groups = {Update.class})
        private String paramUpdate;
    
        private Order order;
    
        public interface Insert {
        }
    
        public interface Update {
        }
    }

    请求Controller:

    @RestController
    @RequestMapping("/param")
    @Validated
    public class ParamValidController {
        @PostMapping("/insert")
        public void insert(@RequestBody @Validated({RequestParam.Insert.class}) Order order){
        }
    
        @PostMapping("/update")
        public void update(@RequestBody @Validated({RequestParam.Update.class}) Order order{}
    }

    这样就可以实现对insert方法校验paramInsert,对update方法校验paramUpdate。

    嵌套校验

    @Getter
    @Setter
    public class RequestParam {
        @NotBlank(groups = {Insert.class})
        private String paramInsert;
        @NotBlank(groups = {Update.class})
        private String paramUpdate;
        @Valid
        @NotNull
        private Order order;
    
        public interface Insert {
        }
    
        public interface Update {
        }
    }
    @Data
    public class Order {
        @NotBlank
        private String orderName;
        @Pattern(regexp = "[0-9A-Za-z]{5}", message = "设备编码必须符合数字与字母的规则")
        private Integer orderNo;
    }

    一个待验证的pojo类,如果其中还包含了待验证的对象,需要在待验证对象上注解@Valid,才能验证待验证对象中的成员属性。

    此处@NotNull只能验证order不为空,加上了@Valid才能对Order嵌套类的成员属性进行验证,当然在Order类中的需校验的属性字段也需要添加校验注解。

     

    总结:

    • 在使用@Validated做参数校验的时候,需要在Controller类上面加@Validated注解,参数校验才能生效,如果方法参数是pojo类,则需要在参数上面也加@Validated或@Valid校验才能生效。非pojo类的参数,不需要加@Validated或@Valid。

    • 可以使用@Validated({RequestParam.Insert.class})实现同一个pojo类的分组校验
    • 需要对待验证的pojo类内部的对象属性进行验证的时候,需要在待验证的对象上注解@Valid,实现嵌套验证

    另外推荐两篇写的比较好的SpringBoot项目做参数校验的博文:

    Spring Boot 参数校验

    @Validated和@Valid区别

    博文参考:

    Springboot中如何优雅的进行字段校验

  • 相关阅读:
    一本名副其实的 Web架构“圣经”——关于《HTTP权威指南》
    图灵生日会——纪念阿兰图灵诞辰100周年及图灵公司七周年线下交流会
    跟着图灵听课去!(六月)
    “电梯演讲”最精炼、贴切的语言
    送你一把开启演讲之路的钥匙——《演讲的艺术》
    翻译是一份严谨的工作——关于HTTP中文翻译的讨论
    浪潮之巅作者吴军推荐序——《推荐系统实践》
    如何到达永生?揭示科学之美
    软件行业大牛告诉你何谓成功?
    C#线程系列讲座(3):线程池和文件下载服务器
  • 原文地址:https://www.cnblogs.com/yif0118/p/15077815.html
Copyright © 2020-2023  润新知