通用 Excel 模块
pjcloud-common-excel 提供 Excel 导入、普通导出以及大数据量 XLSX 分批流式导出能力。
分批流式导出
BatchExcelExportTemplate 适用于单次导出不能把全部查询结果和全部工作表行同时保留在 JVM 堆中的场景。它统一负责:
- 根据预统计数量循环分页查询;
- 使用
SXSSFWorkbook把超出内存窗口的工作表行刷新到磁盘; - 校验分页实际数量与预统计数量一致;
- 校验 Excel 2007 单工作表行数上限;
- 释放模板流、工作簿、SXSSF 临时 XML 和最终 XLSX 临时文件;
- 通过回调接入业务进度、汇总行和文件上传逻辑。
业务模块先增加公共 Excel 依赖:
<dependency>
<groupId>com.bsd</groupId>
<artifactId>pjcloud-common-excel</artifactId>
</dependency>
典型调用方式:
String fileUrl = BatchExcelExportTemplate.<ExportRow, ExportContext, String>builder(total)
.batchSize(1000)
.dataStartRowIndex(2)
.reservedTailRowCount(1)
.temporaryFilePrefix("user-export-")
.templateSupplier(() -> ResourceUtil.getStream("file/user.xlsx"))
.templateInitializer(workbook -> prepareTemplate(workbook))
.pageFetcher((pageNumber, batchSize) -> {
Page<ExportRow> page = new Page<>(pageNumber, batchSize, false);
return userService.pageForExport(page, query).getRecords();
})
.rowWriter((sheet, rowIndex, dataIndex, item, context) ->
writeRow(sheet, rowIndex, dataIndex, item, context))
.footerWriter((sheet, rowIndex, processedTotal, context) ->
writeSummary(sheet, rowIndex, context))
.progressListener((processedTotal, expectedTotal) ->
reporter.advance("已整理 " + processedTotal + " / " + expectedTotal + " 条"))
.fileConsumer(path -> upload(Files.readAllBytes(path), fileName))
.execute();
与异步任务组合
公共 Excel 模块不依赖 pjcloud-common-async-task。业务层通过 progressListener 把每批完成事件转给
AsyncTaskProgressReporter,通过 fileConsumer 上传完整文件并返回 AsyncTaskResult 所需的地址。
异步任务总步数可统一计算:
int progressTotal = BatchExcelExportTemplate.calculateProgressTotal(total, batchSize, 2);
reporter.updateTotal(progressTotal, "已查询 " + total + " 条数据,将分批生成文件");
额外的 2 由业务流程定义,例如文件上传一步和异步任务成功收尾一步。公共模板每完成一个查询批次只通知一次,
不会按明细行高频写 Redis。
调用约束
- 预统计和分页查询必须使用完全相同的筛选条件、租户上下文和数据权限。
- 分页 SQL 必须有稳定排序;排序字段存在重复值时,需要追加唯一字段,避免翻页时漏行或重复。
- 导出期间数据发生增删会触发数量不一致异常,业务方应提示用户重新导出。
dataStartRowIndex和reservedTailRowCount都按 Excel 零基行号语义配置。fileConsumer收到的路径只在回调期间有效,不得交给其他线程延迟读取。- 默认关闭共享字符串表以控制内存;只有确认重复文本占比高且内存可控时才启用。
- 单个工作表仍受 XLSX 的 1,048,576 行上限约束;超过上限时应按业务条件拆分文件或扩展为多工作表导出。