【解决方式】xml文件定义与对象映射

【解决方式】xml文件定义与对象映射

说明

​ XML文件是我们开发过程中常用的一种数据格式,由于它成熟的校验机制与固定的语法格式,虽然较为复杂但也没有失去他的作用;业务开发过程中,需要采集Excel的文件内容且与数据库表结果相映射,就开发了一套代码用于处理这种较为固定的Excel数据的采集;其中定义了一种固定的xml文件格式,与读取xml文件的一种方式。

业务描述

​ 业务目的:

​ 通过配置不同的xml配置文件,达到适配不同Excel文件格式并采集相应数据的功能,中间转化的文件以CSV格式,有利于直接Load到对应的数据库表中。

​ 满足的功能点:

​ (1)文件校验;

​ (2)文件预处理;

​ (3)文件数据提取;

​ (4)文件行列转换;

​ (5)文件某行或某列聚合(加法、乘法、列表);

​ (6)根据数据某一列排序;

​ (7)文件数据采集后处理;

​ (8)文件数据入库前处理;

​ (9)文件数据导入数据库;

​ (10)数据入库前处理;

​ (11)数据入库后处理。

技术点

​ POI、XML、Java反射(可以用spring替代)

实现说明

​ XML文件中可以定义多个采集子项目,每个采集子项目中可以定义多个文件采集任务,文件采集选项使用名称正则匹配。其中可以定义多个文件处理器,如文件校验,文件采集前置处理,后置处理,入库逻辑处理等。代码也可配置到xml文件中,实现处理逻辑的灵活选择,xml中也可以定义文件数据采集逻辑。

定义xml文件
<CollectFileCfg>
    <SubItems>
        <SubItem name="item1">
            <FileOptions>
                <FileOption name="\d{4}?日前联络线计划\d{4}-\d{2}-\d{2}总加.xls" suffix=".xls" dir="" toDir="" mode="row" group="true" header="true">
<!--                    暂时未扩展的功能-->
<!--                    <Parameters>-->
<!--                        <Parameter key="" value="" type=""/>-->
<!--                    </Parameters>-->
                    <MatchFileMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="matchFileMethodTemplate" ref="0"/>
                    </MatchFileMethod>
                    <ValidFileMethods>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="vaildMethodTemplate" ref="0"/>
                    </ValidFileMethods>
<!--                    抽取前文件处理 参照样例方法-->
                    <PreHandleFileMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="fileMethodTemplate" ref="0"/>
                    </PreHandleFileMethod>
<!--                    可代替实际抽取逻辑的方法配置 参照样例方法-->
                    <HandleFileMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="fileMethodTemplate" ref="0"/>
                    </HandleFileMethod>
                    <Sheets>
                        <Sheet index="0">
<!--                            <Grids>-->
<!--                                <Grid column="1"></Grid>-->
<!--                                <Grid column="3"></Grid>-->
<!--                            </Grids>-->
                            <Groups>
                                <Group by="0" collect="3" sort="2" operator="list">
<!--                                    <Method class="com.fp.databasepmtest.collect.util.FieldTransMethod" name="getGroup"/>-->
                                </Group>
                            </Groups>
                        </Sheet>
                    </Sheets>
                    <!--                    抽取后文件处理 参照样例方法-->
                    <AfterHandleFileMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="fileMethodTemplate" ref="0"/>
                    </AfterHandleFileMethod>
                    <!--                    入库前文件处理 参照样例方法-->
                    <PreLoadTableMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="fileMethodTemplate" ref="1"/>
                    </PreLoadTableMethod>
                    <!--                    入库文件处理 可代替入库 参照样例方法-->
                    <LoadTableMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="loadMethodTemplate" ref="1"/>
                    </LoadTableMethod>
                    <Tables>
                        <Table id="1" name="market_publish_point" dir="E:\test_table.csv" sheet="0" isLoad="true">
                            <Fields>
                                <Field name="id" type="UUID">
                                    <Method class="com.fp.databasepmtest.collect.util.FieldTransMethod" name="getIdByDate" args="1"/>
                                </Field>
                            </Fields>
                        </Table>
                    </Tables>
                    <!--                    入库后文件处理 参照样例方法-->
                    <AfterLoadTableMethod>
                        <Method class="com.fp.collect.util.FieldTransMethod" name="loadMethodTemplate" ref="1"/>
                    </AfterLoadTableMethod>
                </FileOption>
            </FileOptions>
        </SubItem>
    </SubItems>
</CollectFileCfg>
Xsd校验xml

