将 POI SXSSFWorkbook 流式传输到 servlet 输出流
Streaming a POI SXSSFWorkbook to the servlet output stream
我们正在构建一个 Spring 引导 REST 端点,它生成一个大型 XLS 文件(可能包含约 100 万行)并提供下载。
当前解决方案使用 Apache POI 库的 SXSSF API 创建工作簿;
之后我们将工作簿写入输出流,将流收集到一个字节数组中,然后提供这个供下载。
当我们添加更多行时,如何流式传输工作簿的内容,这样我们就不会将整个文件保存在内存中?
当前解决方案的代码
@RequestMapping(path = "/download/xls", method = RequestMethod.GET, produces = org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<InputStreamResource> downloadXls(HttpServletResponse response, XlsRequest request) throws FileNotFoundException, InternalServerErrorException {
byte[] data = downloadIssuesAsExcel(response, request);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Description", "File Transfer");
headers.add("Content-Disposition", "attachment; filename=justAFile.xlsx");
headers.add("Content-Transfer-Encoding", "binary");
headers.add("Connection", "Keep-Alive");
headers.setContentType(
org.springframework.http.MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
InputStreamResource isr = new InputStreamResource(new ByteArrayInputStream(data));
return ResponseEntity.ok().contentLength(data.length).headers(headers).body(isr);
}
public byte[] downloadIssuesAsExcel(HttpServletResponse response, XlsRequest request)
throws InternalServerErrorException {
try {
SXSSFWorkbook workbook = createExcel(request, response);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
workbook.write(stream);
workbook.dispose();
workbook.close();
stream.close();
return stream.toByteArray();
} catch (Exception e) {
throw new InternalServerErrorException("IO exception while downloading XLS file", e);
}
}
还尝试直接在 response.getOutputStream() 中写入工作簿内容,但文件不知何故被损坏。
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Description", "File Transfer");
response.setHeader("Content-Disposition", "attachment; filename=" + issueDataService.getExcelName(request));
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Connection", "Keep-Alive");
SXSSFWorkbook workbook = createExcel(request, response);
workbook.write(response.getOutputStream());
workbook.dispose();
workbook.close();
我刚刚使用您的代码作为模板并创建了运行良好的控制器
@RestController
public class XlsxController {
@RequestMapping(path = "/download/xls", method = RequestMethod.GET, produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public void downloadXls(HttpServletResponse r) throws IOException {
r.setHeader("Content-Description", "File Transfer");
r.setHeader("Content-Disposition", "attachment; filename=justAFile.xlsx");
r.setHeader("Content-Transfer-Encoding", "binary");
r.setHeader("Connection", "Keep-Alive");
try (SXSSFWorkbook w = getWorkbook()) {
w.write(r.getOutputStream());
}
}
100 万行权重超过 40 Mb 的工作簿
org.springframework:spring-webmvc:5.2.2.RELEASE
org.apache.poi:poi-ooxml:4.1.1
我们正在构建一个 Spring 引导 REST 端点,它生成一个大型 XLS 文件(可能包含约 100 万行)并提供下载。 当前解决方案使用 Apache POI 库的 SXSSF API 创建工作簿; 之后我们将工作簿写入输出流,将流收集到一个字节数组中,然后提供这个供下载。
当我们添加更多行时,如何流式传输工作簿的内容,这样我们就不会将整个文件保存在内存中?
当前解决方案的代码
@RequestMapping(path = "/download/xls", method = RequestMethod.GET, produces = org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity<InputStreamResource> downloadXls(HttpServletResponse response, XlsRequest request) throws FileNotFoundException, InternalServerErrorException {
byte[] data = downloadIssuesAsExcel(response, request);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Description", "File Transfer");
headers.add("Content-Disposition", "attachment; filename=justAFile.xlsx");
headers.add("Content-Transfer-Encoding", "binary");
headers.add("Connection", "Keep-Alive");
headers.setContentType(
org.springframework.http.MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
InputStreamResource isr = new InputStreamResource(new ByteArrayInputStream(data));
return ResponseEntity.ok().contentLength(data.length).headers(headers).body(isr);
}
public byte[] downloadIssuesAsExcel(HttpServletResponse response, XlsRequest request)
throws InternalServerErrorException {
try {
SXSSFWorkbook workbook = createExcel(request, response);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
workbook.write(stream);
workbook.dispose();
workbook.close();
stream.close();
return stream.toByteArray();
} catch (Exception e) {
throw new InternalServerErrorException("IO exception while downloading XLS file", e);
}
}
还尝试直接在 response.getOutputStream() 中写入工作簿内容,但文件不知何故被损坏。
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Description", "File Transfer");
response.setHeader("Content-Disposition", "attachment; filename=" + issueDataService.getExcelName(request));
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Connection", "Keep-Alive");
SXSSFWorkbook workbook = createExcel(request, response);
workbook.write(response.getOutputStream());
workbook.dispose();
workbook.close();
我刚刚使用您的代码作为模板并创建了运行良好的控制器
@RestController
public class XlsxController {
@RequestMapping(path = "/download/xls", method = RequestMethod.GET, produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
public void downloadXls(HttpServletResponse r) throws IOException {
r.setHeader("Content-Description", "File Transfer");
r.setHeader("Content-Disposition", "attachment; filename=justAFile.xlsx");
r.setHeader("Content-Transfer-Encoding", "binary");
r.setHeader("Connection", "Keep-Alive");
try (SXSSFWorkbook w = getWorkbook()) {
w.write(r.getOutputStream());
}
}
100 万行权重超过 40 Mb 的工作簿
org.springframework:spring-webmvc:5.2.2.RELEASE
org.apache.poi:poi-ooxml:4.1.1