使用 reactJS 下载 xlsx 文件:Excel 无法打开文件

Download an xlsx file with reactJS: Excel can not open file

我正在尝试使用 reactJS 下载 xlsx 文件,但是当我在下载后尝试打开我的文件时收到此消息:

"Excel can not open file 'file.xlsx' because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the file format"

这是前端代码:

const REST_DOWNLOAD_URL = REST_URL + '/token';

Rest.ajaxPromise('GET', REST_DOWNLOAD_URL).then(function (res) {

var FILE_URL = "/supermarket/token/" + res;
Rest.ajaxPromise('GET', FILE_URL).then(function (my_file) {


                let blob = new Blob([my_file._body], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8' });

                if (navigator.msSaveOrOpenBlob) {
                    navigator.msSaveBlob(blob, 'file.xlsx');
                } else {

                    let link = document.createElement('a');
                    link.href = window.URL.createObjectURL(blob);
                    link.setAttribute('download', 'file.xlsx');
                    document.body.appendChild(link);
                    link.download = '';
                    link.click();
                    document.body.removeChild(link);

                }
            });

});

为什么我会收到这个错误?请有人帮助我,我坚持了 3 周

[编辑 1]

我要下载的文件是在后端构建的,基本上我获取数据库中的值并使用 Apache poi 工作簿创建 excel sheet。我将向您展示代码的主要部分:

1) 该方法在前端第一次GET请求时由前端调用,目的是在下载前准备文件。非常简单,只需创建一个令牌 (buildToken()) 并将临时文件与该令牌相关联 (createTempFile(randomBackendToken))。临时文件充满了我在数据库中得到的内容 (createFile(os))

@RequestMapping(value = "/token", method = RequestMethod.GET)
public String returnToken() throws IOException {

        String randomBackendToken = tokenGenerator.buildToken();
        OutputStream os = tokenGenerator.createTempFile(randomBackendToken);
        tokenGenerator.createFile(os);

        return randomBackendToken;

    }

2) 创建临时文件的方法:

public OutputStream createTempFile(String randomBackendToken) throws IOException {

        OutputStream os = null;
        File file = File.createTempFile(randomBackendToken, ".xlsx"); 
        os = new FileOutputStream(file); 

        return os;
    }

3) 我收到空的临时文件并在数据库中填充我的数据的方法:

public void createFile(OutputStream os) throws IOException {

        List<Supermakets> supermarkets = service.findAllSupermarkets(); 
        Workbook workbook = writeExcel.createSheet(supermarkets); 
        workbook.write(os); 
        IOUtils.closeQuietly(os);
}

4) 我构建 xlsx 文件的 WriteExcel Class:

private static String[] columns = {"Code", "Name", "Type"};

    public Workbook createSheet(List<Supermarket> supermarkets) throws IOException {

        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("file");

        [....]

        // Row for Header
        Row headerRow = sheet.createRow(0);

        // Header
        for (int col = 0; col < columns.length; col++) {
            Cell cell = headerRow.createCell(col);
            cell.setCellValue(columns[col]);
            cell.setCellStyle(headerCellStyle);
        }

        //Content
        int rowIdx = 1;
        for (Supermarket supermarket : supermarkets) {
            Row row = sheet.createRow(rowIdx++);

            row.createCell(0).setCellValue(supermarket.getCode());
            row.createCell(1).setCellValue(supermarket.getName());
            row.createCell(2).setCellValue(supermarket.getType());

        }
        return workbook;

}

因此,以上所有内容仅适用于第一个 GET 请求。我做了另一个,下面的方法持有第二个申请。我只是为我和他们验证前端 returns 的令牌,基于验证,我允许下载我在上一步中创建的文件:

public void export(@PathVariable(value = "frontendToken") String frontendToken, HttpServletResponse response) throws IOException {

        if (StringUtils.isNotBlank(frontendToken)) {

            String tmpdir = System.getProperty("java.io.tmpdir");


            File folder = new File(tmpdir);
            File[] listOfFiles = folder.listFiles();


            for (int i = 0; i < listOfFiles.length; i++) {
                if (listOfFiles[i].isFile()) {
                    boolean fileIsValid = tokenGenerator.validateToken(frontendToken, listOfFiles[i]);

                    if (fileIsValid) {

                        InputStream input = new FileInputStream(listOfFiles[i]);
                        OutputStream output = response.getOutputStream();

                        int data = input.read();

                        while (data != -1) {

                            output.write(data);
                            data = input.read();

                        }
                        input.close();
                        output.flush();
                        output.close();

                        String mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                        response.setContentType(mimeType);

                        listOfFiles[i].delete(); 
                    }
                }
            }
        }
    }

这就是我所做的一切。找不到哪里出了问题或缺少什么。当我在导航器上按 F12 查看请求的响应时,会显示一些编码的内容,例如:

PK@SM_rels/.rels­’ÁjÃ0†_ÅèÞ8í`ŒQ·—2èmŒî4[ILbËØÚ–½ýÌ.[Kì($}ÿÒv?‡I½Q.ž£uÓ‚¢hÙùØx>=¬î@ÁèpâH"Ã~·}¢

有什么疑惑可以吗?

伙计们!

问题是:javascript 将我的二进制数据转换为字符串,这破坏了我的 excel 文件。我解决了我的问题,将后端的二进制数据转换为文本,然后在前端进行了反转。以下链接对我有帮助:

Creating a Blob from a base64 string in JavaScript

感谢所有试图提供帮助的人。希望我的问题可以帮助到其他人