介面的表格匯出為excel,並下載
最近,公司做了一個介面上的表格匯出為excel並下載的一個功能.下面將具體的做法記錄一下,以便後面複習.
首先先說一下需求
一.介面上有一個表格:
就上面這個表格,我是寫死的,要在介面上方有一個按鈕,匯出並下載的功能,上圖中我還沒有整理,見諒.
二.先做匯出,我用的是poi匯出,具體的例子網上有很多,需要導包什麼的,這些我就不做多的介紹了
1.我先在 介面上寫一個點選事件,使用window.open()方法進入到controller
$("#exportEx2").click(function () { var url = "${ctx}/analysis/mobileApp/" + _mobileAppId + "/demoExport2"; alert("url:"+url); window.open(url, "_self"); });
url是controller的地址,直接用window.open(),開啟
2.後臺controller的寫法
@RequestMapping("/mobileApp/{mobileAppId}/demoExport2") @ResponseBody public void doExport2(@PathVariable("mobileAppId") int mobileAppId, String _mobileAppVersionId,HttpServletRequest request, HttpServletResponse response) throws IOException { // 檔名 String filename = "自定義事件.xls"; BufferedInputStream in = null; BufferedOutputStream out = null; try { List<Map<String, String>> list = new ArrayList<Map<String, String>>(); for (int i = 0 ; i<18 ; i++) { //組裝測試資料 Map<String, String> map = new HashMap<String, String>(); map.put("ri", ""+i); map.put("name", "test0"+i); map.put("age", "23"); list.add(map); } // 第一步:定義一個新的工作簿 XSSFWorkbook wb = new XSSFWorkbook(); // 第二步:建立一個Sheet頁 XSSFSheet sheet = wb.createSheet("startTimeendTime"); sheet.setDefaultRowHeight((short) (2 * 256));//設定行高 sheet.setColumnWidth(0, 4000);//設定列寬 sheet.setColumnWidth(1,5500); sheet.setColumnWidth(2,5500); XSSFFont font = wb.createFont(); font.setFontName("宋體"); font.setFontHeightInPoints((short) 16); XSSFRow row = sheet.createRow(0); XSSFCell cell = row.createCell(0); cell.setCellValue("流水號 "); cell = row.createCell(1); cell.setCellValue("姓名"); cell = row.createCell(2); cell.setCellValue("年齡"); XSSFRow rows; XSSFCell cells; for (int i = 0; i < list.size(); i++) { // 第三步:在這個sheet頁裡建立一行 rows = sheet.createRow(i+1); // 第四步:在該行建立一個單元格 cells = rows.createCell(0); // 第五步:在該單元格里設定值 cells.setCellValue(list.get(i).get("ri")); cells = rows.createCell(1); cells.setCellValue(list.get(i).get("name")); cells = rows.createCell(2); cells.setCellValue(list.get(i).get("age")); cells = rows.createCell(3); } //開始執行寫入操作 String rootpath = request.getSession().getServletContext().getRealPath( "/"); File file = new File(rootpath+"temp.xls"); wb.write(new FileOutputStream(file)); response.setContentType("application/vnd.ms-excel; charset=utf-8") ; String showName = "多事件/多維度表格.xlsx"; response.setHeader("Content-Disposition", "attachment;filename=" + new String(showName.getBytes("UTF-8"), "iso8859-1")); in = new BufferedInputStream(new FileInputStream(file)); out = new BufferedOutputStream(response.getOutputStream()); byte[] data = new byte[1024]; int len = 0; while (-1 != (len=in.read(data, 0, data.length))) { out.write(data, 0, len); } } catch (Exception e) { logger.error("download file encount error!"); } finally { try { if (in != null) { in.close(); } if (out != null) { out.close(); } } catch (IOException e) { logger.error("download file colse io encount error!"); } } }
首先這個controller的前面,我拼了一個List<Map<String, String>> ,這個裡面存放的是資料.
後來使用了poi的一些api,去建立excel工作sheet等,這些我也就不細說了,回頭好好看看poi的demo就啥都明白了,並且我這裡是寫死的資料,for迴圈都是遍歷的死資料,還是比較簡單,按理說寫到這裡,controller走完 ,前臺就可以彈出一個框,也就是下面這個框:
然後選擇下載地址就可以匯出並下載了,但是事情沒有想象的那麼簡單,我點完按鈕之後,發現跳轉到了一個空白頁面
window.open()函式原本就是開啟一個頁面,我設定的"_self",也就是在本瀏覽器頁面再開啟一個頁面,但是沒有開啟,是為什麼呢,後來一遍一遍試,並且叫來了老大幫我看,發現使我們的專案會攔截這個請求,也就是說我新寫的一個controller沒有再攔截器的配置頁面配置,所以會攔截,接下來,我在攔截器的配置頁面中配置了這個controller,就彈出來了,下來下來的excel的內容是我拼接的list<Map>中的內容.
3.接下來,我怎麼獲取到頁面中的表格中的資料,然後傳到後臺呢,這就用到了jquery的知識,
首先我前段頁面的表格其實就是一個table 如下:
<table style="width: 100%; border: 1px solid black;" id="excelTable">
<tr style="width: 100%; height: 30px; border: 1px solid black;">
<td style="width: 20%;">時間</td>
<td>域名</td>
<td>城市</td>
<td>使用者量</td>
<td>頁面瀏覽量</td>
</tr>
<tr>
<td>09-12 週三</td>
<td>com.app.tingyun</td>
<td>北京</td>
<td>32</td>
<td>76</td>
</tr>
<tr>
<td>09-12 週四</td>
<td>com.app.tingyun</td>
<td>上海</td>
<td>32</td>
<td>76</td>
</tr>
<tr>
<td>09-12 週三</td>
<td>com.app.tingyun</td>
<td>廣州</td>
<td>32</td>
<td>76</td>
</tr>
</table>
我可以試用jqyery遍歷這個table,將其中的內容轉換成json字串,然後傳到後臺
遍歷table的程式碼如下:
function getExcelJson(){
var excelJson = new Array();
$("#excelTable tr").each(function(i){
var arr = new Array();
$(this).children("td").each(function(j){
var aa = $(this).text();
arr.push($(this).text())
});
excelJson.push(arr);
});
var excelJsonTxt = JSON.stringify(excelJson);
return excelJsonTxt;
}
返回一個json型別的字串,然後再url後面加上引數,使用get請求的方式傳過去,其實這裡肯定不能用get請求方式將這個引數傳過去,得需要post請求,但是時間來不及了,我就先使用get方式傳過去了,也沒報錯,後面我再修改成post請求方式吧,所以點選事件中的url修改為如下:
$("#exportEx2").click(function () {
var excelJsonTxt = getExcelJson();
var url = "${ctx}/analysis/mobileApp/" + _mobileAppId + "/demoExport2?excelJsonTxt="+encodeURIComponent(excelJsonTxt);
alert("url:"+url);
window.open(url, "_self");
});
這裡就是將excelJsonTxt 引數傳過去,並且做了一下 encode處理,我這裡就不多說了,搞過前端的都懂.
4.後面的controller 相應的也需要修改,接收到excelJsonTxt 引數後,動態的填充excel,controller如下:
/**
* @Description: 匯出excel
* @auther:
* @date: 2018/9/30/0030 14:34
* @return
*/
@RequestMapping("/mobileApp/{mobileAppId}/demoExport2")
@ResponseBody
public void doExport2(@PathVariable("mobileAppId") int mobileAppId, String _mobileAppVersionId,HttpServletRequest request, HttpServletResponse response) throws IOException {
// 檔名
String filename = "自定義事件.xls";
String excelJsonTxt = request.getParameter("excelJsonTxt");
JSONArray jsonArray = JSON.parseArray(excelJsonTxt);
BufferedInputStream in = null;
BufferedOutputStream out = null;
try {
// 第一步:定義一個新的工作簿
XSSFWorkbook wb = new XSSFWorkbook();
// 第二步:建立一個Sheet頁
XSSFSheet sheet = wb.createSheet("startTimeendTime");
sheet.setDefaultRowHeight((short) (2 * 256));//設定行高
sheet.setColumnWidth(0, 4000);//設定列寬
sheet.setColumnWidth(1,5500);
sheet.setColumnWidth(2,5500);
XSSFFont font = wb.createFont();
font.setFontName("宋體");
font.setFontHeightInPoints((short) 16);
XSSFRow row = sheet.createRow(0);
XSSFCell cell = row.createCell(0);
JSONArray tHead = (JSONArray) jsonArray.get(0);
for(int i=0; i<tHead.size(); i++){
cell.setCellValue(tHead.get(i).toString());
cell = row.createCell(i+1);
}
XSSFRow rows;
XSSFCell cells;
for (int i = 1; i < jsonArray.size(); i++) {
// 第三步:在這個sheet頁裡建立一行
rows = sheet.createRow(i+1);
// 第四步:在該行建立一個單元格
cells = rows.createCell(0);
// 第五步:在該單元格里設定值
JSONArray tBody = (JSONArray) jsonArray.get(i);
for(int j=0; j<tBody.size();j++){
cells.setCellValue(tBody.get(j).toString());
cells = rows.createCell(j+1);
}
}
//開始執行寫入操作
String rootpath = request.getSession().getServletContext().getRealPath( "/");
File file = new File(rootpath+"temp.xls");
wb.write(new FileOutputStream(file));
response.setContentType("application/vnd.ms-excel; charset=utf-8") ;
String showName = "多事件/多維度表格.xlsx";
response.setHeader("Content-Disposition", "attachment;filename=" + new String(showName.getBytes("UTF-8"), "iso8859-1"));
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(response.getOutputStream());
byte[] data = new byte[1024];
int len = 0;
while (-1 != (len=in.read(data, 0, data.length))) {
out.write(data, 0, len);
}
} catch (Exception e) {
logger.error("download file encount error!");
} finally {
try {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
} catch (IOException e) {
logger.error("download file colse io encount error!");
}
}
}
將接受到的excelJsonTxt 引數轉換成JSONARRAY物件,然後填充到單元格中,後面的程式碼一看便知.
至此,匯出為excel並下載將告一段落,其實其中還有很多沒有明白的地方,以後在慢慢補充.
不積跬步,無以至千里
不積小流,無以成江海