开源地址
GitHub - beijing-penguin/eventpoi: 事件流poi处理工具
<dependency>
<groupId>io.github.beijing-penguin</groupId>
<artifactId>eventpoi</artifactId>
<version>0.0.8</version>
</dependency>
知乎文案链接
eventpoi java百万级以上excel导入导出 - 知乎
优点
- 支持 【功能】 【读取excel/导入】excel文件高性能读取 并自动转java对象,只需一行代码
- 支持 【功能】 支持导出表格形式的excel文件,和列表excel文件
- 支持 【功能】 【图片导入】支持图片列和文本混合列形式的excel导入
- 支持 【功能】 【行回调异步处理】边读边处理,无须等待excel全部解析。
- 支持 【功能】 自动识别xls文件和xlsx文件格式
- 支持 【功能】 自动识别date列时间格式,无需像别的工具那样,时间字段上设置yyyyMMdd格式
- 支持 【功能】 复杂的表格导出,既包含【列表形式】的数据 也包含【表单形式】的数据导出(查看 "测试包含表格和列表数据的复杂导出.java" 文件)
- 支持 【特性】 使用事件驱动方式读取excel,无行数和内存限制。
- 支持 【特性】 高性能SXSSFWorkbook导出大文件,默认也是使用SXSSFWorkbook导出(导出20w行数据,仅需要3s)
对比阿里的EasyExcel,本开源工具具有如下优势(前两点是本开源的主要优势)
- 支持复杂结构的、可带图片的excel文件导出
- 支持复杂excel结构的图片导入
- 支持较新的poi版本,目前支持到了4.1.2
- 性能对比持平(100w导出,普通机器测试,耗时仅需十几秒。cpu好点的服务器,可能只有8~9秒)
- 操作更加简单,无需build构造实体,仅需一行代码调用静态方法
使用案例均能在开源代码的src/test/java目录下,直接main方法运行,使用中,如果遇到模板文件读取不到的FileNotFoundException情况,可能是因为不同IDE编译器编译路径文件不同导致,请自行调整代码(使用绝对磁盘路径如E:\\xx\\xx\\xx\\template.xlsx),保证能正确读到template.xlsx文件即可。
使用方法
新建一个需要导出的模板文件,如下
调用代码,使用一行代码读取excel(方法参数上需要传入上面定义好的模板文件),如下
package com.dc.eventpoi.test;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.dc.eventpoi.ExcelHelper;
public class 使用一行代码读取excel {
public static void main(String[] args) throws Exception {
List<Person> objList = ExcelHelper.parseExcelToObject(Test1.class.getResourceAsStream("demo1.xlsx"), Test1.class.getResourceAsStream("demo1Templete.xlsx"), Person.class);
System.err.println(JSON.toJSONString(objList,true));
}
}
同样的方式,传入模板文件以及自己的业务数据,使用一行代码导出excel,如下
package com.dc.eventpoi.test;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.dc.eventpoi.ExcelHelper;
import com.dc.eventpoi.core.PoiUtils;
public class 使用一行代码导出excel {
public static void main(String[] args) throws Exception {
List<Person> personList = new ArrayList<Person>();
//构造导出时的数据
for (int i = 0; i < 2000; i++) {
Person p1 = new Person();
p1.setNo("NO_"+i);
p1.setAge(11);
p1.setName("ssssss_"+i);
p1.setRemark("测试测试啊remar_"+i);
personList.add(p1);
}
//模拟一些需要删除某些列 的业务场景
byte[] newTempFile = PoiUtils.deleteCol(Test1.class.getResourceAsStream("demo1Templete.xlsx"), "${salary}");
long t1 = System.currentTimeMillis();
byte[] exportByteData = ExcelHelper.exportExcel(newTempFile, personList,0);
System.out.println("cost="+(System.currentTimeMillis()-t1));
//支持设置单元格样式噢!!!^_^
// byte[] exportByteData = ExcelHelper.exportExcel(Test1.class.getResourceAsStream("demo1Templete.xlsx"), personList,new CallBackCellStyle() {
// @Override
// public void callBack(CellStyle cellStyle) {
// cellStyle.setAlignment(HorizontalAlignment.CENTER); // 水平居中
// cellStyle.setVerticalAlignment(VerticalAlignment.CENTER); // 上下居中
// cellStyle.setBorderTop(BorderStyle.THIN);
// cellStyle.setBorderBottom(BorderStyle.THIN);
// cellStyle.setBorderLeft(BorderStyle.THIN);
// cellStyle.setBorderRight(BorderStyle.THIN);
// }
// }, "${salary}");
Files.write(Paths.get("./my_test_temp/测试导出指定对象并删除指定列.xlsx"), exportByteData);
}
}
下面看下比较复杂的excel结构的导出
模板文件,分2个区域,一个是列表数据区域,一个是表格数据区域,如下
下面的代码中,OrderInfo代表了占位符的表格数据区域,而List<ProductInfo>则代表了excel中列表形式的数据区域,那么代码如下:
package com.dc.eventpoi.test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import com.dc.eventpoi.ExcelHelper;
public class 测试包含表格和列表数据的复杂导出 {
public static void main(String[] args) throws Exception {
//列表或 表格的数据的集合
List<Object> excelDataList = new ArrayList<Object>();
//构造表格形式的数据
OrderInfo orderInfo = new OrderInfo();
orderInfo.setKehu("ddddcccc");
orderInfo.setOrderName("进口海鲜");
orderInfo.setTotalMoney("15.66");
orderInfo.setBuyer("张三");
orderInfo.setSaller("李四");
//添加表格数据 到大集合当中
excelDataList.add(orderInfo);
List<ProductInfo> productList = new ArrayList<ProductInfo>();
//构造导出时的数据
for (int i = 0; i < 20; i++) {
ProductInfo p1 = new ProductInfo();
p1.setNo("NO_"+i);
p1.setName("ssssss_"+i);
String img_file_path = new File(Test1.class.getResource("unnamed.jpg").getPath()).getAbsolutePath();
p1.setHeadImage(Files.readAllBytes(Paths.get(img_file_path)));
p1.setCaigouNum(i+10);
productList.add(p1);
}
//添加列表数据到大集合当中
excelDataList.add(productList);
//第三个参数表示,导出时,删除那些列(按模板文件中的key删除,可不传)
byte[] exportByteData = ExcelHelper.exportExcel(Test1.class.getResourceAsStream("订单_templete.xlsx"), excelDataList,0);
Files.write(Paths.get("./my_test_temp/测试包含表格和列表数据的复杂导出.xlsx"), exportByteData);
}
}
更复杂excel导出,如下面,需要动态合并单元格
package com.dc.eventpoi.test;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import com.dc.eventpoi.ExcelHelper;
import com.dc.eventpoi.core.inter.CellStyleCallBack;
import com.dc.eventpoi.core.inter.SheetCallBack;
public class 测试包含表格和列表数据的复杂导出2 {
public static void main(String[] args) throws Exception {
//构造表格形式的数据
OrderInfo orderInfo = new OrderInfo();
orderInfo.setKehu("ddddcccc");
orderInfo.setOrderName("进口海鲜");
orderInfo.setTotalMoney("15.66");
orderInfo.setBuyer("张三");
orderInfo.setSaller("李四");
//构造列表形式的数据
List<Object> excelDataList = new ArrayList<Object>();
List<ProductInfo> productList = new ArrayList<ProductInfo>();
ProductInfo p1 = new ProductInfo();
p1.setNo("NO_1");
p1.setName("ssssss111");
//这是图片项
String img_file_path = new File(Test1.class.getResource("unnamed.jpg").getPath()).getAbsolutePath();
p1.setHeadImage(Files.readAllBytes(Paths.get(img_file_path)));
ProductInfo p2 = new ProductInfo();
p2.setNo("NO_2");
p2.setName("ssssss222");
ProductInfo p3 = new ProductInfo();
p3.setNo("NO_3");
p3.setName("ssssss333");
productList.add(p1);
productList.add(p2);
productList.add(p3);
excelDataList.add(productList);
excelDataList.add(orderInfo);
//导出
byte[] exportByteData = ExcelHelper.exportExcel(Test1.class.getResourceAsStream("订单_templete.xlsx"), excelDataList,new SheetCallBack() {
@Override
public void callBack(SXSSFSheet sxssSheet) {
CellRangeAddress mergedRegionAt = new CellRangeAddress(7, 8, 0, 0);
sxssSheet.addMergedRegionUnsafe(mergedRegionAt);
}
},new CellStyleCallBack() {
@Override
public void callBack(SXSSFSheet sxssSheet, SXSSFCell curCell, CellStyle curCellStyle) {
System.err.println(curCell.getRowIndex());
if(curCell.getRowIndex()%2==0) {
curCellStyle.setFillForegroundColor(IndexedColors.AQUA.getIndex());
curCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
}else {
curCellStyle.setFillForegroundColor(IndexedColors.DARK_YELLOW.getIndex());
curCellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
}
}
});
Files.write(Paths.get("./my_test_temp/测试包含表格和列表数据的复杂导出2.xlsx"), exportByteData);
}
}
导出效果图如下(第8行和第9行的第一列已经合并,也设置上了背景颜色)