Потоковая POI SXSSFWorkbook в выходной поток сервлета - PullRequest
2 голосов
/ 09 января 2020

Мы создаем конечную точку REST Spring, которая генерирует большой файл XLS (может содержать ~ 1 миллион строк) и предоставляет его для загрузки. Текущее решение использует SXSSF API из библиотеки Apache POI для создания книги; после этого мы записываем книгу в выходной поток, собираем поток в массив байтов и затем предоставляем этот файл для загрузки.

Как может быть передано содержимое книги, поскольку мы добавляем больше строк , чтобы мы не хранили весь файл в памяти?

Код для текущего решения

@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();

1 Ответ

1 голос
/ 10 января 2020

Я только что использовал ваш код в качестве шаблона и создал контроллер, который отлично работает

@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());
        }
    }

Рабочая книга с 1 миллионами строк весом более 40 МБ

org.springframework:spring-webmvc:5.2.2.RELEASE
org.apache.poi:poi-ooxml:4.1.1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...