SpringBoot中使用EasyExcel并行导出多个excel文件并压缩zip后下载

2024-09-17 10:53:19 浏览数 (1)

背景

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的生成过程:

代码语言:javascript复制
@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);
    }
}

0 人点赞