easypoi大批量导出excel数据
easypoi导出excel数据
最近,面临了一个新的需求,需要将表中的几百万数据导出到Excel文件中。为了满足这一需求,我决定采用EasyPoi库来实现该功能
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
下面是我封装的工具类
因为easypoi可以使用@Excel注解来生成excel列所以我就不使用模板了。
使用IExcelExportServer将数据分批查询出来,里面的mapper查询这块需要优化,推荐从非关系型数据库中查询。
/**
* 大批量导出
* @param name
* @param bo
* @param entityClass
* @param response
* @param <T>
*/
public <T> void matterExport(String name, QueryBo bo, Class entityClass, HttpServletResponse response) {
IExcelExportServer exportServer = new IExcelExportServer() {
@Override
public List<Object> selectListForExcelExport(Object queryParams, int page) {
LambdaQueryWrapper<User> wrapper = iUserService.buildQueryWrapper(bo);
String lastsql = "LIMIT " + (page - 1) * limit + ", " + limit;
wrapper.last(lastsql);
List<User> reslist = userMapper.selectList(wrapper);
if (null == reslist || reslist.isEmpty()) {
return null;
}
List<T> list = JSONObject.parseArray(JSON.toJSONString(reslist), entityClass);
List<Object> objects = new ArrayList<Object>(list);
if (list.size() == 0) {
return null;
}
return objects;
}
};
exportBufferExcel(name, entityClass, exportServer, response);
}
生产workbook后通过文件流的方式导出
/**
* 增强导出
* @param name
* @param entityClass
* @param response
* @param <T>
*/
public <T> void exportBufferExcel(String name, Class entityClass, IExcelExportServer exportServer, HttpServletResponse response) {
ExportParams params = new ExportParams(null, name, ExcelType.XSSF);
params.setCreateHeadRows(true);
// 生产workbook
try {
Workbook workbook = ExcelExportUtil.exportBigExcel(params, entityClass, exportServer, null);
downLoadExcel(name, response, workbook);
} catch (IOException e) {
e.printStackTrace();
log.error("导出失败! ===>{}", e.getMessage());
}
}
/**
* 下载
*
* @param fileName 文件名称
* @param response
* @param workbook excel数据
*/
private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {
try {
response.setCharacterEncoding("UTF-8");
response.setHeader("content-Type", "application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
workbook.write(response.getOutputStream());
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
这样是不是就够了?
本人在用自己的电脑通过本地数据库和jar包测试表数据量达到100w+的时候就有很明显的卡顿了,电脑配置为i7CPU 32G内存。
众所周知在Excel中打开超过100万行的数据,可能会导致性能下降和卡顿,部分数据也可能没有及时加载。Excel的最大行数和列数取决于硬件和软件的限制,一般情况下,Excel的行数最大为1048576,列数最大为16384。因此,如果超过了这些限制,Excel可能会出现加载错误。
这个时候单纯的一个excel导出已经不能满足我们的使用需求了。
easypoi多表格大批量导出excel数据
1、对数据进行分片,我这里用hutool工具类中ListUtil.partition方法对在数据中查询的数据进行分片
LambdaQueryWrapper<User> wrapper = iUserService.buildQueryWrapper(bo);
List<User> userList = userMapper.selectList(wrapper);
List<List<Map<String, Object>>> partition = ListUtil.partition(userList, partSize);
注意:不要直接去数据库查询和这样分片,我这里偷懒了
2、创建一个ThreadPoolExecutor线程池用来提交线程,使用CountDownLatch程序计数器计数,传入线程数,这里也就是我们将要生成的文件个数和分片数,线程中执行将分片中的数据写入excel并将excel文件防止到一个用压缩的临时目录中, 然后调用await()方法等待所有线程执行结束。最后关闭线程。
3、将临时目录中的文件夹压缩成你想要的压缩文件类型后将压缩好的文件上传至0ss中并清除临时目录。