实际项目中经常会遇到excel导入、导出操作,数据量过大会导致内存溢出,自己封装了一个导入导出的工具类,包括用户模式、事件驱动模式两种导入导出,数据量较小是可以使用用户模式,数据量比较大使用事件驱动模式,实测事件驱动模式下导入导出百万数据量毫无压力。
下面介绍下事件驱动模式导入导出的用法:
一、事件驱动模式导入
1、定义导入实体类,对应excel表格每一行数据,需要与表格字段顺序一致(使用lombok插件,省去getter、setter方法)。
@Data
public class ImportVo {
private String name;
private String sex;
private String email;
private String age;
}
2、导入方法调用,解析本地文件,同时映射为定义的实体类(文件中单元格类型设置为文本格式)。
public void importExcel() throws Exception {
ExcelHandler handler = new ExcelHandlerImpl();
String path = "D:/test.xlsx";
File file = new File(path);
List<ImportVo> list = handler.saxImport(file, "sheet", ImportVo.class, true);
List<User> userList = new ArrayList<>();
Iterator<ImportVo> iterator = list.iterator();
while (iterator.hasNext()) {
ImportVo importVo = iterator.next();
User user = new User();
user.setName(importVo.getName());
user.setSex(Integer.parseInt(importVo.getSex()));
user.setEmail(importVo.getEmail());
user.setAge(Double.parseDouble(importVo.getAge()));
user.setCreateTime(new Date());
userList.add(user);
if (userList.size() == 10000) {
userMapper.batchInsert(userList);
userList.clear();
}
}
}
二、事件驱动模式导出
1、定义导出实体类,@Header为导出列头显示的内容(使用lombok插件,省去getter、setter方法)。
@Data
public class ExportVo {
@Header("姓名")
private String name;
@Header("性别")
private int sex;
@Header("邮箱")
private String email;
@Header("年龄")
private double age;
}
2、分页填充数据,每次填充10000条数据,添加完所有数据后,写入本地文件。
public void export() throws Exception {
// 导出到本地磁盘
String path = "D:/test.xlsx";
Workbook wb = new SXSSFWorkbook(1000);
Sheet sheet = wb.createSheet("export_sheet");
ExcelHandler handler = new ExcelHandlerImpl();
List<ExportVo> dtoList = new ArrayList<>();
PageInfo<User> pageInfo = findAll(1, 10000);
fillSheet(sheet, handler, dtoList, pageInfo);
while (pageInfo.isHasNextPage()) {
pageInfo = findAll(pageInfo.getNextPage(), 10000);
fillSheet(sheet, handler, dtoList, pageInfo);
}
File file = new File(path);
OutputStream os = new FileOutputStream(file);
wb.write(os);
}
private void fillSheet(
Sheet sheet, ExcelHandler handler, List<ExportVo> dtoList, PageInfo<User> pageInfo)
throws Exception {
dtoList.clear();
for (User user : pageInfo.getList()) {
ExportVo vo = new ExportVo();
vo.setName(user.getName());
vo.setSex(user.getSex());
vo.setEmail(user.getEmail());
vo.setAge(user.getAge());
dtoList.add(vo);
}
handler.fillSheet(sheet, true, dtoList);
}
3、不分页导出
public void exportNoPage() throws Exception {
// 导出到本地磁盘
String path = "D:/test.xlsx";
ExcelHandler handler = new ExcelHandlerImpl();
List<ExportVo> dtoList = new ArrayList<>();
PageInfo<User> pageInfo = findAll(1, 1000000);
for (User user:pageInfo.getList()) {
ExportVo vo = new ExportVo();
vo.setName(user.getName());
vo.setSex(user.getSex());
vo.setEmail(user.getEmail());
vo.setAge(user.getAge());
dtoList.add(vo);
}
Workbook wb = handler.exportXLSX("no_page",true,true,dtoList);
File file = new File(path);
OutputStream os = new FileOutputStream(file);
wb.write(os);
}
总结:这个是以POI为基础开发的一个工具集,难点在于事件驱动模式对Excel的解析,Excel2007以后都是用XML格式存储,所以解析就是对XML文件的处理,要了解XML的存储结构然后对不同的标签做不同的处理。
源码地址:https://github.com/yuwy691/PoiExcelHandler.git
如何查看Excel2007 XML存储结构:https://blog.csdn.net/yuwy691/article/details/86161227