数据校验: 数据校验封装历程

版权声明:每天进步一点点——我也只是写着玩儿——随便转随便评 https://blog.csdn.net/u013034889/article/details/79393459

导读: 公司的整个架构在调整,然后产品的开发也基本有了一定的模式。 那么,本宝宝,非常有幸,被认命加入到模板制造的队伍中。 整个模板规范的制作,有很多内容,PC端,M站等,这两天,我主要是在做一个通用的数据校验封装。 

一、最开始的实现模式

   if (StringUtils.isBlank(bo.getRateId())) {
            return ResponseBzn.build("-11", "费率信息异常");
        }

        if (bo.getStartDate() == null) {
            return ResponseBzn.build("-11", "保险起期异常");
        }

        if (bo.getProposalHolderPerson() == null) {
            return ResponseBzn.build("-1", "请录入投保人信息");
        }

        ProposalHolderPerson holder = bo.getProposalHolderPerson();
        if (StringUtils.isBlank(holder.getName())) {
            return ResponseBzn.build("-1", "请录入投保人姓名");
        }

感觉,很多人都见过,也应该都写过类似的代码。 反正,我肯定是写过滴。 呃,那时候还觉得挺对的。其实,如果只有一次应用,各不相同的话,我现在也觉得这样也很对。 嘿嘿,但为什么要重构封装呢?
第一、校验有共性、大多数产品都会涉及到这样的校验。 嗯,或者说是每一个产品
第二、不止有基本的输入校验,还有相关规则校验
第三、混合到真正的业务中,影响了代码的结构
第四、无法复用

二、最开始的调整思路

最开始的时候,是希望通过注解的形式加以校验。 也就是说当参数从前台传入的时候,后台通过@Valitated注解进行校验。注意:最开始的想法是每一个校验块都通过注解。毕竟,这样方便嘛。 一点简单的输入校验直接利用已有的注解,就完全可以实现。 但自己项目的个性化校验,就需要自定义注解去实现了。

自定义注解实现,根本不是难事儿(呃,我也不知道咋回事,记忆中,写这个自定义注解写了好多回了,包括反射。以前看这些东西都怕,就一个劲儿躲。现在是和睦相处,呵呵)。但是想的也简单,不就是注解嘛。但在实施的过程中,其实碰壁了。

虽然,最后这种方式我没测成功,但还是贴段当时的代码看看吧。
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CertNo.certNoValidator.class})
@Documented
public @interface CertNo {
    String message() default "";

    Class<?> entity();

    Class<?>[] groups() default {};

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

    class certNoValidator implements ConstraintValidator<CertNo, String> {

        Object entityInstance;

        @Override
        public void initialize(CertNo constraintAnnotation) {
            try {
                this.entityInstance = constraintAnnotation.entity().newInstance();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }

        @Override
        public boolean isValid(String value, ConstraintValidatorContext context) {
            //获取证件类型
            try {
                Integer certType = (Integer) getProperty(entityInstance, "certType");
                if (certType == 1) {
                    IDCodeInfo idCodeInfo = new IDValidator().getInfo(value);
                    if (StringUtils.length(value) >= 18 && idCodeInfo.isValid()) {
                        setProperty(entityInstance, "sex", idCodeInfo.getSex());
                        setProperty(entityInstance, "birthday", FormatUtil.string2Date(idCodeInfo.getBirth()));
                        return true;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }

        /*该方法用于传入某实例对象以及对象方法名,通过反射调用该对象的某个get方法*/
        private static Object getProperty(Object beanObj, String property) throws Exception {
            PropertyDescriptor pd = new PropertyDescriptor(property, beanObj.getClass());
            Method getMethod = pd.getReadMethod();
            return getMethod.invoke(beanObj);
        }

        /*该方法用于传入某实例对象以及对象方法名、修改值,通过放射调用该对象的某个set方法设置修改值*/
        private static Object setProperty(Object beanObj, String property, Object value) throws Exception {
            PropertyDescriptor pd = new PropertyDescriptor(property, beanObj.getClass());
            Method setMethod = pd.getWriteMethod();
            return setMethod.invoke(beanObj, value);
        }
    }
}

其实这个注解要做的事,很简单。它要做的就是:当传入的证件类型为身份证类型时,校验其身份证号是否合规,并且,此时允许性别、出生日期为空,通过身份证号自动设置。
上面这段代码,这个注解是实现了,但是,根本没用。 有个大Bug解决不了。  嗯,好奇但又没看出来的,可以留言问我哈。
这个没行得通,但又真的想通过注解去做,结果就试了试在实体里面写方法,把注解加到方法上。 这个方法,最开始是单独写的,后来很尴尬的发现,都没有地方调用这个方法。  然而,就算显示的调用,也没做到复用(每个产品都有自己的实体DTO,后来,改了这段方法实现的位置,但还是解决不了复用的根本问题。嘿嘿,有无聊的,可以想想这个方法,加到哪儿才会有用。)
这个其实都不是最奇葩的,最奇葩的是,实体里面,带集合,带实体。 有一个规则校验,需要用到实体的属性和实体集合中实体的属性,但又是归属于其附带实体的校验内容。  当时采用了校验的分组groups策略,但依然没解决实际问题。
后来就问了问我朋友公司都怎么处理数据校验的,比较通用的是:

关于这一点,可以参考看看java使用validator进行校验 

但也是达不到预期的效果。呵呵,天无绝人之路,本宝宝突然想起当年整.NET的时候,有试过一个校验的框架。 而且,我就在想,我肯定不是第一个遇到这样问题的人,看看别人怎么解决的,站在巨人的肩膀上嘛,嘿嘿。 然后就找到了fluent_validator这个专门用来做逻辑校验的框架。

三、关于fluent_validator

Java的业务逻辑验证框架fluent-validator 

有了这个可以校验逻辑的组件,接下来就是想,怎样调整和涉及,能够让类型产品复用,同样的校验规则,一步搞定呢? 下篇博客再写,做的其实也不好,但简单复用还是没毛病的。

但我们从前往后看,调整之后,最起码,将数据校验和其核心业务剥离了,职责更加明确。

四、个人总结

对此,个人并没有想过多说明的,但我感觉收获还是蛮大的。 以前没弄过关于校验的封装,总感觉这是个小事情,每个人自己写就可以了。  对代码没有洁癖,说的就是之前和现在的我。

另外,只要思想不滑坡,办法总比困难多,加油!

展开阅读全文

没有更多推荐了,返回首页