以Web方式下载数据有多种场景:
1.服务端本身已经存在文件,此时只需要一个文件访问地址即可下载,比如:将文件URL设置为<a>
标签的href属性即可,点击<a>
标签就能立即触发浏览器下载文件,此时无需单独设置下载提示信息。
2.下载的文件在服务端并不存在,而是需要查询数据库等才能获取,这种方式无法直接在客户端设置一个文件访问URL,通常是以流式方式下载数据,这就是本篇博文要阐述的情景。
在大多数需要以流方式下载/导出文件的场景,从客户端发出请求,到浏览器端开始下载文件这一段间隔里,是不会有任何提示的,查看网络请求也是处于“Pending”状态的。 甚至有时候因为服务端查询数据耗时慢等问题会让用户误以为没有触发下载,于是又重复点击按钮,在导出大量数据的场景,这可能会加剧服务端的处理负担。 实际上,这却又是一个常见且普遍的问题。 之所以会出现这样的情况,就是因为当我们在浏览器端点击“下载/导出”按钮的时候没有给予用户一个明确的提示信息,或者说没有通过一种有效的手段来防止用户出现重复点击的情况。
那么对于这种以流式方式下载文件的情况,又该如何来实现当用户点击按钮后到浏览器出现下载提示这段时间给予用户一个明确的提示呢? 有一篇博文web程序下载文件添加等待加载效果阐述了使用iframe框架来实现这一功能,但经过实验并未成功。 直到看到另一篇博文前后端分离,前端获取文件流下载文件介绍的方式,经过实验发现,这种方式确实有效。
于是把该博文介绍的方式以一个完整的示例(使用EasyExcel导出表格)整理出来,提供给大家参考(基于Chrome浏览,版本:103.0.5060.134)。 展示效果如下:
服务端核心代码:
// 以流的方式下载文件
@RequestMapping("/download")
public String download(HttpServletRequest request, HttpServletResponse response,
@RequestParam("name") String name,
@RequestParam("age") int age) throws IOException {
System.out.println(String.format("name:%s, age:%s", name, age));
String fileName = URLEncoder.encode(String.format("%s_%s.xlsx", "导出数据", System.currentTimeMillis()), "UTF-8");
response.reset();
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("filename", fileName);
response.setContentType("application/octet-stream; charset=UTF-8");
try {
// 模拟查询数据耗时
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
EasyExcel.write(response.getOutputStream(), SubjectExport.class).sheet("sheet").doWrite(dataList);
return null;
}
前端代码:
<html>
<body>
<div>
<form id="paramForm">
<input type="hidden" name="name" value="zhangsan" />
<input type="hidden" name="age" value="12" />
</form>
</div>
<div>
<button id="btnDownloadXhr">导出</button>
</div>
</body>
<script type="text/javascript" src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript" src="http://cdn.bootcss.com/jquery.blockUI/2.66.0-2013.10.09/jquery.blockUI.min.js"></script>
<script type="text/javascript">
$(function(){
$("#btnDownloadXhr").click(function () {
downloadXhr();
})
})
function downloadXhr() {
var url = "/download";
var param = $("#paramForm").serialize();
var xhr = new XMLHttpRequest();
xhr.open("POST", url);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
xhr.responseType = "blob";
xhr.onload = function () {
console.log("加载完毕");
$.unblockUI();
if (xhr.status === 200) {
var blob = this.response;
var reader = new FileReader();
reader.readAsDataURL(blob);
var filename = decodeURI(this.getResponseHeader('filename'));
reader.onload = function (e) {
var a = document.createElement('a');
a.download = filename;
a.href = e.target.result;
//兼容firefox
$('body').append(a);
a.click();
$(a).remove();
}
}
};
xhr.send(param);
console.log("正在加载数据...")
$.blockUI({
message: "正在加载数据..."
});
}
</script>
</html>
完整示例代码地址:test-web-downloadtip,可以直接下载下来在本地运行。
【参考】 https://blog.csdn.net/qq_40527797/article/details/122813537 springBoot+JSP搭建项目 https://easyexcel.opensource.alibaba.com/ Easy Excel https://blog.csdn.net/fgx_123456/article/details/79603455 web程序下载文件添加等待加载效果 https://blog.csdn.net/w139074301/article/details/121786052 前后端分离,前端获取文件流下载文件