了解您想用 EasyExcel 实现分批查询数据并写入不同 Sheet 的需求,这对于处理大量数据导出非常有用。下面我将为您梳理核心的实现思路、关键代码示例以及一些实用的注意事项。
📝 核心实现思路
利用 EasyExcel 实现分批查询数据并写入不同 Sheet 的核心在于分页查询 与多 Sheet 写入机制的结合。其基本流程如下:
-
计算总分页数与 Sheet 数:根据数据总量、每个 Sheet 容纳的数据行数(如 100 万行)以及每次查询的数据量(如 20 万行),计算出需要多少个 Sheet 以及每个 Sheet 需要查询多少次。
-
创建 ExcelWriter :在开始导出前,初始化一个
ExcelWriter
对象。 -
循环写入每个 Sheet:外层循环控制 Sheet 的创建,内层循环进行分页查询和数据写入。
-
关闭资源 :在所有数据写入完成后,务必调用
excelWriter.finish()
来关闭写入器并释放资源,这对于避免内存泄漏和确保文件完整性至关重要 。
具体的操作步骤和关键决策点,可以参考下面的流程图,它清晰地展示了从数据查询到最终生成多 Sheet Excel 文件的完整过程:
flowchart TD
A[开始导出] --> B[计算总数据量<br>确定Sheet数和分页数]
B --> C[创建ExcelWriter]
C --> D{是否还有Sheet要处理?}
D -- 是 --> E[创建新Sheet]
E --> F{是否完成当前Sheet的写入?}
F -- 否 --> G[分页查询下一批数据]
G --> H[将数据写入当前Sheet]
H --> F
F -- 是 --> D
D -- 否 --> I[关闭ExcelWriter<br>finish]
I --> J[导出完成]
💻 关键代码示例与解释
以下是一个简化的代码框架,展示了如何实现上述流程。代码中包含了关键步骤的注释说明。
// 1. 准备输出流和ExcelWriter(通常在实际项目中与HttpServletResponse绑定)
String fileName = "batch_export_example.xlsx";
ExcelWriter excelWriter = EasyExcel.write(fileName).build();
// 2. 定义常量:每个Sheet的数据量、每次查询的数据量
int perSheetRows = 1000000; // 每个Sheet存放100万行数据
int pageSize = 200000; // 每次查询20万行
int totalCount = 5000000; // 总数据量500万行(实际场景中需从数据库查询count)
// 3. 计算需要的Sheet数量和每个Sheet需要写入的次数
int totalSheets = (totalCount + perSheetRows - 1) / perSheetRows; // 向上取整
// 4. 外层循环:遍历每个Sheet
for (int sheetIndex = 0; sheetIndex < totalSheets; sheetIndex++) {
// 创建新的Sheet,可设置Sheet名称
WriteSheet writeSheet = EasyExcel.writerSheet(sheetIndex, "数据Sheet_" + (sheetIndex + 1))
.head(YourDataModel.class) // 指定数据模型类,用于生成表头
.build();
// 5. 内层循环:计算当前Sheet的数据范围,并进行分页查询和写入
int startRow = sheetIndex * perSheetRows;
int endRow = Math.min((sheetIndex + 1) * perSheetRows, totalCount);
int currentPage = 1;
int currentPosition = startRow;
while (currentPosition < endRow) {
// 计算当前页实际应查询的数据量
int currentPageSize = Math.min(pageSize, endRow - currentPosition);
// 分页查询数据(假设您的分页查询方法返回List<YourDataModel>)
List<YourDataModel> dataBatch = yourDataService.getDataBatch(currentPage, currentPageSize);
// 将查询到的数据写入当前Sheet
excelWriter.write(dataBatch, writeSheet);
currentPage++;
currentPosition += currentPageSize;
}
}
// 6. 非常重要:关闭ExcelWriter,释放资源
excelWriter.finish();
代码关键点说明:
-
数据模型类 (
YourDataModel
) :这是一个普通的 Java 类,使用@ExcelProperty
注解来映射 Excel 的表头。例如,@ExcelProperty("姓名") private String name;
。 -
分页查询方法 (
yourDataService.getDataBatch
):您需要根据自己项目的持久化框架(如 MyBatis-Plus、JPA 等)实现一个分页查询方法,根据页码和页面大小返回数据列表。 -
Sheet 命名 :通过
EasyExcel.writerSheet
方法可以指定 Sheet 的索引和名称。 -
资源释放 :
excelWriter.finish()
是必须调用的方法,它确保所有数据被正确写入文件并关闭相关输出流 。
⚠️ 注意事项与优化建议
-
性能与内存管理:
-
批量大小 :
pageSize
(每批查询的数据量)需要根据实际情况调整。太小会导致数据库查询频繁,太大则可能增加单次内存占用。通常建议在几千到几万条之间进行测试和选择 。 -
流式导出:EasyExcel 本身设计为低内存占用。对于超大数据量(如百万行以上),其写入机制能有效避免内存溢出(OOM)。
-
-
样式与格式:
-
自动列宽 :可以注册
LongestMatchColumnWidthStyleStrategy
策略,让 EasyExcel 自动根据单元格内容调整列宽,提升 Excel 文件的可读性 。 -
自定义样式 :如果需要设置单元格边框、字体、对齐方式等,可以通过实现
WriteHandler
接口或使用HorizontalCellStyleStrategy
来自定义样式 。
-
-
Web 环境下的导出:
- 当在 Controller 中处理 HTTP 导出请求时,需要正确设置
HttpServletResponse
的响应头(如 Content-Type、Content-Disposition),并将OutputStream
传递给EasyExcel.write
。
- 当在 Controller 中处理 HTTP 导出请求时,需要正确设置
希望这些详细的说明和代码示例能帮助您顺利实现功能!如果您在具体实现过程中遇到更细致的问题,例如特定场景的优化,我们可以继续深入探讨。