1.16.二向箔:Excel

谁能亨鱼?溉之釜鬵。谁将西归?怀之好音。——佚名 先秦《匪风》

数据文件:data.test.xlsx

    本章节讲解Zero中另外一个比较重要的插件zero-ifx-excel,它可以帮助您将Excel中的数据快速导入系统中,同时在上传下载过程中也可以帮您很快完成导入导出编程。

「壹」基本配置

    先在您的Maven的pom.xml中引入下边依赖片段:

    <dependency>
        <groupId>cn.vertxup</groupId>
        <artifactId>zero-ifx-excel</artifactId>
    </dependency>

1.1. Excel模板

    Zero中的一个Excel模板格式如下:

    该模板的注意事项:

  1. 一个Sheet中可以包含多个{TABLE}的起始区域,边界计算条件如:

    • 左边界:从左往右扫描的第一个出现了{TABLE}的列。

    • 上边界:从上往下扫描的第一个出现了{TABLE}的列。

    • 右边界:{TABLE}行右边横跨的列总数(如上图)——一定要合并单元格

    • 下边界:下边没有数据的行的上一行。

  2. 一个Workbook中可以包含多个Sheet,且{TABLE}后一个单元格表示了当前程序应该导入到哪一张数据表中,如示例中会导入到X_APP表。

  3. 字段描述一般为中文,提供给人阅读,而字段名不是表中的列名,而是和表绑定的Java Pojo类的属性名,例:

    |表名|列名|属性名(字段名)|字段描述| |---|---|---|---| |X_APP|NAME|name|应用名称| |X_APP|PORT|port|应用端口号|

    当然若您不想使用Zero中提供的导入功能以及和Jooq绑定的数据访问功能,那就只有直接使用ExcelInfix 结构来执行纯粹的编码模式了,Zero中的Excel使用了Apache POI4.x版本,你可以独立开发,像前文提到过的集成插件一样,也可以直接借着本章的内容直接实现导入。一个Excel模板的示例截图如下:

Zero中导入和导出的文件模板是一致的,只要数据准备无误,那么就可导入数据到系统。

1.2. Zero配置

    提供了数据模板后,您需要在Zero中打开-excel的配置(假设您已经完成了VertxDAO的生成流程,参考Jooq章节):

vertx.yml

vertx-excel.yml

0.8.0之后的版本变化,移除了pojo/dao两个属性

vertx-inject.yml

1.3. 导入测试

    将数据文件放到您的src/main/resources/init/目录中:

    在您的IDEA中开发普通启动类:

    创建对应的运行配置:

    这样配置后,您就可以在运行的控制台看到如下信息:

    运行完成后,查看您的数据库(数据已经进入系统):

    这是最简单的一种场景,直接将一个Excel中{TABLE}区域的数据导入到数据表X_TABULAR中,但这种场景对OOB数据的基础数据导入尤其有效,您可以放一批数据文件在init 目录中,然后直接运行上述程序实现批量的数据导入。在输出中您不仅可以看到读取的数据量以及文件,还可以看到线程名称,整个过程是多线程运行的(一个数据文件一个线程)。

    由于vertx-excel.yml文件中已经配置过key和unique,所以您可以再执行该程序,不论最终您执行多少次,数据库中的数据一直都只有7条。

「贰」开发场景

2.1. ExcelClient获取

本节省略了部分配置,请把第一章节阅读完了再进行本章节的示例程序编写。

    不可否认,zero-ifx-excel和Shell部分不同,Excel功能里多了一个Infix插件——这意味着您可以使用插件模式直接在Worker组件中使用它的客户端。先看一段代码:

    测试上述程序您会得到类似如下响应:

请求:GET /hi/excel/hello?name=Lang

    如此您就可以在Agent组件和Worker组件中直接使用ExcelClient了,有了该Client就可以直接操作Excel文件,而它的配置不需要那么复杂的部分,仅需vertx-inject.yml 中的代码段即可:

    除此之外,您同样可以使用下边代码段读取ExcelClient引用(插件的两种获取方式):

    本小节最后附上ExcelInfix的源代码,让读者再回顾一下Zero中插件Infix的详细开发流程:

    上述ExcelInfix比其他Infix多出了一个createClient的方法,主要是为独立环境(不启动Zero容器的工具环境)的导入导出量身打造,而这个方法在Bt中一直在使用。

2.2. ExcelClient的API

    ExcelClient的API函数主要有三种:

函数前缀
依赖Jooq
含义

ingest

读取Excel文件。

export

将数据导出成Excel模板。

import

从Excel文件读取数据导入到对应表中。

    上述API中只有import系列的API是需要和Jooq绑定的,否则即使可以从Excel中读取数据,也无法执行后续导入流程,该Jooq绑定位于vertx-excel.yml 中的mapping配置中。

2.2.1. ingest

    ingest前缀API定义如下:

2.2.2. export

    export前缀的API定义如下:

导出不支持同步模式,但异步转同步可直接在外层使用回调,而Zero本身大部分地方都是异步。

2.2.3. import

    import前缀的API定义如下:

2.2.4. 汇总

    上边的API定义比较统一,于是汇总说明下:

  1. 输入参数为filename时,系统直接通过后缀名.xlsx.xls判断是2007格式还是2003格式,推荐使用2007格式,.xls格式在导入时部分功能可能会有问题。

  2. 输入参数为InputStream时,系统则直接通过isXlsx参数来判断格式,这种模式下无法读取输入字节流的后缀名。

  3. TypeAtom是Zero中定义的核心数据结构,用于描述字段、类型信息。

  4. ExTable是zero-ifx-excel定义的核心数据结构——虚拟表,用于描述导入的二维数据表,和它相对应的数据结构是ExRecord——虚拟记录

