【参数校验框架】自定义一个基于 javax.validation 接口的参数校验工具类

一、场景介绍
  • @Valid@Validated 注解一般都直接在 Controller 层对请求参数的校验而直接在入参中使用进行绑定数据校验

  • 在有些情况,例如:你的参数对象中的某个字段是一个复合对象,或者业务层的某个方法所定义的入参对象也需要进行数据合法性校验,那么这种情况下如何实现像 Controller 层一样的校验效果呢?

  • 需要说明在这种情况下 @Validated 已经无法直接使用了,因为 @Validated 注解发挥作用主要是 Spring MVC 在接收参数的过程中实现了自动数据绑定校验,而在普通的业务方法或者复合参数对象中是没有办法直接绑定校验的。

  • 这种情况下,我们可以通过定义一个基于 javax.validation 接口的 ValidatorUtil 工具类,这样就可以在非 @Validated 直接绑定校验的场景中通过校验工具类来实现对 Bean 对象约束注解的校验,来校验 @Valid 的规则来实现一样的校验效果

二、校验场景
  • Controller 层不对请求参数到校验(当然一般情况下是在 Controller 进行参数绑定到时候校验参数到合法性,但是这里只是用示例说明,在 Service 层也同样可以达到这种校验的效果)

  • Service 层对实体 Bean 进行 @Valid 扫描到注解进行校验

  • 校验自定义注解和原生注解到字段不合规性的异常

三、封装工具
  • 自定义 ValidatorUtil 工具类

    /**
     * Copyright (C), 1998-2021, Shenzhen Rambo Technology Co., Ltd
     * 自定义对象属性规则校验工具,校验方式适配 @Valid 和 @Validated 注解的校验规则
     *
     * @author  Rambo
     * @date    2021/3/11 19:24
     * @since   1.0.0.1
     */
    public class ValidatorUtil {
    
        /** 通过建造者工厂模式创建 javax.validation.Validator 对象*/
        private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
    
        /**
         * Bean 对象的整体校验,有不符合规范的属性,迭代异常 Message 并拼接后全部抛出
         *
         * @author  Rambo
         * @date    2021/3/11 19:28
         * @param	obj     待验证对象
         * @param	groups  分组
         */
        public static void validated(Object obj, Class<?>... groups) {
            Set<ConstraintViolation<Object>> resultSet = validator.validate(obj, groups);
            if (resultSet.size() > 0) {
                // 如果存在错误结果,则将其解析并进行拼凑后异常抛出
                List<String> errorMessageList = resultSet.stream().map(ConstraintViolation::getMessage).collect(Collectors.toList());
                StringBuilder errorMessage = new StringBuilder();
                errorMessageList.forEach(o -> errorMessage.append(o).append(";"));
                // 抛出异常
                throw new IllegalArgumentException(errorMessage.toString());
            }
        }
    }
    
四、使用工具
  1. 自定义需要检验到 Order 对象

    @Data
    @ToString
    public class Order implements Serializable {
        private static final long serialVersionUID = 784930215432L;
    
        /** 订单号*/
        private int id;
    
        /** 订单名称*/
        @NotNull(message = "订单名称不能为空")
        private String orderName;
    
        /** 订单状态
            定制化注解,支持参数值与指定类型数组列表值进行匹配(缺点是需要将枚举值写死在字段定义的注解中)*/
        @EnumValidated(strValues = {"FAIL", "PAYED"}, message = "只能查询指定状态的订单信息-1")
        private String orderState;
    
        /** 订单状态枚举
            定制化注解,实现参数值与枚举列表的自动匹配校验(能更好地与实际业务开发匹配)*/
        @EnumValidated(enumValues = OrderStateEnum.class, message = "只能查询指定状态的订单信息-2")
        private String orderStateEnum;
    }
    
  2. 编写控制层,并且对绑定到入参不进行校验,并且模拟程序在 Service 层对 @Valid 所扫描到注解进行校验

    @PostMapping("/util/order")
    @ApiOperation(value = "订单查询", notes = "订单查询,采用自定义工具类创建Validator.validate(obj, groups)来校验 @Valid 的规则")
    public DataResult orderList2(@RequestBody Order order) {
        // 采用自定义工具类创建Validator.validate(obj, groups)来校验 @Valid 的规则
        ValidatorUtil.validated(order);
        log.info("The request is {}", order.toString());
        return DataResult.success();
    }
    
  3. 模拟请求参数

    {
      "id": 0,
      "orderState": "FAIL1",
      "orderStateEnum": "FAIL2"
    }
    
  4. 验证响应结果

    {
      "code": 10000,
      "msg": "只能查询指定状态的订单信息-1;只能查询指定状态的订单信息-2;订单名称不能为空;",
      "detail": null,
      "data": null
    }
    

    P.S

    以上 Controller 通过项目中定义 @RestControllerAdvice 来进行异常统一处理,所以看到的响应结果是封装过的

  5. Service 层对 @Valid 所扫描到注解,通过自定义工具类 ValidatorUtil 来进行参数的校验,在编程体验上就可以整体上保持一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值