背景
SpringBoot的同步导出方式中,服务器会阻塞直到Excel文件生成完毕,在处理大量数据的导出功能,利用CompletableFuture,我们可以将导出任务异步化,最后 这些文件进一步压缩成ZIP格式以方便下载:
DEMO代码:
代码语言:javascript复制@RestController
@RequestMapping("/export")
public class ExportController {
@Autowired
private ExcelExportService excelExportService;
@GetMapping("/zip")
public ResponseEntity<byte[]> exportToZip() throws Exception {
List<List<Data>> dataSets = multipleDataSets();
List<CompletableFuture<String>> futures = new ArrayList<>();
// 异步导出所有Excel文件
String outputDir = "path/to/output/dir/";
for (List<Data> dataSet : dataSets) {
futures.add(excelExportService.exportDataToExcel(dataSet, outputDir));
}
// 等待所有导出任务完成
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).get(10, TimeUnit.MINUTES);;
// 收集Excel文件路径
List<String> excelFilePaths = futures.stream()
.map(CompletableFuture::join) // 获取文件路径
.collect(Collectors.toList());
// 压缩文件
File zipFile = new File("path/to/output.zip");
try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(zipFile))) {
for (String filePath : excelFilePaths) {
zipFile(new File(filePath), zipOut, new File(filePath).getName());
}
}
// 返回ZIP文件
byte[] data = Files.readAllBytes(zipFile.toPath());
return ResponseEntity.ok()
.header("Content-Disposition", "attachment; filename="" zipFile.getName() """)
.contentType(MediaType.parseMediaType("application/zip"))
.body(data);
}
// 将文件添加到ZIP输出流中
private void zipFile(File file, ZipOutputStream zipOut, String entryName) throws IOException {
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {
ZipEntry zipEntry = new ZipEntry(entryName);
zipOut.putNextEntry(zipEntry);
byte[] bytesIn = new byte[4096];
int read;
while ((read = bis.read(bytesIn)) != -1) {
zipOut.write(bytesIn, 0, read);
}
zipOut.closeEntry();
}
}
// 获取数据
private List<List<Data>> multipleDataSets() {
}
}
SpringBoot异步并行生成excel文件,利用EasyExcel
库来简化Excel的生成过程:
@Service
public class ExcelExportService {
private static final String TEMPLATE_PATH = "path/to/template.xlsx";
@Autowired
private TaskExecutor taskExecutor;
public CompletableFuture<Void> exportDataToExcel(List<Data> dataList, String outputDir) {
Path temproaryFilePath = Files.createTempFile(outputDir, "excelFilePre",".xlsx");
return CompletableFuture.runAsync(() -> {
try (OutputStream outputStream = new FileOutputStream(temproaryFilePath )) {
EasyExcel.write(outputStream, Data.class)
.withTemplate(TEMPLATE_PATH)
.sheet()
.doFill(dataList)
.finish();
return temproaryFilePath.toString();
} catch (IOException e) {
throw new RuntimeException("Failed to export Excel file", e);
}
}, taskExecutor);
}
}