Ajax下载文件添加进度条教程

简介: Ajax下载文件添加进度条教程

image.png

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情

对于下载文件这个常见场景,相信大家都遇到过,不管是从浏览器下载软件还是在某某后台导出文件之类,一般我们使用浏览器下载软件都是可以看到下载进度提示的,而我们在某某后台导出文件之类却很少能看到下载进度,点击导出按钮,如果导出文件耗时太久而页面又没有变化,可能让用户重新点击导出或者切换页面,浪费用户点击,总之就是导出体验不够友好。这里给大家介绍一种后台系统下载文件添加进度条提示的通用方法。

本文基于 Springboot + thymeleaf + layer + bootstrap3 技术给大家讲解

1. Java后端代码

@RequestMapping("/export")
public void list(JobLog jobLog, HttpServletRequest request, HttpServletResponse response) throws IOException {
    ParameterUtil.set(jobLog);
    jobLogService.export(jobLog, response, request);
}
...
@Override
public void export(JobLog jobLog, HttpServletResponse response, HttpServletRequest request) throws IOException {
    ExportParams exportParams = new ExportParams();
    exportParams.setStyle(IExcelExportStylerImpl.class);
    exportParams.setColor(HSSFColor.HSSFColorPredefined.GREEN.getIndex());
    try (Workbook workbook = ExcelExportUtil.exportBigExcel(exportParams, JobLog.class, this, jobLog);
         // 划重点-使用bos获取excl文件大小
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         OutputStream os = response.getOutputStream()) {
        workbook.write(bos);
        ServletUtil.setExportResponse(request, response, "任务日志列表.xlsx", bos.size());
        // 保存数据
        bos.writeTo(os);
    }
}
...
/**
 * 设置文件导出响应流
 *
 * @param response 响应对象
 * @param request  请求对象
 * @param size     文件大小
 * @throws UnsupportedEncodingException 不支持字符编码异常
 */
public static void setExportResponse(HttpServletRequest request, HttpServletResponse response, String fileName, Integer size) throws UnsupportedEncodingException {
    response.setCharacterEncoding(Constants.UTF_ENCODING);
    response.setHeader("Content-Length", HttpUtil.safeHttpHeader(size + ""));
    response.setHeader("Content-Disposition", HttpUtil.safeHttpHeader("attachment;filename=" + FileUtils.setFileDownloadHeader(request, fileName)));
    response.setContentType("application/octet-stream");
}

上述代码核心逻辑在 setExportResponse() 方法,给响应流添加内容长度即文件大小

2. 前端代码

/**
 * 通用导出方法,此处依赖leyer,bootstrap3
 */
function exportData(exportUrl, formId, filename) {
    var req = new XMLHttpRequest();
    req.open("post", exportUrl);
    req.responseType = "blob";
    //监听进度事件
    req.addEventListener("progress", function (evt) {
        // 是否有长度信息
        if (evt.lengthComputable) {
            // 已加载字节数
            var loaded = evt.loaded;
            // 总字节数
            var total = evt.total;
            var percentComplete = loaded / total;
            $("#process").css({'width': percentComplete * 100 + "%"})
            $("#processText").text(percentComplete * 100 + "%")
            console.log(percentComplete);
            if (percentComplete >= 1) {
                setTimeout(() => {
                    layer.closeAll();
                }, 2000);
            }
        }
    }, false);
    layer.closeAll();
    layer.open({
        type: 1,
        title: '正在下载,请稍后...',
        icon: 16,
        shade: 0.01,
        time: false,
        area: ['240px', '75px'],
        content: `<div class="progress progress-striped active" style="position: relative;top: 15%;width: 95%;display: inline-flex;margin: 0 0 0 5px;">
                            <div style="width: 0%" id="process" class="progress-bar progress-bar-success">
                                <span id="processText" style="color: #262c2a">0%</span>
                            </div>
                        </div>` //这里content是一个普通的String
    });
    req.onreadystatechange = function () {
        if (req.readyState === 4) {
            if (req.status === 200) {
                if (typeof window.chrome !== 'undefined') {
                    // Chrome version
                    var link = document.createElement('a');
                    link.href = window.URL.createObjectURL(req.response);
                    link.download = filename;
                    link.click();
                } else if (typeof window.navigator.msSaveBlob !== 'undefined') {
                    // IE version
                    var blob = new Blob([req.response], {type: 'application/force-download'});
                    window.navigator.msSaveBlob(blob, filename);
                } else {
                    // Firefox version
                    var file = new File([req.response], filename, {type: 'application/force-download'});
                    window.open(URL.createObjectURL(file));
                }
            } else {
                layer.close(index);
                layer.alert('下载失败!');
            }
        }
    };
    req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    req.send($('#' + formId + '').serialize());
}

上述代码核心逻辑是通过原生Ajax请求下载文件,再通过 req.addEventListener("progress", function (evt) {...} 方法,监听 progress 事件,计算下载进度。需要注意的是如果后端没有返回内容长度(  Content-Length ),那么下载进度条是无效的

实现效果如下:

image.png

3. 总结

觉得有用的话不妨点赞、转发、评论,上述示例代码来自 github.com/wayn111/cro… 项目,想要跟作者沟通技术问题的话可以加我微信【waynaqua】。

目录
相关文章
|
7月前
|
JavaScript 前端开发 容器
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
AJAX载入外部JS文件到页面并让其执行的方法(附源码)
70 0
|
6月前
|
PHP
php+ajax传file文件数据
php+ajax传file文件数据
52 0
|
7月前
|
JSON 前端开发 JavaScript
jQuery ajax读取本地json文件 三级联动下拉框
jQuery ajax读取本地json文件 三级联动下拉框
|
7月前
|
移动开发 前端开发 安全
Ajax跨域的所有方法(最详细带使用教程!!!)
Ajax跨域的所有方法(最详细带使用教程!!!)
|
7月前
|
XML 前端开发 JavaScript
AJAX | 拦截器、文件上传和下载
AJAX | 拦截器、文件上传和下载
71 0
|
JavaScript 前端开发
原生JS实现Ajax下载文件
原生JS实现Ajax下载文件
257 0
|
域名解析 JSON 前端开发
漏刻有时数据可视化ajax访问静态json文件使用POST方法返回405 (Method Not Allowed)的解决方案
漏刻有时数据可视化ajax访问静态json文件使用POST方法返回405 (Method Not Allowed)的解决方案
174 0
|
XML 存储 JSON
可能不是史上最全但肯定能学会的 Ajax 教程
可能不是史上最全但肯定能学会的 Ajax 教程
221 0
|
XML JSON 缓存
【建站系列教程】3.2、ajax使用精讲
【建站系列教程】3.2、ajax使用精讲
115 0
【建站系列教程】3.2、ajax使用精讲
|
前端开发
Ajax模板文件
Ajax模板文件
78 0