Spring Boot中如何用单个Controller同时生成多份不同列CSV文件下载
问题原因
单个HTTP请求只能对应一个响应,每个响应仅支持返回一个文件。你在同一个接口中往同一个HttpServletResponse的输出流里写入两份CSV内容,自然会出现内容拼接的情况。
解决方案
提供两种常用实现方式:
方案1:前端发起两次独立导出请求(改动最小,推荐)
将公共CSV导出逻辑抽为通用工具方法,提供两个导出接口(或同一个接口加类型参数区分导出字段),前端分别调用两个接口即可得到两个独立CSV文件。
代码示例
// 抽离公共CSV导出工具方法 private void writeCsvToResponse(List<String> includeFields, String fileName, List<Report> data, HttpServletResponse response) throws Exception { response.setContentType("text/csv"); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\""); StatefulBeanToCsvBuilder<Report> builder = new StatefulBeanToCsvBuilder<Report>(response.getWriter()) .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) .withSeparator(CSVWriter.DEFAULT_SEPARATOR) .withOrderedResults(true); // 过滤排除不需要导出的字段 Arrays.stream(Report.class.getDeclaredFields()) .filter(field -> !includeFields.contains(field.getName())) .forEach(field -> builder.withIgnoreField(Report.class, field)); builder.build().write(data); } // 导出id+amount的接口 @GetMapping("/export/id-amount") public void exportIdAmount(@RequestParam(name="cohort") String cohort, HttpServletResponse response) throws Exception { List<Report> data = reportsService.findByCohort(cohort); writeCsvToResponse(List.of("id", "amount"), "liabilities_id_amount.csv", data, response); } // 导出name+currency的接口 @GetMapping("/export/name-currency") public void exportNameCurrency(@RequestParam(name="cohort") String cohort, HttpServletResponse response) throws Exception { List<Report> data = reportsService.findByCohort(cohort); writeCsvToResponse(List.of("name", "currency"), "liabilities_name_currency.csv", data, response); }
方案2:后端打包两个CSV为ZIP单次返回
如果要求单次请求就能拿到两个文件,可以将两份CSV打包为ZIP压缩包返回,解压后即可得到两个独立文件。
代码示例
import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import java.nio.charset.StandardCharsets; @GetMapping("/export/both") public void exportBothCsv(@RequestParam(name="cohort") String cohort, HttpServletResponse response) throws Exception { // 设置响应为ZIP类型 response.setContentType("application/zip"); response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"liabilities_bundle.zip\""); List<Report> data = reportsService.findByCohort(cohort); try (ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream())) { // 写入第一个CSV到ZIP包 addCsvToZip(List.of("id", "amount"), "liabilities_id_amount.csv", data, zipOut); // 写入第二个CSV到ZIP包 addCsvToZip(List.of("name", "currency"), "liabilities_name_currency.csv", data, zipOut); } } // 通用方法:生成CSV并写入ZIP压缩包 private void addCsvToZip(List<String> includeFields, String entryName, List<Report> data, ZipOutputStream zipOut) throws Exception { ZipEntry zipEntry = new ZipEntry(entryName); zipOut.putNextEntry(zipEntry); OutputStreamWriter writer = new OutputStreamWriter(zipOut, StandardCharsets.UTF_8); StatefulBeanToCsvBuilder<Report> builder = new StatefulBeanToCsvBuilder<Report>(writer) .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER) .withSeparator(CSVWriter.DEFAULT_SEPARATOR) .withOrderedResults(true); Arrays.stream(Report.class.getDeclaredFields()) .filter(field -> !includeFields.contains(field.getName())) .forEach(field -> builder.withIgnoreField(Report.class, field)); builder.build().write(data); writer.flush(); zipOut.closeEntry(); }
内容的提问来源于stack exchange,提问作者swarajsingh78
相关产品推荐
相关产品推荐

