关键点在于,多次复用模板流,InputStream只能读取一次,先copy到ByteArrayOutputStream,
获取byte数组,写到ByteArrayInputStream中,之后每次循环生成一个excel后对stream进行reset,
这样就可以实现模板流复用,另外excel生成写入到ZipOutputStream后也可以reset复用。
private ExportResultDTO exportZip(Map<String, List<ExcelData>> outMap) {
try (InputStream templateStream = awss3Util.getTemplateAsInputStream(TEMPLATE_NAME);
ByteArrayOutputStream templateStreamOut = new ByteArrayOutputStream();
ByteArrayOutputStream excelOut = new ByteArrayOutputStream();
ByteArrayOutputStream zipOut = new ByteArrayOutputStream();
ZipOutputStream zipOutputStream = new ZipOutputStream(zipOut)) {
IOUtils.copy(templateStream, templateStreamOut);
byte[] bytes = templateStreamOut.toByteArray();
try (ByteArrayInputStream templateByteInputStream = new ByteArrayInputStream(bytes)) {
for (Map.Entry<String, List<ExcelData>> entry : outMap.entrySet()) {
String excelName = entry.getKey();
List<ExcelData> dataList = entry.getValue();
writerStreamByTemplate(excelOut, templateByteInputStream, dataList);
zipOutputStream.putNextEntry(new ZipEntry(excelName));
zipOutputStream.write(excelOut.toByteArray());
templateByteInputStream.reset();
excelOut.reset();
}
}
templateStream.close();
templateStreamOut.close();
excelOut.close();
zipOutputStream.flush();
zipOutputStream.close();
String key = redisUtil.getIncrementKey();
awss3Util.putBytesToDefBucket(key, zipOut.toByteArray());
zipOut.close();
return ExportResultDTO.builder()
.s3ObjectKey(key)
.s3ObjectBucket(AWSS3Util.AWS_S3_BUCKET_DEFAULT)
.contentType("application/zip")
.filename("excel.zip")
.build();
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new RuntimeException("Export excel failed.", e);
}
}
private void writerStreamByTemplate(OutputStream outputStream, InputStream templateStream, List<LGGIOSSManifest2021DTO> dataList) {
ExcelWriter excelWriter = EasyExcel.write(outputStream)
.withTemplate(templateStream)
.build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();
excelWriter.fill(dataList, writeSheet);
excelWriter.finish();
}