​ 可以在xsd文件中定义xml文件节点的具体格式与数据类型校验。

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:complexType name="FieldType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Method" type="MethodType" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string" use="required"/>
        <xs:attribute name="type" type="TypeType"/>
        <xs:attribute name="collect" type="IntStringType"/>
    </xs:complexType>

    <xs:simpleType name="TypeType">
        <xs:restriction base="xs:string">
            <xs:pattern value="String|char|int|long|BigDecimal|double|float|UUID|date"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="MethodType">
        <xs:attribute name="class" type="xs:string"/>
        <xs:attribute name="name" type="xs:string"/>
        <xs:attribute name="args" type="xs:string"/>
        <xs:attribute name="ref" type="xs:string"/>
    </xs:complexType>

    <xs:complexType name="FieldsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Field" type="FieldType" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="TableType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Fields" type="FieldsType"/>
        </xs:sequence>
        <xs:attribute name="id" type="xs:int" use="required"/>
        <xs:attribute name="name" type="xs:string" use="required"/>
        <xs:attribute name="dir" type="xs:string"/>
        <xs:attribute name="sheet" type="xs:int" use="required"/>
        <xs:attribute name="isLoad" type="xs:boolean" use="required"/>
    </xs:complexType>

    <xs:complexType name="TablesType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Table" type="TableType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="GridType">
        <xs:attribute name="row" type="IntStringType"/>
        <xs:attribute name="column" type="IntStringType"/>
        <xs:attribute name="type" type="TypeType"/>
        <xs:attribute name="format" type="xs:string"/>
    </xs:complexType>

    <xs:complexType name="SheetType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Grids" type="GridsType" minOccurs="0"/>
            <xs:element name="Groups" type="GroupsType" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="index" type="xs:int" use="required"/>
    </xs:complexType>

    <xs:simpleType name="IntStringType">
        <xs:restriction base="xs:string">
            <xs:pattern value="\d"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="GridsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Grid" type="GridType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="SheetsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Sheet" type="SheetType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="FileOptionType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Parameters" type="ParametersType" minOccurs="0"/>
            <xs:element name="MatchFileMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="ValidFileMethods" type="methodsType" minOccurs="0"/>
            <xs:element name="PreHandleFileMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="HandleFileMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="Sheets" type="SheetsType"/>
            <xs:element name="AfterHandleFileMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="PreLoadTableMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="LoadTableMethod" type="methodsType" minOccurs="0"/>
            <xs:element name="Tables" type="TablesType"/>
            <xs:element name="AfterLoadTableMethod" type="methodsType" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string"/>
        <xs:attribute name="suffix" type="SuffixType" use="required"/>
        <xs:attribute name="dir" type="xs:string"/>
        <xs:attribute name="toDir" type="xs:string"/>
        <xs:attribute name="rename" type="xs:string"/>
        <xs:attribute name="protocol" type="ProtocolType"/>
        <xs:attribute name="mode" type="ModeType" use="required"/>
        <xs:attribute name="group" type="BoolStringType" use="required"/>
        <xs:attribute name="header" type="BoolStringType" use="required"/>
    </xs:complexType>

    <xs:simpleType name="SuffixType">
        <xs:restriction base="xs:string">
            <xs:pattern value=".xls|.xlsx"/>
        </xs:restriction>
    </xs:simpleType>
    
    <xs:complexType name="ParametersType">
        <xs:sequence minOccurs="0" maxOccurs="unbounded">
            <xs:element name="Parameter" type="ParameterType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="ParameterType">
        <xs:attribute name="key" type="xs:string" use="required"/>
        <xs:attribute name="value" type="xs:string" use="required"/>
        <xs:attribute name="type" type="TypeType" use="required"/>
    </xs:complexType>

    <xs:complexType name="methodsType">
        <xs:sequence minOccurs="0" maxOccurs="unbounded">
            <xs:element name="Method" type="MethodType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="BoolStringType">
        <xs:restriction base="xs:string">
            <xs:enumeration value="true"/>
            <xs:enumeration value="false"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="GroupsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Group" type="GroupType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="GroupType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="Method" type="MethodType" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="by" type="IntStringType" use="required"/>
        <xs:attribute name="sort" type="IntStringType"/>
        <xs:attribute name="collect" type="IntStringType" use="required"/>
        <xs:attribute name="operator" type="OperatorType"/>
    </xs:complexType>

    <xs:simpleType name="OperatorType">
        <xs:restriction base="xs:string">
            <xs:pattern value="\+|\*|list"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="ProtocolType">
        <xs:restriction base="xs:string">
            <xs:pattern value="sftp|local|io"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:simpleType name="ModeType">
        <xs:restriction base="xs:string">
            <xs:pattern value="row|column"/>
        </xs:restriction>
    </xs:simpleType>

    <xs:complexType name="FileOptionsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="FileOption" type="FileOptionType"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="SubItemType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="FileOptions" type="FileOptionsType" minOccurs="0"/>
        </xs:sequence>
        <xs:attribute name="name" type="xs:string"/>
    </xs:complexType>
    
    <xs:complexType name="SubItemsType">
        <xs:sequence maxOccurs="unbounded">
            <xs:element name="SubItem" type="SubItemType" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="CollectFileCfg">
        <xs:complexType>
            <xs:sequence maxOccurs="unbounded">
                <xs:element name="SubItems" type="SubItemsType"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>
Xml配置文件读取

​ 通过以下方法把xml文件中的数据注入到根节点对象中去。

