1. 程式人生 > >介面的表格匯出為excel,並下載

介面的表格匯出為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並下載將告一段落,其實其中還有很多沒有明白的地方,以後在慢慢補充.

不積跬步,無以至千里

不積小流,無以成江海