前后端Excel处理篇——后端EasyExcel写操作入门
注:本文内容不包括EasyExcel写操作
文章大纲:
一、EasyExcel简介
Java领域解析,生成Excel比较有名的框架有Apache poi
、jslx
等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.
EasyExcel是阿里巴巴开源项目,基于Java的简单、省内存的Excel处理框架。
EasyExcel原理是通过POI的SAX模式,在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析,从而大大减少内存占用。
二、api
1、常用api
- EasyExcel 入口类,用于构建开始各种操作
- ExcelWriter 可以理解为一个工具类,直接完成
EasyWriterBuilder
的创建、数据的写入等 - WriteWorkbook理解为Excel 工作簿、WriteSheet理解为Excel的sheet,WriteTable理解为sheet中的一块区域
- **WriteHandler ** 类似切面 在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据
所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel...sheet()方法之前作用域是整个sheet,之后针对单个sheet
2、注解
ExcelProperty
index 指定写到第几列,默认根据成员变量排序。value
指定写入的名称,默认成员变量的名字,多个value
可以参照快速开始中的复杂头ExcelIgnore
默认所有字段都会写入excel,这个注解会忽略这个字段DateTimeFormat
日期转换,将Date
写到excel会调用这个注解。里面的value
参照java.text.SimpleDateFormat
NumberFormat
数字转换,用Number
写excel会调用这个注解。里面的value
参照java.text.DecimalFormat
ExcelIgnoreUnannotated
默认不加ExcelProperty
的注解的都会参与读写,加了不会参与
3、源码体系结构
个人看EasyExcel
写操作相关源码,对EasyExcel
类体系结构的一个理解:
- builder:
ExcelWriterBuilder
、ExcelWriterSheetBuilder
等等,可以理解为最外层的构造器,配置执行逻辑,处于最上层 - exector 根据builder中的逻辑执行,内置了handler切面
- hander: 类似切面或Hook,在工作簿(WorkBook)、表(sheet)、行、单元格创建前后调用
三、怎么用
本部分只作为一个简要的引子,详细可看:官网写示例
1、直接写
(1)常规写
java
/**
* 实体类
*/
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
/**
* 忽略这个字段
*/
@ExcelIgnore
private String ignore;
}
/**
* 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 直接写即可
*/
@Test
public void simpleWrite() {
// 写法1
String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
// 写法2—— 推荐
fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, DemoData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
} finally {
// 千万别忘记finish 会帮忙关闭流
if (excelWriter != null) {
excelWriter.finish();
}
}
}
(2)自定义拦截器写
个人理解,EasyExcel 定义是简单、易用,但对于一些特殊的情况处理起来并不方便,且主要依赖拦截器实现。
写法:自定义一个实现拦截器接口的类,在这个类中写自己需要的逻辑。
java
/**
* 自定义实现拦截器接口的类
*/
private static class RowHandler implements RowWriteHandler {
@Override
public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, Integer relativeRowIndex, Boolean isHead) {
// 行创建之前执行逻辑代码
}
@Override
public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
// 行创建之后执行逻辑代码
}
@Override
public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
// 行处理完成后执行逻辑代码
}
}
2、模板写
Easyexcel
的填充功能比较基础,适用于一些常规结构(基础列表型数据)Excel的处理,对于复杂的Excel处理更推荐JSLX
进行处理。模板填充功能官网示例:https://www.yuque.com/easyexcel/doc/fill
四、总结
EasyExcel
适用于对性能有要求且Excel
是常规结构(基础列表型数据)的情形,它的API使用简易,但对于复杂Excel的处理主要依赖在拦截器中写业务逻辑实现,使用并不简便。