前面已经实现过导出excel导出下拉框操作和正常数据的导出,伴随着业务发展的需求,需要进行导出最少10万+数据,但是导出大量数据时可能会面临一些挑战,包括内存使用、性能和超时等问题。如果在导出过程中发生错误,这可能会导致部分数据未能成功导出,用户可能会得到不完整的 Excel 文件。
所以在处理大量数据导出时,我采用一下方式进行:
1、分批导出: 尝试将数据分成较小的批次进行导出,而不是一次性导出所有数据。这可以通过在代码中实现分页或分批查询的逻辑来完成。
2、异步导出: 如果导出过程较为耗时,可以考虑将导出任务放到异步任务中执行,以避免对用户请求的阻塞。
maven
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.2</version>
</dependency>
pojo
package com.jaxf.electric.excel;
import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
@Data
public class MonitorDataExcel{
@ExcelIgnore
private Integer id;
@ExcelProperty("时间")
private String beginTime;
@ExcelProperty("设备id")
private String deviceId;
@ExcelProperty("温度")
private String Temperature;
@ExcelProperty("电压")
private String Voltage;
@ExcelProperty("湿度")
private String Humidity;
}
serviceImpl
public void exportDeviceDate(HttpServletResponse response) {
Long pageSize = (long) this.count();
List<MonitorDataExcel> allData = new ArrayList<>();
for (int i = 0; i < (1L + 1); i++) {
Long pageNum = (long) i;
List<MonitorDataExcel> list = limitDictData(pageNum * pageSize, pageSize);
allData.addAll(list);
}
// 获取当前年月
YearMonth currentYearMonth = YearMonth.now();
// 使用自定义格式化方式打印当前年月
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
String formattedYearMonth = currentYearMonth.format(formatter);
String filename = formattedYearMonth + "月数据统计表.xlsx";
try (OutputStream out = response.getOutputStream()) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
// 配置 WriteSheet 以允许单元格编辑
WriteSheet writeSheet = EasyExcel.writerSheet(formattedYearMonth + "月数据统计").build();
// 将 Excel 版本设置为 XLSX(Excel 2007或更高版本),以支持编辑
ExcelWriter excelWriter = EasyExcel.write(out, ElectricalMonitorExcel.class).excelType(ExcelTypeEnum.XLSX)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
.build();
// 将数据写入 Excel
excelWriter.write(allData, writeSheet);
excelWriter.finish();
} catch (Exception e) {
log.error("导出excel时发生异常:{}", e.getMessage(), e);
}
}
多线程操作
/*
* 多线程读写
* */
@GetMapping
public void exportDeviceDate() {
CountDownLatch countDownLatch = new CountDownLatch(5);
Long pageSize = 100000L;
int count = (int) dictService.count();
for(int i=0;i<(count/pageSize+1);i++){
Long pageNum = Long.valueOf(i);
new Thread(() -> {
List<MonitorDataExcel> list = electricalMonitorDataService.limitDictData(pageNum*pageSize, pageSize);
// 获取当前年月
YearMonth currentYearMonth = YearMonth.now();
// 使用自定义格式化方式打印当前年月
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
String formattedYearMonth = currentYearMonth.format(formatter);
String filename = formattedYearMonth + "月数据统计表.xlsx";
//导出到本地
File file = new File("D:/" + filename);
if (!file.exists()){
file.mkdirs();
}
String filename = "D:/" + filename;
EasyExcel.write(filename, ExcelDict.class).sheet("统计表").doWrite(list);
countDownLatch.countDown();
}).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
long pagStart = System.currentTimeMillis();
//打包
ZipUtil.zipDirectory("D:/demo","D:/demo.zip");
}
service && serviceImpl
List<MonitorDataExcel> limitDictData(Long pageNum, Long pageSize);
public List<ExcelDict> limitDictData(Long pageNum, Long pageSize){
//获取第1页,10条内容,默认查询总数count
PageHelper.offsetPage(pageNum.intValue(), pageSize.intValue());
List<ExcelDict> dictList = dictMapper.queryAll();
PageInfo<ExcelDict> pageInfo = new PageInfo<>(dictList);
return pageInfo.getList();
}
由于公司的也无需求还不明了,故此只能先建立基础框架,上面也进行了测试,导出数据在10万+以上,耗时大致接近1分钟。暂时先记录到这吧(属于烂尾项目,没走完整个业务流程,到时候在提出需求的时候进行更新)