標籤:stat open 統一 技術分享 tps form btn 方式 ;;
最近的一個項目比較忙,一直沒時間過來跟新部落格。今天過來分享一下在此項目中遇到的一個小問題:匯出Excel;相信匯出Excel這個功能是特別常見的,也有很多的方式。好了,不多說了,直接說說自己遇到的各種坑,我後台用的是poi匯出。
首先,說一下需求,想要的結果就是:“符合匯出條件時,正常匯出,並彈出提示框讓使用者選,不符合匯出條件時,提示使用者不能匯出,還要在使用者匯出的同時將匯出按鈕禁用,當匯出成功後,再將匯出按鈕放開“
(我首先會將我做的全過程的思路和所遇到的問題和解決方案說一下,乾貨會在下面貼出來)
1、因為我們整個架構習慣用非同步請求,所以一開始我使用ajax非同步請求匯出Excel,結果發現匯出不了,背景程式也跑完了,日誌也記錄了,,就是沒有出現excel,更別說提示框了,網上查了很多,都說是因為ajax和後台交流用的是字元流,瀏覽器是不會識別你讓他下載的,所以此路不通。(也有小夥伴說用ajax同步,也試了,不行。又填上了一個坑。。。。)
2、然後就準備用form表單submit提交匯出,試了一下,發現可以啊,很高興,但是問題又來了,form表單提交後頁面其實重新整理了,如果不符合匯出條件我該怎麼提示使用者呢?新跳轉一個頁面嗎?感覺這樣不太合適,因為使用者辛辛苦苦輸入了半天的條件,然後等了半天后台校正(涉及到大資料量),結果等來的是跑到另一個頁面跟你說不能匯出,如果是我我會崩潰的,等了半天不說,奶奶個腿,我輸入半天的查詢條件還得重新輸入,這個不能忍。。好吧,這種方法不行,然後試著從後台往jsp頁面寫指令碼,但是也發現根本不執行,也就納悶了,最後,網上有一位小夥伴說用一個iframe的隱藏欄位,如果不合格話,再用流的方式將問題寫回來,最終問題解決了(代碼將會統一貼在下面)。
3、這樣感覺很完美了,但是問題還沒有完全解決,還有一個禁用按鈕的問題,這個問題想想很簡單,使用者點擊匯出時將按鈕禁用,匯出完成後傳回來一個標誌,然後再將按鈕放開,但是問題來了,這個標誌怎麼穿回來?一開始我想當然的想和錯誤提示一樣的結局方案,發現不行因為,我匯出Excel已經將response流給用掉了,我不可能在用流的方式將標誌寫回來了。這樣就會導致我放不開匯出按鈕,那老闆就不同意了,加班加點的找方法。終於,讓我找到了一個解決思路,用cookie來做。具體思路就是:使用者點擊匯出後,禁用按鈕,然後js寫個定時器輪訓找cookie,在將檔案流寫出後,我會放一個cookie在瀏覽器中,那麼此時js就能找到這個cookie了,找到後,首先將定時器給幹掉,再將cookie給幹掉(有點過河拆橋的感覺,哈哈),然後將匯出按鈕給放開。
(雖然問題解決了,但是cookie和定時器輪訓還是有一點不靠譜,希望大家有更好的解決方案,請大家不吝賜教,謝謝!!!)
前台代碼:
<button class="btn btn-sm btn-success" type="submit" id="detailEp" onclick="return exportCheck(true);" forbid="yes"><i class="icon-arrow-right bigger-110"></i> 匯出</button>
<script>$(function() {var timer = "";});//點擊匯出按鈕時禁用匯出按鈕$("#myForm").submit(function() {$("button[type=submit]",this).attr("disabled","disabled");//提交匯出後定時去查看有沒有匯出成功timer = setInterval(refrashPg,1000);})//匯出成功後會放開匯出按鈕的禁用function refrashPg() {if (getCk() =="1") {clearInterval(timer);$("#detailEp").removeAttr("disabled");}delCk();}//js擷取到cookiefunction getCk() {debuggervar ck = document.cookie.split(";"); var ckname = "";for (var i = 0;i<ck.length;i++) {var arr = ck[i].split("=");if (arr[0] =="updtstatus") {ckname = arr[1];break;}}return ckname;}//js刪除掉cookiefunction delCk() {var exp = new Date(); var name = "updtstatus";exp.setTime(exp.getTime()-1000);var cval = getCk();document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString();}}
</script>
後台匯出代碼就是普通的Java POI代碼:
1 public void buildExcelDocument(Map<String, Object> obj,String fileName,String type, 2 HttpServletRequest request, HttpServletResponse response) 3 throws Exception { 4 HSSFWorkbook workbook = new HSSFWorkbook(); 5 if ("1".equals(type)) { 6 List<Map<String, Object>> contentList = (List<Map<String, Object>>) obj.get("content"); 7 HSSFSheet sheet = workbook.createSheet("sheet1");//建立Excel的版本是2003-2007(xls) 如果需要2010的話,用 XSSFSheet 8 Map<String,String> titleList = (Map<String, String>) obj.get("title"); 9 //表頭的key 對應內容listMap中的map的key10 List<String> mkey = new ArrayList<String>();11 //表頭的value 表頭12 List<String> mvalue = new ArrayList<String>();13 Iterator<Entry<String, String>> it = titleList.entrySet().iterator();14 while(it.hasNext()){15 @SuppressWarnings("rawtypes")16 java.util.Map.Entry entry = (java.util.Map.Entry)it.next();17 mkey.add((String) entry.getKey());18 mvalue.add((String) entry.getValue());19 }20 sheet.setDefaultColumnWidth((short) 12); 21 HSSFCell cell = null; 22 for (int i = 0;i<mvalue.size();i++) {23 cell = getCell(sheet, 0, i);24 setText(cell, mvalue.get(i));25 }26 27 for (short i = 0; i < contentList.size(); i++) { 28 HSSFRow sheetRow = sheet.createRow(i+1); 29 Map<String, Object> entity = contentList.get(i); 30 for (int j = 0;j< mkey.size();j++) {31 if (entity.get(mkey.get(j)) instanceof String) {32 sheetRow.createCell(j).setCellValue((String)entity.get(mkey.get(j)));33 } else if (entity.get(mkey.get(j)) instanceof Double) {34 sheetRow.createCell(j).setCellValue((Double)entity.get(mkey.get(j)));35 } else if (entity.get(mkey.get(j)) instanceof Date){36 String date = (entity.get(mkey.get(j))).toString();37 sheetRow.createCell(j).setCellValue(date.substring(0, 10));38 } else if (entity.get(mkey.get(j)) instanceof BigDecimal){39 sheetRow.createCell(j).setCellValue((entity.get(mkey.get(j))).toString());40 }41 }42 }43 }44 } else if ("2".equals(type)) {45 List<String[]> contentList = (List<String[]>) obj.get("content"); 46 HSSFSheet sheet = workbook.createSheet("sheet1"); 47 String[] titleList = (String[]) obj.get("title");48 HSSFCell cell = null; 49 for (int i = 0;i<titleList.length;i++) {50 cell = getCell(sheet, 0, i);51 setText(cell, titleList[i]);52 }53 for (short i = 0; i < contentList.size(); i++) { 54 HSSFRow sheetRow = sheet.createRow(i+1); 55 String[] detail = contentList.get(i);56 for (int j = 0;j< detail.length;j++) {57 sheetRow.createCell(j).setCellValue((String)contentList.get(i)[j]);58 }59 }60 }61 62 //設定下載時用戶端Excel的名稱 63 String filename = fileName + ".xls"; 64 //處理中文檔案名稱 65 filename = Chineseutil.encodeFilename(filename, request); 66 response.setContentType("application/Vnd.ms-excel;charset=UTF-8"); 67 response.setHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes("gb2312"), "iso8859-1")); 68 OutputStream ouputStream = response.getOutputStream();69 workbook.write(ouputStream); 70 71 //匯出資料後將資訊存入cookie72 Cookie status = new Cookie("updtstatus", "1");73 status.setMaxAge(3600);//設定cookie存活時間1個小時74 response.addCookie(status);75 76 ouputStream.flush(); 77 ouputStream.close(); 78 }View Code
Java 匯出Excel的各種嘗試