`
trent_luo
  • 浏览: 43682 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Excel 校验引擎项目设计分享

阅读更多
Excel 校验引擎项目设计分享
需求:
     校验EXCEL文件中每一列,每一个单元格的内容,输出校验报告。
     校验规则实现可配置的形式。
     支持代码的扩展,比如增加校验规则,增加校验结果的处理方式,只需要实现相应的接口,并修改配置文件的内容即可。

设计方案:
     规则的配置以XML配置。

配置文件分为两部分:
第一部分是 校验器 validator的配置,定义validator的名称和class路径。扩展增加的校验器只需要在配置文件里面定义。程序会自动调用该校验器进行校验。
第二部分是每一个列对应的配置。
<item name="END_AREA" alias="目的站">
        <rule type="required" level=”WARN”/>
        <rule type="address"/>
        <rule type=”String”>
               <property name=”minLength”>1</property>
               <property name=”maxLength”>5</property>
        </rule>
          <rule type="repeat">
             <property name="unite">true</property>
        </rule>
</item>
每一个列上可以对应多个规则 rule, type的值为第一部分定义的校验器的别名。Item里面的每个rule都实现自己单独的校验方式。不依赖,不干扰。每个校验器都可以定义校验级别level,校验级别涉及到后面对校验结果更灵活的处理。  每个validator也可以有自己私有的属性 property。比如需要校验某一列的值是字符串,并且长度大于 1 小于 5.则新建一个实现了 Ivalidator接口的类。定义该类的私有属性为

实现接口的方法为校验的逻辑操作

。最大长度,最小长度的值在配置文件里面配置
<rule type=”String”>
               <property name=”minLength”>1</property>
               <property name=”maxLength”>5</property>
</rule>。
一般情况下,校验器是针对每个列的。也就是校验器只对某列的内容进行校验。特殊情况下,我们需要对 多个列之间的内容进行联合校验。比如校验 假入有两列内容重复话,校验结果就判定这两行内容是重复的。可以在配置文件中进行如下配置。
<item name="FROM_AREA" alias="始发站" description="">
        <rule type="repeat">
             <property name="unite">true</property>
        </rule>
    </item>
<item name="END_AREA" alias="目的站">
          <rule type="repeat">
             <property name="unite">true</property>
        </rule>
    </item>
<!-- 重复性校验 -->
       <bean id="repeat"  class="com.alibaba.alp.common.importdata.validator.RepeatValidator"/>
对于repeat这个重复性的校验器。如果unite属性是false的,则该校验器只进行该列的内容是否有重复。如果unite的属性为true的话。并且在配置文件中有多个unite属性为true的的repeat校验器的话。它就会做多列联合性的校验判。前面已经说了,每个列进行的校验操作都是单独的,没有任何关联的。它是如何做到多列间能联合校验的呢。这主要依赖于

AbstractExcelValidator抽象类中的私有属性。AbstractExcelValidator是每个校验器的父类。它实现了IValidator接口,但是没有实现方法,所以只能被继承。 Target 为每个单元格的内容,level为该校验器的校验级别。 dataObj 是一个 HashMap的对象。当我们要将excel的内容与业务数据进行校验的时候,就可以从dataObj取得数据。当需要进行多列联合校验的时候,我们可以将校验结果存入dataObj。
下面讲一下几个重要的类实现。

每个自定义的校验器需要继承 AbstractExcelValidator,实现check方法。Check方法中做的是每个校验独有的校验逻辑,并将校验结果写入 VerifyReport。
VerifyReport主要提供注册监听器和客户端调用的setMsg方法。具体的如何去处理校验结果的操作,比如将该校验结果,实时输出到控制台,网络传输,写入文件等操作,有注册在该对象上的监听器去实现

如果想扩展该校验结果的处理方式。则只需实现 IVerifyListener接口即可。引擎会自动根据客户端实现的监听器去处理结果。有多个监听器则多种处理方式。目前的项目中,校验结果是以EXCEL输出的。如果想增加一个处理方式为 为本输出,或者 浏览器 上实时显示每一个校验结果,则在 IVerifyListener 的实现类中实现。无需改动引擎代码。
每个配置在文件中的校验器它们是如何来进行校验操作的呢?这主要是依赖于验证器工厂类,ValidatorFactory。

该工厂通过反射的方式,将 单元格的内容,业务校验数据,以及配置文件中配置的校验级别,特有属性等数据,注入给校验器,组装好每一个校验器。 组装好的校验器都可以调用自身的 check方法进行校验操作。
本项目中进行EXCEL操作,使用的是jxl包。如果需要用其他的包进行操作的话则实现IConfigFileEngine接口,替换XMLConfigFileEngine类。

主要的几个类的UML图为
相关的代码在
http://svn.alibaba-inc.com/repos/ali_itu/bss/alp/branches/20110517_58681_engine-1.6.5_2/alp.common   com.alibaba.alp.common.importdata.validator 包和 com.alibaba.alp.common.importdata包。

<!--运线价格的数据校验配置-->
<data-validate-config name="运线价格">
    <!-- 配置校验规则调用的类,省得在下面的规则里面把每个class路径都写出来。实现类的属性通过反射自动匹配注入 -->
    <beans>
       <!-- 长度校验 -->
       <bean id="length" class="com.alibaba.alp.common.importdata.validator.StringLengthValidator"/>
       <!-- 是否必填的校验 -->
       <bean id="required" class="com.alibaba.alp.common.importdata.validator.RequiredValidator"/>
       <!-- 地址库的校验 -->
       <bean id="address" class="com.alibaba.alp.bops.biz.common.impt.validator.AddressValidator"/>
       <!-- 浮点数的校验 -->
       <bean id="float" class="com.alibaba.alp.common.importdata.validator.FloatValidator"/>
       <!-- 整数的校验 -->
       <bean id="integer" class="com.alibaba.alp.common.importdata.validator.IntegerValidator"/>
       <!-- 重复性校验 -->
       <bean id="repeat"  class="com.alibaba.alp.common.importdata.validator.RepeatValidator"/>
        <!-- 重复性校验 -->
       <bean id="company"  class="com.alibaba.alp.bops.biz.common.impt.validator.CompanyValidator"/>
       <bean id="transportType" class="com.alibaba.alp.bops.biz.common.impt.validator.TransportTypeValidator"/>
       <bean id="valueBoundValidator" class="com.alibaba.alp.common.importdata.validator.ValueBoundValidator"/>
    </beans>
    <items>
        <!-- repeatColumn 为需要判重的列组合 -->
    <item name="FROM_AREA" alias="始发站" description="">
        <rule type="required"/>
        <rule type="address"/>
        <rule type="repeat">
             <property name="unite">true</property>
        </rule>
    </item>
    <item name="END_AREA" alias="目的站">
        <rule type="required"/>
        <rule type="address"/>
          <rule type="repeat">
             <property name="unite">true</property>
        </rule>
    </item>
    <item name="VOLUME_RATE" alias="轻货费率">
        <rule type="required"/>
    <rule type="integer">
        <property name="scale">+</property>
    </rule>
    </item>
    <item name="WEIGHT_RATE" alias="重货费率">
        <rule type="required"/>
        <rule type="float">
            <property name="scale">+</property>
            <property name="precision">2</property>
        </rule>
    </item>
    <item name="PER_LOWEST_PRICE" alias="最低一票">
        <rule type="required"/>
    <rule type="integer">
        <property name="scale">+</property>
    </rule>
    </item>
    <item name="TRANSPORT_TIME" alias="运行时效">
        <rule type="required"/>
    </item>
    <item name="TRANSPORT_TYPE_CODE" alias="运输方式">
         <rule type="required"/>
         <rule type="transportType"/>
        <rule type="repeat">
        <property name="unite">true</property>
        </rule>
    </item>
    <item name="PRICE_PATTERN" alias="运价模式">
        <rule type="valueBoundValidator" level="error">
             <property name="bound">D2S|D2D|S2D|S2S</property>
        </rule>
        <rule type="repeat">
        <property name="unite">true</property>
        </rule>
    </item>
    <item name="COMPANY_CODE" alias="物流公司编号">
        <rule type="required"/>
        <rule type="company"/>
        <rule type="repeat">
        <property name="unite">true</property>
        </rule>
    </item>
    </items>
</data-validate-config>
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics