一、問題場景
最近在做數據統計功能,需求是導出大數據量的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; }