「这是我参与11月更文挑战的第20天,活动详情查看:2021最后一次更文挑战」
项目开发中,存在很多的业务需求要求对页面的相关数据进行导入和导出,而对于数据量较大的页面又要考虑在导出时不能影响到服务运行的稳定性,因此在选择数据导入导出框架时要考虑业务的需求。
对于低内存占用导出大量数据的情景、EasyExcel框架会有很好的效果实现。
1. EaseExcel
1.1 EaseExcel介绍
EasyExcel是一个基于Java的简单、省内存读写Excel的开源项目,EasyExcel是在Apache poi框架的基础上对其进行深度优化,减少Excel文件导入导出时对系统内存的占用,实现尽可能少的使用内存来完成上百M大小Excel文件的读写。
Apache poi在使用时会首先将文件加载到内存中进行操作,因此对于几十上百M的文件有可能会发生OOM内存溢出导致服务不可用,而EasyExcel优化可以实现20s读取75M文件只占用64M内存,有效的避免了OOM的发生。
1.2 EaseExcel学习
EasyExcel是alibaba公司开源的优秀框架,有优秀的开发人员在持续维护。可以通过EasyExcel的官方文档来学习使用,也可以下载项目源码来了解实现原理。
1.3 使用EaseExcel
项目中只需要引入EaseExcel的依赖信息,就可以编码使用Jar包中定义的类方法实现Excel文件的导入和导出。
<!-- EaseExcel的依赖信息 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
2. EasyExcel的导出实现
导出功能相比于导入有着更加广泛的使用,因此首先来学习EasyExcel中导出Excel的实现。
2.1 建立模型类
Java语言中,所有的数据是基于对象存在,而数据导出时也脱离不数据对象,因此首先要建立与导出数据结构相同的模型类。
定义一个简单的Java类来承载用户数据,使用lombok的@Data快速实现对象创建。
//创建数据模型,存放用户导出数据
@Data
public class UserModel {
private String id;
private String code;
private String name;
}
2.2 本地导出方法实现
本地简单实现Excel文件的导出时,只需要调用EasyExcel类中的相关方法定义导出文件的属性,并使用doWrite()设置导出数据后完成Excel的导出。
@Test
public void exportTemplate(){
List<UserModel> list = new ArrayList<>();
UserModel userModel = new UserModel();
userModel.setCode("123");
userModel.setName("tom");
list.add(userModel);
EasyExcel.write("用户数据.xlsx", UserModel.class)
.sheet("Sheet1")
.doWrite(list);
}
对于导出代码中的类方法,可以简单介绍为:
EasyExcel
作为工具类,继承EasyExcelFactory,以建造者模式设置Excel的属性,最终完成创建和导出write()
方法定义了文件导出路径信息pathName、以及使用哪个类class来写数据sheet()
方法可以对导出Excel的sheet指定名称doWrite()
用于指定Excel中的数据- 文件导出结束后文件流会自动关闭
3. EasyExcel导入的实现
Excel导入时就是对选择文件内容的读取操作,使用EasyExcel读取文件时的流程如下:
- 创建一个实体对象用来承载从文件中读取的数据,对象结构要和文件中数据一致
- 定义一个回调监听器,用于在一行一行读取数据时执行回调
- 通过EasyExcel读取文件
3.1 创建实体对象
创建方式与导出数据时一致,只要保证对象的属性与导入数据列一致即可。
//导入时不需要额外的列,导入导出也可以使用同一个实体类
@Data
public class UserModel {
private String code;
private String name;
}
3.2 定义监听器
EasyExcel要求定义一个监听器实现ReadListener类,其中T代表当前要导入的实体类,并实现其中的invoke()和doAfterAllAnalysed()两个方法。
invoke()
方法用于每次读取一行数据后回调doAfterAllAnalysed()
方法用于整个文件读取完成后回调
//导入时的监听器要针对每个导入对象类创建
public class UserModelListener implements ReadListener<UserModel> {
private static final Logger log = LoggerFactory.getLogger(UserModelListener.class);
@Override
public void invoke(UserModel userModel, AnalysisContext analysisContext) {
log.info("解析到一条数据:{}", userModel.toString());
//指定其他操作
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("所有数据解析完成!");
//指定其他操作
}
}
3.3 本地导入方法实现
定义好实体类和对应的回调监听器后,便可以使用EasyExcel来实现Excel文件的读取导入。
read()
方法用来指定读取文件的路径信息、读取实体类、回调监听器类等信息sheet()
方法用来指定读取文件中的sheet名称doRead()
方法则是执行读取操作,每读取一行数据便会执行一次回调
//基于指定路径文件、实体类、实体类的监听器实现导入操作
@Test
public void importExcel(){
EasyExcel.read("用户数据.xlsx", UserModel.class, new UserModelListener())
.sheet()
.doRead();
}