前端文件下载方案汇总

通常前后端数据交互都是用JQuery的ajax函数,其返回类型只有xml、text、json、html等类型,没有“流”类型,所以我们无法使用ajax实现文件下载。下面介绍几种文件下载的思路。

一、windows.open下载文件

后端返回的是文件流

1.1 前端代码

var downloadURL = "appraise/download?flightNo=123";
window.open(downloadURL);

1.2 后端代码

response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
//通知浏览器下载文件而不是打开
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");

//工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
int index = 0;
for(Map.Entry> entry : evaluationTypeMap.entrySet()){
    if(providers.containsKey(entry.getKey())){
        AbstractEvaluationProvider evaluationDataProvider = providers.get(entry.getKey());
        ExportExcelUtils.exportExcel(workbook,index++,evaluationDataProvider.createSheet(),evaluationDataProvider.createHead(),evaluationDataProvider.createData(entry.getValue()));
    }
}
workbook.write(response.getOutputStream());

1.3 优点

  • 浏览器兼容性好

1.4 缺点

  • URL长度受限制
  • 拿不到后端处理这个过程的时机,无法根据回调函数做交互以及进度提示

二、ajax提交请求,后端返回文件在线地址

后端返回的是文件地址(文件地址可访问)

2.1 前端代码

$.ajax({
    type: "post",
    url: "appraise/download",
    data: {'flightNo':'123'},
    success: function (res) {
        if (res.Status) {
            // window.open或者a标签下载 
            var isSupportDownload = 'download' in document.createElement('a');
            if (isSupportDownload) {
                var $a = $("");
                $a.attr({
                    href: res.url,
                    download: 'filename'
                }).hide().appendTo($("body"))[0].click();
            } else {
                window.open(res.url)
            }
        } else {
            alert(res.Message);
        }
    }
})

2.2 后端代码

return "doc/adscf-1123-221ss-dda.doc";

2.3 优点

  • 可以获取文件返回时机,可以做交互

2.4 缺点

  • 线上产生大量的中间临时文件,可以用设置时限来优化或可使用大厂的云存储,从而减少临时文件的产生

三、使用form.submit下载文件

后端返回文件流

3.1 前端代码

try{
        var exportForm = $("
"); exportForm.append(""); exportForm.append(""); exportForm.append(""); $(document.body).append(exportForm); exportForm.submit(); }catch (e) { alert_prompt(e); }finally { exportForm.remove(); }

3.2 后端代码

response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
//通知浏览器下载文件而不是打开
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");

//工作薄
HSSFWorkbook workbook = new HSSFWorkbook();
int index = 0;
for(Map.Entry> entry : evaluationTypeMap.entrySet()){
    if(providers.containsKey(entry.getKey())){
        AbstractEvaluationProvider evaluationDataProvider = providers.get(entry.getKey());
        ExportExcelUtils.exportExcel(workbook,index++,evaluationDataProvider.createSheet(),evaluationDataProvider.createHead(),evaluationDataProvider.createData(entry.getValue()));
    }
}
workbook.write(response.getOutputStream());

3.3 优点

  • 兼容性良好,传统方式,不会出现URL长度限制问题

3.4 缺点

  • 拿不到后端处理这个过程的时机,无法根据回调函数做交互以及进度提示

四、使用 jquery-download 插件

  • jquery-download 下载地址:https://github.com/johnculviner/jquery.fileDownload/blob/master/src/Scripts/jquery.fileDownload.js
  • jquery-download CDN地址:https://www.bootcdn.cn/jquery.fileDownload/

4.1 前端代码

$.fileDownload('appraise/downLoad.jhtml', {
                httpMethod: 'post',
                data: {'flightLeftDate': flightLeftDate,'flightRightDate':flightRightDate},
                prepareCallback: function (url) {
                    console.log("文件下载中...");
                    // 数据加载动画
                    $("#loading").modal('show');
                },
                abortCallback: function (url) {
                    // 异常终止
                    alert_prompt("文件下载异常!");
                    $("#loading").modal('hide');
                },
                successCallback: function (url) {
                    alert_prompt("文件下载成功!");
                    $("#loading").modal('hide');
                },
                failCallback: function (html, url) {
                    if(html.indexOf('<') >= 0) {
                        html = $(html).text();
                    }
                    var result = JSON.parse(html);
                    $("#loading").modal('hide');
                    alert_prompt("文件下载失败:" + result.Head.Msg);
                }
            });

4.2 后端代码

        if(!evaluationTypeMap.isEmpty()){
            try{
                response.setContentType("application/vnd.ms-excel");
                response.setCharacterEncoding("utf-8");
                // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
                String fileName = URLEncoder.encode("测试", "UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xls");
                response.setHeader("Set-Cookie", "fileDownload=true; path=/");

                //工作薄
                HSSFWorkbook workbook = new HSSFWorkbook();
                int index = 0;
                for(Map.Entry> entry : evaluationTypeMap.entrySet()){
                    if(providers.containsKey(entry.getKey())){
                        AbstractEvaluationProvider evaluationDataProvider = providers.get(entry.getKey());
                        ExportExcelUtils.exportExcel(workbook,index++,evaluationDataProvider.createSheet(),evaluationDataProvider.createHead(),evaluationDataProvider.createData(entry.getValue()));
                    }
                }
                workbook.write(response.getOutputStream());
            }catch (Exception e){
                log.error("efb:评价导出---->导出失败:",e);
                // 重置response
                response.reset();
                response.setContentType("application/json");
                response.setCharacterEncoding("utf-8");
                EfbReturnPO efbReturnPO = new EfbReturnPO();
                efbReturnPO.setUnSuccessHead("下载文件失败:" + e.getMessage());
                response.setHeader("Set-Cookie", "fileDownload=false; path=/");

                response.getWriter().println(AOSJson.toJson(efbReturnPO));
            }
        }else{
            log.error("efb:评价导出---->导出失败:无匹配数据");
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            EfbReturnPO efbReturnPO = new EfbReturnPO();
            efbReturnPO.setUnSuccessHead("无匹配数据!");
            response.setHeader("Set-Cookie", "fileDownload=false; path=/");

            response.getWriter().println(AOSJson.toJson(efbReturnPO));
        }

注意:后端代码增加了一个名为"fileDownload"的cookie的返回;jquery.download.js插件使用该cookie来判断是否下载成功,从而进入成功回调函数(successCallback)

4.3 优点

  • 浏览器兼容好,此插件做了多种兼容
    • window.open(url)打开某个文件地址
    • iframe的框架中,设置src属性,通过iframe进行文件的下载,支持文件地址
    • 通过form标签,设置action的文件地址,然后通过form的提交来完成文件的下载
  • 可以获取文件返回时机,可以做交互

五、其它方案

  • iframe直接向后端提交,实现对文件流进行下载
  • Html5的Blob对象实现对文件流进行下载
  • file-saver实现对文件流进行下载

你可能感兴趣的:(前端文件下载方案汇总)