什么是 EasyExcel
以前我都是用Apache poi
解析 Excel,但我不喜欢自己处理模型转换、数值类型转换,而且 poi 处理大 excel 时内存高。后来听说了阿里开源的 EasyExcel,决定试用下。
官方如此自我介绍:
快速、简单避免 OOM 的 Java 处理 Excel 工具
EasyExcel 是一个基于 Java 的简单、省内存的读写 Excel 的开源项目。在尽可能节约内存的情况下支持读写百 M 的 Excel。 github 地址:https://github.com/alibaba/easyexcel
引入依赖
我的 maven pom 文件如下
1 | <properties> |
极简读 Excel 示例
1. 数据类DemoBizExcelRow.java
,存储 excel 一行的数据
1 | // 使用lombok,或自己实现get/set |
2. 自定义数据行监听类DemoDataListener.java
,逐行解析数据
如果想要获得解析结果集的话,可以像下面这样通过构造函数传参来接收。如果要在监听类里完成 DB 存储操作,可以参考官方示例DemoDataListener.java
。
1 | public class DemoDataListener extends AnalysisEventListener<DemoBizExcelRow> { |
3. 使用
1 | String file = "D:\\Demo.xlsx"; |
使用起来不复杂,自己只要做两件事:1.定义数据类 2.自定义监听(用于获取 excel 内容,或者完成 dao 操作等等)
自定义读取 Excel
可是,在我自己的实际使用中,我还需要以下的功能:
- 表头有多行,每类业务表 excel 还互不相同
- 获取表头数据,至少包括排序、列名
- 校验部分表头名,以确保 excel 符合要求,如不符,直接退出
- 解析时数据校验,比如,必填项不能为空,特定列的值不能超出某个范围,特定列值通过 enum 转换
- 获取每行中所有错误列集合,然而,官方默认行为是,遇到某个单元格有误的时候忽略剩余单元格,跳到下一行
1. 返回结果类
上面的例子只返回了有效数据集合List<DemoExcelRow>
,而现在想要 a)有效数据 b)错误信息 c)表头信息,设计一个结果类处理起来更方便。
1 |
|
2. 数据类DemoExcelRow.java
1 | // 使用lombok,或自己实现get/set |
解读:
- 变量
subject
一个转换器,下面会说 - 变量
doubleData
通过注解@NumberFormat("#.##")
指定两位小数,通过@ExcelProperty(index = 5)
设定它在第 6 列 - 默认所有字段都会和 excel 匹配,通过
@ExcelIgnore
说明某变量不是 excel 中的字段 HEAD_ROW_NUMBER
真正的表头所在行HEAD_CHECK_MAP
用于表头校验的 map
3. 转换器
转换器SubjectConverter.java
将 excel 中的文本转成 enum 中的 1、2、3,如本例中,读到”应收账款”转存为 16。
下面的代码只有convertToJavaData()
被修改了,其他都是继承来的,IDE 会自动生成,所以这部分不写了。
1 | public class SubjectConverter implements Converter<String> { |
4. 自定义单元格解析的监听
ReadAllCellDataThrowExceptionLastListener.java
类照搬了官方ModelBuildEventListener.java
,只是将其中遇到错误格中止当前行剩余内容,改成了遇到错误不中止继续读完整行。
下面只写出被修改的函数,相同部分不写了,直接在ModelBuildEventListener.java
里抄了。
1 | public class ReadAllCellDataThrowExceptionLastListener extends |
5. 自定义数据行解析的监听
1 | public class MyBizDemoListener<T> extends AnalysisEventListener<T> { |
解读:
- 在
invokeHead()
中,借助构造函数传入的变量headCheckMap
校验 excel 表头 - 在
onException()
中,仅当throw exception
时才会终止 excel 解析,否则只是跳过到下一行 - 在
invoke()
中,处理必填项、数值合法性校验等等
6. 使用
1 | String file = "D:\\Demo.xlsx"; |
解读:
EasyExcel
默认提供了解析单元格的监听(即上面提到的ModelBuildEventListener.java
),如果要使用自定义的单元格解析监听,要先去掉默认useDefaultListener(false)
,再注册自己的registerReadListener(new ReadAllCellDataThrowExceptionLastListener())
- 在使用自定义单元格解析监听情况下,不能通过
EasyExcel.read()
传入自定义的行解析监听,只能通过registerReadListener()
注册,并且,(这一点很重要)要放在注册自定义单元格监听之后。
补充
格式转换
日期
1 |
|
- 2020/1/2 –> 1577894400000(即,2020-01-02)
- 你好 –> throw new Exception()
- // 转换失败时,会抛异常
1 |
|
- 2019/2/5 –> 2019-02-05
- 你好 –> 你好
- // 转换失败时,保持原值,不会抛异常
数值
1 |
|
- 1.2345 –> 1.23
- 你好 –> throw new Exception()
- // 转换失败时,会异常
1 |
|
- 1.2345 –> 1.23
- 你好 –> 你好
- // 转换失败时,保持原值,不会抛异常