private static final String COLLECT_FILE_CFG_XML_PATH = "classpath:collect/CollectFileCfg.xml";

    private static final String COLLECT_FILE_CFG_XSD_PATH = "collect/CollectFileCfgXsd.xml";

    private static final String COLLECT_FILE_CFG_XSD_TMP_PATH = "./CollectFileCfgXsd.xml";

    private static final CollectFileCfg COLLECTFILECFG = initCollectFileCfg();

    private static CollectFileCfg initCollectFileCfg() {
        try {
            // xsd文件在类文件路径下放置
            ClassPathResource classPathResource = new ClassPathResource(COLLECT_FILE_CFG_XSD_PATH);
            @Cleanup InputStream xsdFileInput = classPathResource.getInputStream();
            // xsd文件暂存
            File xsdFile = new File(COLLECT_FILE_CFG_XSD_TMP_PATH);
            FileUtils.copyInputStreamToFile(xsdFileInput, xsdFile);
            // 读取xml文件
            File xmlFile = ResourceUtils.getFile(COLLECT_FILE_CFG_XML_PATH);
            // xml文件跟节点对象上下文
            JAXBContext context = JAXBContext.newInstance(CollectFileCfg.class);
            // 创建xml文件对象解释器
            Unmarshaller unmarshaller = context.createUnmarshaller();
            // 导入xsd文件
            SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema schema = schemaFactory.newSchema(xsdFile);
            // 解释器设置校验xsd
            unmarshaller.setSchema(schema);
            return (CollectFileCfg) unmarshaller.unmarshal(xmlFile);
        } catch (IOException e) {
            logger.error("Get file failed. {}", e.getMessage());
            throw new RuntimeException("Get file failed.", e);
        } catch (SAXException saxException) {
            logger.error("Init xml schema failed. {}", saxException.getMessage());
            throw new RuntimeException("Init xml schema failed.", saxException);
        } catch (JAXBException jaxbException) {
            logger.error("Parse xml error. {}", jaxbException.getMessage());
            throw new RuntimeException("Parse xml error.", jaxbException);
        }
    }
节点对象定义

​ (1)根节点对象

@Data
@XmlRootElement(name = "CollectFileCfg")
@XmlAccessorType(XmlAccessType.FIELD)
public class CollectFileCfg {

    @XmlElement(name = "SubItem")
    @XmlElementWrapper(name="SubItems")
    private List<SubItem> subItems;
}

​ (2)子项目对象

@Data
@XmlRootElement(name = "SubItem")
@XmlAccessorType(XmlAccessType.FIELD)
public class SubItem {

    @XmlAttribute(name = "name")
    private String name;

    @XmlElement(name = "FileOption")
    @XmlElementWrapper(name = "FileOptions")
    private List<FileOption> fileOptions;
}

​ (3)文件处理对象

@Data
@XmlRootElement(name = "FileOption")
@XmlAccessorType(XmlAccessType.FIELD)
public class FileOption {

    @XmlAttribute(name = "name")
    private String name;

    @XmlAttribute(name = "suffix")
    private String suffix;

    @XmlAttribute(name = "dir")
    private String dir;

    @XmlAttribute(name = "toDir")
    private String toDir;

    @XmlAttribute(name = "rename")
    private String rename;

    @XmlAttribute(name = "protocol")
    private String protocol;

    @XmlAttribute(name = "mode")
    private String mode;

    @XmlAttribute(name = "group")
    private Boolean group;

    @XmlAttribute(name = "header")
    private Boolean header;

    @XmlElementWrapper(name = "Sheets")
    @XmlElement(name = "Sheet")
    private List<Sheet> sheets;

    @XmlElementWrapper(name = "Tables")
    @XmlElement(name = "Table")
    private List<Table> tables;

    @XmlElementWrapper(name = "Parameters")
    @XmlElement(name = "Parameter")
    private List<Parameter> parameters;

    @XmlElementWrapper(name = "ValidFileMethods")
    @XmlElement(name = "Method")
    private List<Method> validFileMethods;

    @XmlElementWrapper(name = "MatchFileMethod")
    @XmlElement(name = "Method")
    private List<Method> matchFileMethod;

    @XmlElementWrapper(name = "PreHandleFileMethod")
    @XmlElement(name = "Method")
    private List<Method> preHandleFileMethod;

    @XmlElementWrapper(name = "HandleFileMethod")
    @XmlElement(name = "Method")
    private List<Method> handleFileMethod;

    @XmlElementWrapper(name = "AfterHandleFileMethod")
    @XmlElement(name = "Method")
    private List<Method> afterHandleFileMethod;

    @XmlElementWrapper(name = "PreLoadTableMethod")
    @XmlElement(name = "Method")
    private List<Method> preLoadTableMethod;

    @XmlElementWrapper(name = "LoadTableMethod")
    @XmlElement(name = "Method")
    private List<Method> loadTableMethod;

    @XmlElementWrapper(name = "AfterLoadTableMethod")
    @XmlElement(name = "Method")
    private List<Method> afterLoadTableMethod;
}

………………

其他对象可以照这xml文件一一定义。

具体的业务逻辑代码有点多而且写的比较粗糙,这里只是提供一个思路,可以在码云上https://gitee.com/niudongjun_gitee/other.git excel-collect查看拉取。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值