美文网首页
前端文件下载方案汇总

前端文件下载方案汇总

作者: AaronSimon | 来源:发表于2019-12-06 14:20 被阅读0次

    通常前后端数据交互都是用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<String, List<EvaluationDo>> 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>");
                    $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 = $("<form action='appraise/downLoad' method='post'></form>");
            exportForm.append("<input type='hidden' name='flightLeftDate' value='" + flightLeftDate + "'/>");
            exportForm.append("<input type='hidden' name='flightRightDate' value='" + flightRightDate + "'/>");
            exportForm.append("<input type='hidden' name='evaluationType' value='vectorDataEvaluation'/>");
            $(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<String, List<EvaluationDo>> 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 插件

    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<String, List<EvaluationDo>> 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实现对文件流进行下载

    相关文章

      网友评论

          本文标题:前端文件下载方案汇总

          本文链接:https://www.haomeiwen.com/subject/hkcegctx.html