【问题标题】:How to download XLSX file with Java Spring/React?如何使用 Java Spring/React 下载 XLSX 文件?
【发布时间】:2019-11-26 23:33:53
【问题描述】:

我正在尝试生成一个.XLSX 文件并下载它。我使用Apache POI 生成excel 文件,我使用Swagger UI 测试端点。我一直在寻找几个小时,运气不佳。我用来生成 Excel 文件的代码是:

@GetMapping(path = "/download")
public ResponseEntity<ByteArrayResource> download(@RequestParam(name = "ids") long [] ids) {
    // ... other code ...
    XSSFWorkbook workbook = createWorkbook(reports);

    LocalDate date = LocalDate.now();

    String filename = "MYC " + date.getYear() + "." + date.getMonthValue();

    try {
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        HttpHeaders header = new HttpHeaders();
        header.setContentType(new MediaType("application", "vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
        header.set(HttpHeaders.CONTENT_DISPOSITION, String.format("attachment; filename=%s.xlsx", filename));
        workbook.write(stream);
        workbook.close();
        return new ResponseEntity<>(new ByteArrayResource(stream.toByteArray()), header, HttpStatus.CREATED);
    } catch (Exception e) {
        return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

使用Swagger UI 进行测试时,我拨打电话并得到以下回报:

我在 SO 上找到的答案建议使用 force-download 而不是 vnd.openxmlformats-officedocument.spreadsheetml.sheet,所以我继续尝试。这一次,Swagger UI 实际上生成了一个Download file 链接。我可以点击它,文件会下载得很好。但是使用force-download真的是一个合适的方法吗?

现在,我尝试在我的前端下载,无论我使用的是force-download 还是vnd.openxmlformats-officedocument.spreadsheetml.sheet,我都会得到一个“损坏的”.xlsx 文件。

刚刚在写我自己的时候发现this SO问题,这个人似乎也收到了相同类型的回复。他通过将二进制数据转换为字符串来修复它。不知道这是否也是我应该做的以及我将如何去做。

【问题讨论】:

    标签: java excel spring apache-poi xlsx


    【解决方案1】:

    好的,所以我设法通过从多个谷歌搜索中收集信息来解决这个问题。对于我的后端,我将byte array 编码为Base64,然后将其作为String 返回。

    @GetMapping(path = "/download")
    public ResponseEntity<String> download(@RequestParam(name = "ids") long[] ids) {
        // ... other code ...
        XSSFWorkbook workbook = createWorkbook(reports);
    
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType("text", "plain");
            workbook.write(outputStream);
            workbook.close();
            return new ResponseEntity<>(Base64.getEncoder().encodeToString(outputStream.toByteArray(), headers, HttpStatus.OK);
        } catch (IOException e) {
            return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
        }
    }
    

    在前端,我使用atob()解码String,然后解码为ArrayBuffer

    // ... other code ...
    actions.getSpreadsheet(ids)
        .then(result => {
            var date = new Date();
            var filename = "JSC " +
                date.getFullYear() +
                "." +
                (date.getMonth() + 1);
    
            var url = window.URL.createObjectURL(new Blob([this.s2ab(atob(result.data))], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;' }));
            var a = document.createElement('a');
            a.href = url;
            a.download = filename + '.xlsx';
            document.body.appendChild(a);
            a.click();
            a.remove();
        }).catch(error => {
            alert('Error retrieving report: ' + error);
        })
    
    s2ab = s => {
        var buf = new ArrayBuffer(s.length);
        var view = new Unit8Array(buf);
        for (var i = 0; i != s.length; i++) {
            view[i] = s.charCodeAt(i) & 0xFF;
        }
        return buf;
    }
    

    【讨论】:

    • 这似乎并不能解决流的问题。您甚至无法从输出流中收集字节。
    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 2021-10-24
    • 2020-07-31
    • 2019-09-15
    • 2021-02-02
    • 1970-01-01
    相关资源
    最近更新 更多