2.3. 核心数据结构

2.3.1. TypeAtom

    io.vertx.up.commune.element.TypeAtom是Zero中的类型定义核心数据结构,它的完整结构如下图:

    此处先解析下io.vertx.up.commune.element.TypeField类型,该类型主要包含两部分内容:

  1. 基础属性信息

    |属性名|类型|含义| |:---|---|:---| |name|String|当前字段的字段名称。| |alias|String|当前字段的别名,通常是文字描述。| |unique|Set<String>|如果是JsonArray,则该值用于标识唯一记录。| |type|Class<?>|当前字段的类型,一般是JsonObject或JsonArray。|

  2. 子属性信息

    |属性名|含义| |:---|:---| |children|一个List类型定义,以索引为键的类型定义,JsonArray专用。| |childMap|以name为键的类型定义,JsonObject专用。|

    在读取到的Excel模板信息中,如果出现了JsonArray、JsonObject两种复杂类型,那么TypeAtom中的complex = true ,这种情况下,那个复杂类型的字段会启用TypeField的复杂部分,并且在扫描模板时会启用复杂扫描算法扫描{TABLE}区域,这样就可以处理更复杂的导入结构。假设有下边Excel格式:

    该模板是复杂模板,启用了复杂扫描算法,最终生成的Json格式如:

    这种情况TypeAtom就显得十分重要了。注意 :这种模板只有在带有TypeAtom的API中会生效,我们产品中启用了动态建模功能,有专用组件生成每个模型对应的TypeAtom对象来执行复杂模板的导入和导出,而Zero框架本身并没有提供任何工具类可快速生成TypeAtom,您若想要导入复杂模板则可以自己生成这个对象。

2.3.2. ExTable

    虚拟表格io.vertx.tp.plugin.excel.atom.ExTable)是zero-ifx-excel{TABLE} 量身定制的一种数据结构,它的完整结构如下:

    上述结构中sheet属性就是当前ExTable所属Excel的sheet名称,而namedescription对应数据模板{TABLE} 行的内容,ExConnect则直接对应到vertx-excel.yml的mapping节点配置,一张表只拥有一个ExConnect,fieldsvalues就不解释了。

2.3.3. ExRecord

    最后一种核心数据结构io.vertx.tp.plugin.excel.atom.ExRecord相对比较简单,这里放出它的源代码让您去理解:

    前边章节学习过io.vertx.up.atom.Kv的键值对结构,而本章中的ExRecord和键值对的数据结构比较类似,唯一不同点在于:

  1. ExRecord包含了多个键值对。

  2. ExRecord的值执行了ExValue转换。

2.4. ExValue解析

    除了上述提到的所有功能以外,Zero中的zero-ifx-excel支持单元格的部分高级功能,它依赖ExValue执行解析。

2.4.1. 基础表达式

    基础表达式主要参考下边表格:

格式
含义

{UUID}

直接生成UUID格式的字符串,每次导入生成的值都不同。

JSON:前缀

读取JSON:之后的数据文件转换成JsonObject或JsonArray。

    第二种格式示例如:

    这些配置中,Zero会去读取src/main/resources根目录(生产环境就是当前目录)之下的对应数据文件,如果无法读取则为null。

2.4.2. Formula引用

    Formula引用表达式是Excel中的功能,而Zero中支持两种Formula表达式:

  1. 当前文件内的Formula表达式。

  2. 外联文件(额外的Excel文件)的Formula表达式。

    接下来演示外联文件(更复杂)的导入过程,在src/main/resources/init/目录中创建新的数据文件,内容如下:

    编辑data.test.xlsx中的sigma和appId字段:

    修改vertx-excel.yml配置:

    重新导入后查看数据库,使用Formula格式的单元格被解析了:

    如果您没有更改vertx-excel.yml配置文件内容,将收到类似如下异常信息:

    在最新的版本中,引入了新的引用配置alias,完整版如下:

    该配置是为了各种环境兼容而量身打造的,在Excel文件中若使用了Formula的表达式类型=XXX 格式,使用外联文件时外联文件的路径在设置中会使用相对路径,而使用了可嵌套的方法后,该路径有时候会被操作系统自动转换成绝对 路径,使用绝对路径时候它对应的根路径会有所变化,后期使用运维部署的手段可处理,目前临时的解决方案则是使用别名。

环境
根路径
含义

Development

src/main/resources

开发源代码环境,Excel中设置表达式的编辑环境。

Development

target/classes

开发运行环境,IDEA运行时的根路径。

Production

.

生产环境使用了java -jar的命令运行,则当前目录则是根路径。

「叁」小结

    到这里,有关zero-ifx-excel插件的内容就讲解得差不多了,它所支持的功能其实已经远远超过了Excel本身的内容,本文并没有讲解如何开发pen 来实现不同颜色模板的导出,但您可以查看配置类io.vertx.tp.plugin.excel.tpl.BlueTpl的源代码。

    从实战看来,Zero最好用的功能是JSON: 这个表达式,有了这个表达式的辅助过后,单元格的数据就不用采用JSON格式的字符串(Excel单元格无法对Json格式的数据做格式校验,并且无法高亮),而是直接引用外联文件,如此,单元格也可以实现重用某个数据文件的功能,这也是我们在开发过程中导数据最实用的功能。

Last updated