使用reactJS下载xlsx文件:Excel无法打开文件 [英] Download an xlsx file with reactJS: Excel can not open file

查看:286
本文介绍了使用reactJS下载xlsx文件:Excel无法打开文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

"Excel无法打开文件'file.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);

                }
            });

});

为什么会出现此错误?请有人帮我,我坚持了三个星期

Why am i getting this error? Please somebody help me, i'm stuck on this for 3 weeks

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

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. I will show you the mainly parts of the code:

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

1) This method is called by frontend on the first GET requisition of frontend and aims to prepare the file before the download. Is very simple, just create a token (buildToken()) and associate a temp file with this token (createTempFile(randomBackendToken)). The temp file is filled with what i get on my database (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)我创建临时文件的方法:

2) The method where i create the temp file:

public OutputStream createTempFile(String randomBackendToken) throws IOException {

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

        return os;
    }

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

3) The method where i receive the empty temp file and fills with my data on database:

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类:

4) My WriteExcel Class that build the xlsx file:

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申请.我再做一个,下面的方法保存第二个请购单.我只验证前端返回给我和他们的令牌,基于验证,我允许下载我在上一步中创建的文件:

So, this all above is just for the first GET requisition. 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(); 
                    }
                }
            }
        }
    }

这就是我正在做的所有事情.找不到什么问题或我所缺少的.当我在导航器上按F12键查看请求的响应时,会为我显示一些编码的内容,例如:

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:

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

有什么怀疑吗?

推荐答案

伙计们!

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

The problem was: my binary data was being converted for string by javascript and this was breaking my excel file. 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将inputStream转换为base64字符串

从中的base64字符串创建BlobJavaScript

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

Thank you for everyone that tried to help. I hope my question can help others

这篇关于使用reactJS下载xlsx文件:Excel无法打开文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