SpringBoot|SpringBoot 实现 excel 全自由导入导出,性能强的离谱,用起来还特优雅
一、简介
在实际的业务系统开发过程中,操作 Excel 实现数据的导入导出基本上是个非常常见的需求。
之前,我们有介绍一款非常好用的工具:EasyPoi,有读者提出在数据量大的情况下,EasyPoi 会占用内存大,性能不够好,严重的时候,还会出现内存异常的现象。
今天我给大家推荐一款性能更好的 Excel 导入导出工具:EasyExcel,希望对大家有所帮助!
easyexcel 是阿里开源的一款 Excel导入导出工具,具有处理速度快、占用内存小、使用方便的特点,底层逻辑也是基于 apache poi 进行二次开发的,目前的应用也是非常广!
文章图片
相比 EasyPoi,EasyExcel 的处理数据性能非常高,读取 75M (46W行25列) 的Excel,仅需使用 64M 内存,耗时 20s,极速模式还可以更快!
文章图片
废话也不多说了,下面直奔主题!
二、实践
在 SpringBoot 项目中集成 EasyExcel 其实非常简单,仅需一个依赖即可。
com.alibaba
easyexcel
3.0.5
EasyExcel 的导出导入支持两种方式进行处理
- 第一种是通过实体类注解方式来生成文件和反解析文件数据映射成对象
- 第二种是通过动态参数化生成文件和反解析文件数据
简单导出 首先,我们只需要创建一个
UserEntity
用户实体类,然后添加对应的注解字段即可,示例代码如下:public class UserWriteEntity {@ExcelProperty(value = "https://www.it610.com/article/姓名")
private String name;
@ExcelProperty(value = "https://www.it610.com/article/年龄")
private int age;
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "https://www.it610.com/article/操作时间")
private Date time;
//set、get...
}
然后,使用 EasyExcel 提供的
EasyExcel
工具类,即可实现文件的导出。public static void main(String[] args) throws FileNotFoundException {
List dataList = new ArrayList<>();
for (int i = 0;
i < 10;
i++) {
UserWriteEntity userEntity = new UserWriteEntity();
userEntity.setName("张三" + i);
userEntity.setAge(20 + i);
userEntity.setTime(new Date(System.currentTimeMillis() + i));
dataList.add(userEntity);
}
//定义文件输出位置
FileOutputStream outputStream = new FileOutputStream(new File("/Users/panzhi/Documents/easyexcel-export-user1.xlsx"));
EasyExcel.write(outputStream, UserWriteEntity.class).sheet("用户信息").doWrite(dataList);
}
运行程序,打开文件内容结果!
文章图片
简单导入 这种简单固定表头的 Excel 文件,如果想要读取文件数据,操作也很简单。
以上面的导出文件为例,使用 EasyExcel 提供的
EasyExcel
工具类,即可来实现文件内容数据的快速读取,示例代码如下:首先创建读取实体类
/**
* 读取实体类
*/
public class UserReadEntity {@ExcelProperty(value = "https://www.it610.com/article/姓名")
private String name;
/**
* 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
*/
@ExcelProperty(index = 1)
private int age;
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
@ExcelProperty(value = "https://www.it610.com/article/操作时间")
private Date time;
//set、get...
}
然后读取文件数据,并封装到对象里面
public static void main(String[] args) throws FileNotFoundException {
//同步读取文件内容
FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-user1.xls"));
List list = EasyExcel.read(inputStream).head(UserReadEntity.class).sheet().doReadSync();
System.out.println(JSONArray.toJSONString(list));
}
运行程序,输出结果如下:
[{"age":20,"name":"张三0","time":1616920360000},{"age":21,"name":"张三1","time":1616920360000},{"age":22,"name":"张三2","time":1616920360000},{"age":23,"name":"张三3","time":1616920360000},{"age":24,"name":"张三4","time":1616920360000},{"age":25,"name":"张三5","time":1616920360000},{"age":26,"name":"张三6","time":1616920360000},{"age":27,"name":"张三7","time":1616920360000},{"age":28,"name":"张三8","time":1616920360000},{"age":29,"name":"张三9","time":1616920360000}]
动态自由导出导入 在实际使用开发中,我们不可能每来一个 excel 导入导出需求,就编写一个实体类,很多业务需求需要根据不同的字段来动态导入导出,没办法基于实体类注解的方式来读取文件或者写入文件。
因此,基于
EasyExcel
提供的动态参数化生成文件和动态监听器读取文件方法,我们可以单独封装一套动态导出导出工具类,省的我们每次都需要重新编写大量重复工作,以下就是小编我在实际使用过程,封装出来的工具类,在此分享给大家!- 首先,我们可以编写一个动态导出工具类
public class DynamicEasyExcelExportUtils {private static final Logger log = LoggerFactory.getLogger(DynamicEasyExcelExportUtils.class);
private static final String DEFAULT_SHEET_NAME = "sheet1";
/**
* 动态生成导出模版(单表头)
* @param headColumns 列名称
* @returnexcel文件流
*/
public static byte[] exportTemplateExcelFile(List headColumns){
List excelHead = Lists.newArrayList();
headColumns.forEach(columnName -> { excelHead.add(Lists.newArrayList(columnName));
});
byte[] stream = createExcelFile(excelHead, new ArrayList<>());
return stream;
}/**
* 动态生成模版(复杂表头)
* @param excelHead列名称
* @return
*/
public static byte[] exportTemplateExcelFileCustomHead(List excelHead){
byte[] stream = createExcelFile(excelHead, new ArrayList<>());
return stream;
}/**
* 动态导出文件(通过map方式计算)
* @param headColumnMap有序列头部
* @param dataList数据体
* @return
*/
public static byte[] exportExcelFile(LinkedHashMap headColumnMap, List
- 然后,编写一个动态导入工具类
/**
* 创建一个文件读取监听器
*/
public class DynamicEasyExcelListener extends AnalysisEventListener
- 动态导入工具类
/**
* 编写导入工具类
*/
public class DynamicEasyExcelImportUtils {
/**
* 动态获取全部列和数据体,默认从第一行开始解析数据
* @param stream
* @return
*/
public static List parseExcelToView(byte[] stream) {
return parseExcelToView(stream, 1);
}
/**
* 动态获取全部列和数据体
* @param streamexcel文件流
* @param parseRowNumber指定读取行
* @return
*/
public static List parseExcelToView(byte[] stream, Integer parseRowNumber) {
DynamicEasyExcelListener readListener = new DynamicEasyExcelListener();
EasyExcelFactory.read(new ByteArrayInputStream(stream)).registerReadListener(readListener).headRowNumber(parseRowNumber).sheet(0).doRead();
List> headList = readListener.getHeadList();
if(CollectionUtils.isEmpty(headList)){
throw new RuntimeException("Excel未包含表头");
}
List> dataList = readListener.getDataList();
if(CollectionUtils.isEmpty(dataList)){
throw new RuntimeException("Excel未包含数据");
}
//获取头部,取最后一次解析的列头数据
Map excelHeadIdxNameMap = headList.get(headList.size() -1);
//封装数据体
List excelDataList = Lists.newArrayList();
for (Map dataRow : dataList) {
Map rowData = https://www.it610.com/article/new LinkedHashMap<>();
excelHeadIdxNameMap.entrySet().forEach(columnHead -> {
rowData.put(columnHead.getValue(), dataRow.get(columnHead.getKey()));
});
excelDataList.add(rowData);
}
return excelDataList;
}
/**
* 文件导入测试
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileInputStream inputStream = new FileInputStream(new File("/Users/panzhi/Documents/easyexcel-export-user5.xlsx"));
byte[] stream = IoUtils.toByteArray(inputStream);
List dataList = parseExcelToView(stream, 2);
System.out.println(JSONArray.toJSONString(dataList));
inputStream.close();
}
}
为了方便后续的操作流程,在解析数据的时候,会将列名作为
key
!三、小结
在实际的业务开发过程中,根据参数动态实现 Excel 的导出导入还是非常广的。
当然,EasyExcel 的功能还不只上面介绍的那些内容,还有基于模版进行 excel的填充,web 端 restful 的导出导出,使用方法大致都差不多,更多的功能,会在后续的文章中再次介绍,如果有描述不对的地方,欢迎网友批评吐槽!
四、参考
【SpringBoot|SpringBoot 实现 excel 全自由导入导出,性能强的离谱,用起来还特优雅】1、easyexcel - 接口文档
推荐阅读
- 详解Swin Transformer核心实现,经典模型也能快速调优
- 如何用set实现一个抽奖
- netty实战|Netty进阶 -- 非阻塞网络编程 实现群聊+私聊+心跳检测系统
- 前后端分离|前后端分离 -- 深入浅出 Spring Boot + Vue + ElementUI 实现相册管理系统【文件上传 分页 】 文件上传也不过如此~
- 前后端分离|前后端分离 --- 深入浅出Spring Boot + Vue实现员工管理系统 Vue如此简单~
- Python|Python实现八大经典排序算法
- 排序算法|Java实现十大经典排序算法--上
- C++实现三子棋游戏详细介绍(附代码)
- SpringBoot|SpringBoot +DynamicDataSource切换多数据源的全过程
- mybatisPlus实现倒序拼接字符串