某天工作接到一个需求:批量导出场站的订单信息,一个场站一个Excel文档;
与单个文件导出的区别在于,单个导出一次性只导出一个文件,在输出流中写入这一个文件即可,那么如何一次性导出多个文件?难道一次接口返回能被循环读取重复打开保存对话框?
不是,其实是使用压缩文件,在内存中将生成的EXCEL文件依次加入到压缩文件中,最后形成一个.zip格式的文件,写入输出流作为接口的返回;
理解简单,话不多说,代码如下:
public void exportLogBatch(ChargingParkCouponLogVO chargingParkCouponLog, HttpServletResponse response) throws IOException {
// 设置响应头,指定下载的文件类型为压缩文件
response.setContentType("application/zip");
String start = DateUtil.format(chargingParkCouponLog.getStartDate(), "yyyy-MM-dd");
String end = DateUtil.format(chargingParkCouponLog.getEndDate(), "yyyy-MM-dd");
response.setHeader("Content-Disposition", "attachment; filename=\"订单停车券按场站批量导出(" + start + "~" + end + ").zip\"");
String[] parkIdArr = chargingParkCouponLog.getParkIds().split(",");
try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) {
for (String s : parkIdArr) {
try {
ChargingParkConfig chargingParkConfig = chargingParkConfigService.getById(Long.valueOf(s));
if (ObjectUtils.isEmpty(chargingParkConfig)) {
continue;
}
List<ChargingParkCouponLogExport> exportList = generateExportFiles(chargingParkCouponLog);
byte[] bytes = generateFileBytes(exportList);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
// 创建压缩文件的条目,并将文件内容写入压缩文件
ZipEntry zipEntry = new ZipEntry("道闸发券识别异常清单—" + chargingParkConfig.getParkName() + ".xlsx");
zipOut.putNextEntry(zipEntry);
byte[] buffer = new byte[1024];
int length;
while ((length = byteArrayInputStream.read(buffer)) >= 0) {
zipOut.write(buffer, 0, length);
}
zipOut.closeEntry();
} catch (Exception e) {
throw new ServiceException("停车券发放记录列表导出异常,编号:" + s);
}
}
zipOut.finish();
} catch (Exception e) {
e.printStackTrace();
}
}
private List<ChargingParkCouponLogExport> generateExportFiles(ChargingParkCouponLogVO chargingParkCouponLog) {
Page page = new Page<>();
page.setSize(10000L);
List list = chargingParkCouponLogService.selectChargingParkCouponLogPage(page, chargingParkCouponLog).getRecords();
List<ChargingParkCouponLogExport> exportList = new LinkedList<>();
list.forEach(item -> {
ChargingParkCouponLogExport logExport = new ChargingParkCouponLogExport();
BeanUtils.copyProperties(item, logExport);
exportList.add(logExport);
});
return exportList;
}
private byte[] generateFileBytes(List<ChargingParkCouponLogExport> exportList) {
// 创建一个ByteArrayOutputStream对象,用于将Excel数据写入内存中的字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
// 使用ExcelWriter创建一个写入器,并将其与ByteArrayOutputStream关联
ExcelWriter excelWriter = EasyExcel.write(outputStream, ChargingParkCouponLogExport.class).build();
// 创建一个WriteSheet对象,设置Sheet名称和表头类
WriteSheet writeSheet = EasyExcel.writerSheet().build();
// 将数据列表写入Excel文件
excelWriter.write(exportList, writeSheet);
// 关闭ExcelWriter
excelWriter.finish();
// 获取ByteArrayOutputStream的字节数组
byte[] bytes = outputStream.toByteArray();
return bytes;
}
调用接口:
返回结果:
总结下导出逻辑的变更:
之前:准备要导出的场站ID,获取该场站要导出的数据,调用导出工具类写输出流;
之后:准备要导出的场站的批量的ID列表,遍历ID列表循环获取场站各自要导出的数据,打开请求的总输出流作为ZipOutStream的输入流,对每个要导出的场站列表,创建单独的二进制输出流,将各自要导出的数据,写入输出流中,写入完后将输出流返回为二进制数组,作为输入流,写入创建的压缩文件中,将所有的导出文件二进制数据都写入各自的ZipEntry,最后写入总的ZipOutStream,循环执行,即可导出所有的文件作为压缩包;