背景:
- 导出竞品周报(月报)数据
- 一个任务导出多个Excel 数据表。
- 数据表数据大于100万时,分割成两个数据表。
功能点:
- 异步导出
- 从ES中获取数据时,仅返回需要的字段,节省内存
- 将获取的数据做分割,按照品牌分类,存于map中
- 当单表数据量超过100万时,需要做数据分割,分割成多个数据表,单表最大100万
- 将导出文件,打成压缩包
- 使用SXSSFWorkbook进行数据导出,避免内存溢出
设置窗口大小 swb = new SXSSFWorkbook(wb, 1000);
设置压缩临时文件 swb.setCompressTempFiles(true);
核心逻辑:
结果:
导出数量:5513997
导出时间:67分钟
代码:
private String createExcelReport(Map.Entry<String, List<AnalysisIndustryBean>> entry, String filePath,
DownloadInfo downloadInfo, HashMap<String, Object> timeMap,
Map<Integer, String> monitorMap, HashMap<Integer, Object> labelMap) throws Exception {
String result = ResultCommon.LOSE_CODE;
XSSFWorkbook wb = null;
Sheet sheet = null;
FileInputStream in = null;
FileOutputStream out = null;
List<AnalysisIndustryBean> beanList = null;
SXSSFWorkbook swb = null;
BufferedOutputStream bos = null;
try {
// 检测项名称
String monitorName = monitorMap.get(Integer.valueOf(entry.getKey()));
System.out.println("[" + DateHelper.getNowDate(DateHelper.FMT_DATE_DATETIME) + "]--------" + monitorName + "(执行中)----------");
String startTime = DateHelper.formatDateString((String) timeMap.get("startTime"), DateHelper.FMT_DATE_DATETIME, DateHelper.FMT_DATE_YYMMDD);
String endTime = DateHelper.formatDateString((String) timeMap.get("endTime"), DateHelper.FMT_DATE_DATETIME, DateHelper.FMT_DATE_YYMMDD);
// 报告名称
String tempFileName = monitorName + "-" + startTime + "-" + endTime + "周报数据";
// 需要导出报告数据
beanList = entry.getValue();
// 模板路径
String templatePath = ExcelReportCommonData.WEEKLY_EXCEL_REPORT_PATH;
in = new FileInputStream(templatePath);
wb = new XSSFWorkbook(in);
swb = new SXSSFWorkbook(wb, 1000);
swb.setCompressTempFiles(true); // 设置压缩文件
swb.setSheetName(0, monitorName);
sheet = swb.getSheetAt(0);
this.styles = com.xlmediawatch.common.Style.ExcelStyle.createStyle(wb);//excel的样式
int rowNum = 1; // 记录行数
int serialNum = 1; // 序号
if (beanList != null && !beanList.isEmpty()) {
int fileCount = 1; // 计数器,用于生成文件序号
for (int i = 0; i < beanList.size(); i++) {
AnalysisIndustryBean esBean = beanList.get(i);
// 每五个元素创建一个新的 Excel 文件,或者到达列表末尾时
if (i > 0 && i % 1000000 == 0) {
// 输出数据
String fileName = i / 1000000 == 1 ? tempFileName + ".xlsx" : tempFileName + "(" + (fileCount - 1) + ").xlsx";
out = new FileOutputStream(filePath + fileName);
bos = new BufferedOutputStream(out);
bos.flush();
swb.write(bos);
// 重置
in = new FileInputStream(templatePath);
wb = new XSSFWorkbook(in);
swb = new SXSSFWorkbook(wb, 1000);
swb.setCompressTempFiles(true); // 设置压缩文件
swb.setSheetName(0, monitorName);
sheet = swb.getSheetAt(0);
// 多个excel之间样式不能共享,所以每个excel都需要重新赋值styles
this.styles = com.xlmediawatch.common.Style.ExcelStyle.createStyle(wb);//excel的样式
rowNum = 1; // 记录行数
serialNum = 1; // 序号
fileCount++; // 文件序号递增
}
// 填充数据
rowNum = createMonitorExcelReportData(rowNum, esBean, serialNum, sheet, monitorName, labelMap);
serialNum++;
}
// 写出最后一个文件,如果列表大小不是5的整数倍时
if (!beanList.isEmpty()) {
String fileName = fileCount == 1 ? tempFileName + ".xlsx" : tempFileName + "(" + (fileCount - 1) + ").xlsx";
out = new FileOutputStream(filePath + fileName);
bos = new BufferedOutputStream(out);
bos.flush();
swb.write(bos);
}
}
result = ResultCommon.SUSSES_CODE;
} catch (IOException e) {
result = ResultCommon.LOSE_CODE;
e.printStackTrace();
} finally {
// 关闭资源
try {
if (bos != null) {
bos.close();
}
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
if (swb != null) {
swb.dispose();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}