一、问题场景
最近在做数据统计功能,需求是导出大数据量的excel,时间间隔较长,大概需要十秒左右,点击导出后,页面没有做任何处理,用户也不知道是否正在导出;如果没有做交互上的限制,用户可以一直点击导出按钮,这样势必会造成服务器瘫痪。
二、尝试过程
花了一天尝试了两种方案:
2.1 纯前端添加遮罩
单纯的前端是无法监听文件是否下载完成的,主要试了两种方案:
1.由于导出是用form表单提交的,并将form的target设置到一个隐藏iframe来达到不刷新页面而导出。本来想利用隐藏iframe的onload事件来判断是否导出成功的,但是调试发现导出成功后不会触发,所以该条路无法走通了。
2.用ajax来做导出,但是该方法无法实现自动下载导出文件,这条路也就无法走通了。
本来想监听浏览器点击下载链接到弹出窗口完成的状态,查阅资料发现这些都是浏览器包办了的,没有任何方法可以获取到状态,可能浏览器是出于安全考虑,所以没有提供。
2.2 前后端联动
主体思路是这样:
前端点击导出按钮加载事件并添加遮罩效果,设置定时器监听ajax从后端返回是否导出完成状态,后端状态设置初始session状态值,在导出事件后改变该session值,最后通过ajax返回前端。前端接收到状态值,如果已导出完成,解除遮罩;如不是,则继续定时监听直到返回导出完成为止。
该方案可行。
三、具体方案
前端js代码:
//点击导出事件function startexport(){$("#divload").show();//打开加载中遮罩 listenEnd();}function listenEnd() {//定时监听 var loop = setInterval(function() {if ($("#txtendflag").val() == "1") {clearInterval(loop);//停止定时任务$("#divload").hide();//关闭加载中遮罩} else {getendflag(); }}, 1000);//单位毫秒 注意:如果导出页面很慢时,建议循环时间段稍长一点 }function getendflag() {//请求session标记位 $.ajax({type : 'post',url : 'ajcxtjlistaction.action?cmd=getendflag',dataType : 'json',success : function(data) { $("#txtendflag").val(data.custom.flag); },error : function(error) {console.log('接口不通' + error);}}) }
后端Java代码:
public void export() {request.getSession().removeAttribute("endflag");//每次导入前,清除结束标记 /******该出为导出代码******/ /******导出结束*******/ request.getSession().setAttribute("endflag", "1");//设置结束标记 }//获取结束标记public Object getendflag() {Object flag = request.getSession().getAttribute("endflag"); //获取结束标记*/JSONObject obj = new JSONObject();obj.put("flag", flag);//返回状态值return obj;}