简体   繁体   English

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

[英]Download an xlsx file with reactJS: Excel can not open file

I'm trying to download an xlsx file with reactJS but i'm receiving this message when i try to open my file after download: 我正在尝试使用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" “ Excel无法打开文件'file.xlsx',因为文件格式或文件扩展名无效。请验证文件未损坏且文件扩展名与文件格式匹配”

Here's the frontend code: 这是前端代码:

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

                }
            });

});

Why am i getting this error? 为什么会出现此错误? Please somebody help me, i'm stuck on this for 3 weeks 请有人帮我,我坚持了三个星期

[EDIT 1] [编辑1]

The file that i'm trying to download is build on backend, basically i get the values on database and use the Apache poi workbook to create the excel sheet. 我要下载的文件建立在后端,基本上我在数据库上获取值并使用Apache poi工作簿创建excel工作表。 I will show you the mainly parts of the code: 我将向您展示代码的主要部分:

1) This method is called by frontend on the first GET requisition of frontend and aims to prepare the file before the download. 1)该方法在前端的第一个GET请求中由前端调用,目的是在下载之前准备文件。 Is very simple, just create a token (buildToken()) and associate a temp file with this token (createTempFile(randomBackendToken)). 非常简单,只需创建一个令牌(buildToken())并将一个临时文件与此令牌(createTempFile(randomBackendToken))关联。 The temp file is filled with what i get on my database (createFile(os)) 临时文件充满了我在数据库中得到的内容(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) The method where i create the temp file: 2)我创建临时文件的方法:

public OutputStream createTempFile(String randomBackendToken) throws IOException {

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

        return os;
    }

3) The method where i receive the empty temp file and fills with my data on database: 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) My WriteExcel Class that build the xlsx file: 4)构建xlsx文件的我的WriteExcel类:

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;

}

So, this all above is just for the first GET requisition. 因此,以上所有内容仅用于第一个GET申请。 I make another one and the method below holds the second requisition. 我再做一个,下面的方法保存第二个申请。 I just verify the token that the frontend returns for me and them, based on the validation, i allow the download of the file that i created on the previous step: 我只验证前端返回给我和他们的令牌,基于验证,我允许下载我在上一步中创建的文件:

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

And that's all that i'm doing. 这就是我正在做的所有事情。 Can't find what's wrong or what i'm missing. 找不到什么问题或我所缺少的。 When i press F12 on my navigator to see the response of the request, shows for me something encoded, like: 当我在导航器上按F12键查看请求的响应时,会为我显示一些编码的内容,例如:

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

Any suspicions of what can be? 有什么怀疑吗?

guys! 伙计们!

The problem was: my binary data was being converted for string by javascript and this was breaking my excel file. 问题是:我的二进制数据被javascript转换为字符串,这破坏了我的excel文件。 i solved my problem converting my binary data on backend to text and then on frontend i make the inverse. 我解决了将后端的二进制数据转换为文本,然后在前端进行逆转换的问题。 The following links helped me: 以下链接对我有帮助:

java convert inputStream to base64 string java将inputStream转换为base64字符串

Creating a Blob from a base64 string in JavaScript 在JavaScript中从base64字符串创建Blob

Thank you for everyone that tried to help. 谢谢所有尝试提供帮助的人。 I hope my question can help others 我希望我的问题可以帮助其他人

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM