waynblog

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

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

所以这里给大家介绍一种Ajax下载文件并添加进度条的方法

1. Java后端代码

@RequestMapping("/export")
publicvoidlist(JobLog jobLog,HttpServletRequest request,HttpServletResponse response)throwsIOException{
ParameterUtil.set(jobLog);
    jobLogService.export(jobLog, response, request);
}
...

@Override
publicvoidexport(JobLog jobLog,HttpServletResponse response,HttpServletRequest request)throwsIOException{
ExportParamsexportParams=newExportParams();
    exportParams.setStyle(IExcelExportStylerImpl.class);
    exportParams.setColor(HSSFColor.HSSFColorPredefined.GREEN.getIndex());
try(Workbookworkbook=ExcelExportUtil.exportBigExcel(exportParams,JobLog.class,this, jobLog);
// 划重点-使用bos获取excl文件大小
ByteArrayOutputStreambos=newByteArrayOutputStream();
OutputStreamos= response.getOutputStream()){
        workbook.write(bos);
ServletUtil.setExportResponse(request, response,"任务日志列表.xlsx", bos.size());
// 保存数据
        bos.writeTo(os);
}
}
...

/**
 * 设置文件导出响应流
 *
 * @param response 响应对象
 * @param request  请求对象
 * @param size     文件大小
 * @throws UnsupportedEncodingException 不支持字符编码异常
 */

publicstaticvoidsetExportResponse(HttpServletRequest request,HttpServletResponse response,String fileName,Integer size)throwsUnsupportedEncodingException{
    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
 */

functionexportData(exportUrl, formId, filename){
var req =newXMLHttpRequest();
    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(typeofwindow.chrome!=='undefined'){
// Chrome version
var link =document.createElement('a');
                    link.href=window.URL.createObjectURL(req.response);
                    link.download= filename;
                    link.click();
}elseif(typeofwindow.navigator.msSaveBlob!=='undefined'){
// IE version
var blob =newBlob([req.response],{type:'application/force-download'});
window.navigator.msSaveBlob(blob, filename);
}else{
// Firefox version
var file =newFile([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
QQ图片20221219194236.png

3. 总结

觉得有用的话不妨点赞、转发、评论,上述示例代码来自 https://github.com/wayn111/crowd-admin 项目

引用链接

[1]: https://juejin.cn/post/7167294154827890702