獲取jqGrid中的所有資料匯出並生成Excel檔案流供使用者下載(post請求實現檔案下載)
阿新 • • 發佈:2019-01-13
最近有一個需求是:
將jqGrid表格中的資料生成報表Excel檔案返回給使用者。
我的想法是獲取jqGrid中的資料然後生成json資料,傳給後端,生成檔案流,響應到前端,儲存為excel檔案。
ajax為什麼不能夠實現下載檔案
ajax的返回值型別是json,text,html,xml型別,或者可以說ajax的接收型別只能是string字串,不是流型別,所以無法實現檔案下載。
但用ajax仍然可以獲得檔案的內容,該檔案將被保留在記憶體中,無法將檔案儲存到磁碟。這是因為JavaScript無法和磁碟進行互動,否則這會是一個嚴重的安全問題,js無法呼叫到瀏覽器的下載處理機制和程式,會被瀏覽器阻塞。
並且 我用ajax實現的時候出現了很多bug。
在網上參考好多部落格,經過不斷的除錯,我還是選擇了原生的XMLHttpRequest物件進行post請求。
blob(HTML5 新特性)
二進位制大物件,是一個可以儲存二進位制檔案的容器。
作用
Js一直以來都沒有比較好的可以直接處理二進位制的方法。而Blob的存在,允許我們可以通過JS直接操作二進位制資料。
Blob物件可以看做是存放二進位制資料的容器,此外還可以通過Blob設定二進位制資料的MIME型別。
BLOB是一個大檔案,典型的BLOB是一張圖片或一個聲音檔案,由於它們的尺寸,必須使用特殊的方式來處理(例如:上傳、下載或者存放到一個數據庫)。
重點應用
- 目前做的通過URL下載檔案。
- 分片上傳檔案(將大檔案分片,輪詢向後臺提交各檔案片段)。
後端程式碼
/**
* 生成Excel報表
* Error:存在問題
* 1. 前端表格中沒有Student物件的一些屬性,生成報表時不必要顯示的屬性欄位在Excel中顯示。
* solve:加判斷控制。
* 2. (由於blob是HTML5新出的)相容性問題:chrome、firefox、opera無問題,
* 3. 檢測grid表格中有無欄位名稱衝突問題。
* solve:細心檢查即可
* 4. 下載完Excel,打開出現"檔案已損壞 無法開啟"問題,這是因為office受保護試圖導致(安全問題)
* solve:在office選項裡邊修改一下即可(客戶端問題)
* @param list
* @param response
*/
@RequestMapping(value = "/exstudent",consumes = "application/json;charset=utf-8")
public void export (@RequestBody List<Student> list, HttpServletResponse response){
OutputStream out = null;
String name = "學生資訊管理表";
for (Student stu:list) {
System.out.println(stu.getStudentname());
}
try {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment;filename=" +URLEncoder.encode(name, "UTF-8")+".xlsx");
out = response.getOutputStream();
//呼叫老師自己寫的庫,本篇文章不詳細說生成Excel檔案的事情。
TExcel.exportExcel(name,Student.class,list,out);
System.out.println("下載ok");
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}finally{
}
}
前端程式碼:
//匯出按鈕被點選之後,將按鈕製為無效(防止多次生成)
function abideBtn(){
console.log("禁止按鈕......");
$("#download").attr({"href":"#"});
$("#download").css("cursor","not-allowed");
}
//下載過程中出錯誤,
function downloadError(){
console.log("發生錯誤,下載失敗");
alert("下載中出現錯誤!請重試");
$("#download").attr({"href":"javascript:exportData();"});
$("#download").css("cursor","pointer");
}
//匯出表格資料
//注意:下面獲取jqGrid中所有行資料的前提是分頁在前端,而不是後端。
//如果你是在後端分頁,那麼你會發現,你會將所有資料都顯示出來。
function exportData() {
var grid = jQuery("#grid");
//獲取當前顯示的資料
var rowNum = grid.jqGrid('getGridParam', 'rowNum'); //獲取顯示配置記錄數量
var total = grid.jqGrid('getGridParam', 'records'); //獲取查詢得到的總記錄數量
//設定rowNum為總記錄數量並且重新整理jqGrid,使所有記錄現出來呼叫getRowData方法才能獲取到所有資料
grid.jqGrid('setGridParam',{rowNum: total,}).trigger('reloadGrid');
var rows = o.jqGrid('getRowData');
grid.jqGrid('setGridParam',{rowNum: rowNum,}).trigger('reloadGrid');
postToPOM(rows);
}
//傳送post請求
function postToPOM(rows) {
console.log(rows);
var url = "../student/exstudent";
var xhr = new XMLHttpRequest();
xhr.open('POST',url,true);
xhr.responseType = "blob";
xhr.setRequestHeader("Content-Type"
, "application/json;charset=utf-8");
//新增監聽事件。
xhr.addEventListener("load",abideBtn,false);
xhr.addEventListener("error",downloadError,false);
xhr.onload = function (){
if(this.status === 200){
//建立Bolb物件
var blob = this.response;//html5新出的
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = function(e){
//建立a標籤,構造下載彈窗
var a = document.createElement("a");
a.id = "downloadTag";
a.download = '學生資訊管理表.xlsx';
a.href = e.target.result;
$("body").append(a);
a.click();
$("#downloadTag").remove();
console.log("下載完成!");
//恢復按鈕
$("#download").attr({"href":"javascript:exportData();"});
$("#download").css("cursor","pointer");
}
}
};
xhr.send(JSON.stringify(rows));
}