# ezimp2
**Repository Path**: rufeng521/ezimp2
## Basic Information
- **Project Name**: ezimp2
- **Description**: 简单高效的轻量级企业数据导入解决方案,为Excel大批量数据导入提供功能、易用性和性能支持。
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: https://gitee.com/hv0912/ezimp2
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 1
- **Created**: 2018-10-11
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
#### 项目介绍
##### 什么是 ezimp2 ?
这是一个个人开源项目,完全重写的 2.0 版本,前生是名为 `EasyImport v1.0` 的开源项目。致力于为企业项目中大批量的数据导入开发工作提供功能全面、上手简单,性能强悍以及扩展性完善的快速开发支持。
该框架在考虑高性能的同时,也充分考虑到了开发人员的使用体验,同时又有着极强的扩展性。尽可能平衡不同开发人员之间的能力差异,简单轻松地构建出一个完善的导入功能,亦可在框架的许可范围内进行个性化的定制开发以扩展功能。不论你想要如何使用该框架,它始终能够保证极高的性能。最主要的是:你现在不用再花费太多时间在数据导入功能的开发上了!
##### 提供哪些功能?
框架总体上提供了如下几个功能,有的功能是必须的,有的是可选的,这完全取决于开发者需要完成什么样的功能。
1. 基本的 Excel 数据读取功能
完全兼容 `Excel 97-2003 工作簿(\*.xls)` 和 `Excel 工作簿(\*.xlsx)`。同时,在读取 Excel 时,框架没有采用传统的读取方式(把整个 Excel 的数据直接读入内存中再进行解析)读取,传统的读取方式会消耗大量的系统内存资源,在高并发的情况下严重影响系统稳定性可可用性。框架的读取方式是通过 `事件驱动模型` 对 Excel 文件进行逐行扫描,逐行解析,在保证内存占用极低的前提下,大大提高了性能。
2. 强大的数据验证功能
框架提供了非常强大的数据验证功能,不但可以验证指定的数据是否满足数据类型的要求,还可以验证是否符合一些指定的规则,同时针对不同的数据类型可以有不同的验证规则,我们把“针对特定一个规则进行数据验证的过程”高度抽象为 `验证器` 。框架提供大部分常用的验证器,我们可以直接配置使用,但是如果开发者有特殊的需求,也可以通过实现对应的验证器接口来定制自己的验证器,只需要在使用的时候注册进框架即可。
3. 强大的数据格式化功能
在某些情况下我们需要对数据进行格式化处理,比如货币、时间日期、数字等,当然大多数企业级应用开发的环境下,我们可能需要进行数据字典转换,即把对应的值转换为数据字典中对应的代码。框架提供了数据格式化的支持,我们把他称作 `格式转换器` 。
4. 按需错误消息推送
框架提供 `错误消息处理器` ,在验证或格式化出错时会向外推送一个错误消息,详细地说明了错误数据的位置、错误原因等,请注意该错误消息不是异常。开发者可以根据需要自行选择是按照批次(单元格、行、工作簿或整个文件)进行推送。
5. 数据写入
处理完成的数据会分批次(单元格、行、工作簿或整个文件)发送给外部程序,这取决于开发者想要做什么。你可以直接输出来查看结果,也可以输出到一个新的 Excel 文件,甚至可以直接存入数据库中。框架默认提供了一个 `DatabaseWriter` 类,他的主要职责就是负责把处理完成后的数据写入数据库中。
6. 多种配置源
默认提供通过 `xml` 配置文件的方式进行导入配置,框架也提供了统一的接口,开发人员可以自行根据需要实现个性化的配置源读取方式,比如从数据库、json文件等各种形式来读取配置源。
7. 严格的配置源有效性验证与错误提示
不论开发人员最终选择通过何种方式来存储与读取配置,框架都会对配置源提供的参数进行严格的有效性验证和逻辑验证,在验证失败时会抛出 `ConfigException` 异常并提示产生异常的原因,防止由于配置源参数有误导致后续操作的级联错误。
8. 简单易用地实现方式
整个框架使用了典型的设计模式 `门面模式` 对外部提供一个统一的操作入口,只需要通过 ImportManager 类可以对框架的整个执行过程进行控制,而你不需要关心框架的具体实现细节。
#### 软件架构
该框架所有的开发和测试工作均在 JDK1.7 版本中完成,并且保证持续更新以及对未来 JDK 版本的支持,但是不提供向下(JDK1.7 以下版本)的兼容性。
#### 安装教程
使用该框架的同时,需要引入一些其他的开源库,框架与其他开源库的依赖关系如下:
```
com.vimhe:ezimp2-core:2.0.0-RELEASE
org.apache.poi:poi-ooxml:3.17
org.apache.poi:poi:3.17
commons-codec:commons-codec:1.10
org.apache.commons:commons-collections4:4.1
org.apache.poi:poi-ooxml-schemas:3.17
org.apache.xmlbeans:xmlbeans:2.6.0
stax:stax-api:1.0.1
com.github.virtuald:curvesapi:1.04
```
##### 手动构建
你可以去 [MAVEN仓库](http://mvnrepository.com/) 下载该框架以及相关依赖库的 jar 版本二进制文件。
##### 使用 MAVEN 构建
如果你的项目使用 MAVEN 作为构建工具,那么只需要加入如下依赖配置即可:
```
com.vimhe
ezimp2-core
2.0.0-RELEASE
```
你不需要再做任何配置,构建工具会帮你把相关的依赖库一并整合进来。
##### 使用 GRADLE 构建
如果你的项目使用 GRADLE 作为构建工具,那么只需要加入如下依赖配置即可:
```
// https://mvnrepository.com/artifact/com.vimhe/ezimp2-core
compile group: 'com.vimhe', name: 'ezimp2-core', version: '2.0.0-RELEASE'
```
你不需要再做任何配置,构建工具会帮你把相关的依赖库一并整合进来。
#### 使用说明
##### 配置源
该框架的所有工作都是从一个配置源开始的,框架默认支持了 xml 形式的配置源,你可以直接编辑配置文件以让框架工作。下面是一个通用的配置:
```xml
```
###### configuration
整个配置文件的根元素,指定配置的名空间。
###### file
表示一个Excel模板文件的配置,可以配置多个,代表多个模板文件。
| 配置项 | 参数类型 | 是否必须 | 默认值 | 说明 |
| :----: | :------: | :------: | :----: | :--------------------------- |
| index | 字符串 | 是 | | 文件索引名,用于标识一个文件 |
| path | 字符串 | 否 | | 文件所在路径 |
| format | 字符串 | 否 | xlsx | 文件格式,可选:xls、xlsx |
###### sheet
表示一个工作簿的配置,可以配置多个,代表多个工作簿。
| 配置项 | 参数类型 | 是否必填 | 默认值 | 说明 |
| :----: | :------: | :------: | :----: | --------------------------------------- |
| index | 整数 | 是 | | 工作簿索引,从1开始 |
| table | 字符串 | 否 | | 对应数据库中的表名 |
| create | 布尔值 | 否 | false | 是否在数据库中自动创建“table”中指定的表 |
###### row
表示行的配置,一个工作簿只能配置一个,因为所有行的配置都是一样的。
| 配置项 | 参数类型 | 是否必填 | 默认值 | 说明 |
| :----: | :------: | :------: | :-----: | ------------------------------------------------------------ |
| start | 整数 | 否 | 2 | 从哪一行开始读取,一般情况下第一行为表头 |
| end | 整数 | 否 | 1048576 | 读取到哪一行结束,当数值大于工作簿中的实际数据行数时,以实际数据行数为准 |
###### column
表示某一列的配置,可以配置多个,代表一行中的多个列。
| 配置项 | 参数类型 | 是否必填 | 默认值 | 说明 |
| :------: | :------: | :------: | :--------------: | ------------------------------------------------------------ |
| index | 字符串 | 是 | | 单元格索引,例如“A”、“B”、“AB” |
| column | 字符串 | 否 | | 对应数据库中表的列名 |
| type | 字符串 | 否 | java.lang.String | 指定该字段的数据类型,可选值如下:
java.lang.String
java.lang.Boolean
java.lang.Byte
java.lang.Short
java.lang.Integer
java.lang.Long
java.lang.Float
java.lang.Double
java.math.BigInteger
java.math.BigDecimal
java.util.Date
java.sql.Date
java.sql.Timestamp |
| readable | 布尔值 | 否 | true | 是否读取该字段 |
###### validator
表示一个验证器的配置,可以配置多个,代表一个列对应的验证器。
| 配置项 | 参数类型 | 是否必填 | 默认值 | 说明 |
| :-----: | :------: | :------: | :------------------: | -------------------- |
| name | 字符串 | 是 | | 验证器名称 |
| value | 字符串 | 否 | | 验证器验证参数 |
| message | 字符串 | 否 | 数据不符合要求的规范 | 验证失败后的错误消息 |
###### formatter
表示一个格式转换器的配置,可以配置多个,代表一个列对应的格式转换器。
| 配置项 | 参数类型 | 是否必填 | 默认值 | 说明 |
| :-----: | :------: | :------: | :------------------: | -------------------- |
| name | 字符串 | 是 | | 验证器名称 |
| value | 字符串 | 否 | | 验证器验证参数 |
| message | 字符串 | 否 | 数据不符合要求的规范 | 验证失败后的错误消息 |
##### 数据验证
框架默认提供了如下几种验证器:
| 验证器名称 | 说明 |
| ---------------------- | ------------------------------------------------------------ |
| nullable | 该字段是否可以为空 |
| stringLength | 字段长度是否等于指定长度 |
| stringMinLength | 字段长度是否不小于指定长度 |
| stringMaxLength | 字段长度是否不大于指定长度 |
| stringStartWith | 字段内容是否以指定的字符串开头 |
| stringEndWith | 字段内容是否以指定的字符串结尾 |
| stringContains | 字段内容是否包含指定的字符串 |
| stringEquals | 字段内容是否等于指定字符串 |
| stringEqualsIgnoreCase | 字段内容是否等于指定字符串(忽略大小写) |
| stringSeparator | 验证内容是否可以通过指定的分隔符分隔 |
| stringPattern | 字段内容是否满足指定的正则表达式 |
| numberEquals | 字段内容是否是数字并与指定的数字相等 |
| numberMin | 字段内容是否是数字并大于或等于指定的数字 |
| numberMax | 字段内容是否是数字并小于或等于指定的数字 |
| datetimeStart | 字段内容是否是时间或日期格式,是否在指定的时间之后(包含指定时间) |
| datetimeEnd | 字段内容是否是时间或日期格式,是否在指定的时间之前(包含指定时间) |
| datetimeBefore | 字段内容是否是时间或日期格式,是否在指定的时间之前(不包含指定时间) |
| datetimeAfter | 字段内容是否是时间或日期格式,是否在指定的时间之后(不包含指定时间) |
同时框架还提供了如下几种扩展:
| 验证器名称 | 说明 |
| ------------ | -------------------------------------------- |
| customEmail | 字段内容是否是有效的电子邮箱地址格式 |
| customIdCard | 字段内容是否是有效的身份证号(含15位和18位) |
| customIp | 字段内容是否是有效的IP地址(仅限ipv4) |
| customPhone | 字段内容是否是有效的手机号格式 |
开发者可以使用上面列表中的验证器对数据进行验证,可以把多个验证组合起来使用,也可以单独使用。在大多数情况下,这些验证器已经满足了需求,如果仍然有部分特殊情况的话,框架提供了强大的扩展接口来实现自定义。
下面是一个用来验证数据是否等于指定内容的自定义验证器,并实现验证器注册和使用:
```java
/**
* 通过创建自己的验证器类并继承抽象验证器类来实现相应的验证方法
* 这里的泛型 代表期望验证的数据类型,你不必在验证方法中手动转换,框架会尝试去做这样的事情
*/
public final class MyStringValidator extends AbstractValidator {
/**
* 为验证器设置一个名称
*
* @return 设置的验证器名称
*/
@Override
protected String validatorName() {
return "myStringValidator";
}
/**
* 具体的验证方法
*
* @param cellValue 单元格数据
* @param configValue 验证器值
* @return 验证成功返回true,否则返回false
*/
@Override
protected boolean validateValue(String cellValue, String configValue) {
return Objects.equals(cellValue, configValue);
}
}
```
然后在配置中指定使用该验证器:
```xml
```
别忘了在程序中进行注册:
```java
class Main {
public static void main(String[] args)
throws OpenXML4JException, SAXException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
new ImportManager("file1",
"xlsx",
classLoader.getResourceAsStream("data.xlsx"),
new ImportConfig(new XmlConfigSource()),
new DataHandler() {
@Override
public void onSheetError(List errorMessages) {
super.onSheetError(errorMessages);
for (ErrorMessage errorMessage : errorMessages) {
System.out.println(errorMessage);
}
}
@Override
public void write(SheetData sheetData, SheetConfig sheetConfig) {
super.write(sheetData, sheetConfig);
for (RowData rowData : sheetData.getValue().values()) {
System.out.println(rowData.getValue());
}
}
})
.addValidator(new MyStringValidator())
.process();
}
}
```
其中 `.addValidator(new MyStringValidator())` 这行就是对自定义验证器的注册。
##### 数据格式化
。。。
##### 错误消息处理
。。。
##### 数据处理
。。。