java後臺生成excel,前臺發請求下載

爲了這個功能找了兩天資料,最後還是弄出來了,在此記錄一下
我用的 ssm + maven ,操作excel的包是poi-ooxml

maven座標如下:

	  <dependency>
		  <groupId>org.apache.poi</groupId>
		  <artifactId>poi-ooxml</artifactId>
		  <version>3.9</version>
	  </dependency>

原理是這樣的:

前臺發送請求到後臺,controller接收後調用生成excel文件的邏輯,此時的excel文件是在內存中的。
如果對此文件的操作是輸出流指定地址,如:
	OutputStream out = new FileOutputStream("E:/Members.xls");
則就保存在了本地 e 盤中。因爲輸出流是new出來的,和瀏覽器沒有任何關係,那如果這一步的輸出流來源和瀏覽器有關係不就有戲了嗎?
controller接收的請求是自動帶有參數HttpServletResponse的,而且有方法可以獲取輸出流:

	response.getOutputStream();
然後response要告訴瀏覽器我這個響應是下載excel文件,所以需要設置一下,如下:
	response.setCharacterEncoding("UTF-8");
	response.setContentType("application/vnd.ms-excel;charset=utf-8");// 設置contentType爲excel格式
	response.setHeader("Content-Disposition", "Attachment;Filename="+ fileName+".xls");
其中的fileName是自己定義的,後面的完整代碼中有東西。
最後是最關鍵的一步,之前看了很多文章都沒看到這一步,所以怎麼都沒成功。
其實很簡單,因爲到這一步excel文件和response或者說和輸出流沒有任何關係,所以需要創造這種關係, 如下:
workbook.write(fos);
其中workboo是操作excel的類,fos就是獲取的輸出流。這樣就可以了。

完整的代碼:

	@RequestMapping("info")
	public void info(HttpServletRequest request, HttpServletResponse response){
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("sequence", "0001");
		map.put("date", "2018/01/04");
		map.put("chetaihao", "1#");
		map.put("productName", "產品名稱");
		map.put("specification", "規格");
		map.put("memo", "備註");
		map.put("inspectRecordBizList", "一個list");

		HSSFWorkbook wb = new HSSFWorkbook();
		Sheet sheet = wb.createSheet("測試表");
		Row row = sheet.createRow(0);
		int i = 0;
		for(String key : map.keySet()){
			Cell cell = row.createCell(i);
			cell.setCellValue((String) map.get(key));
			i++;
		}
		OutputStream fos = null;
		try {
			fos = response.getOutputStream();
			String userAgent = request.getHeader("USER-AGENT");
			String fileName = "test";
			try {
				if(StringUtils.contains(userAgent, "Mozilla")){
					fileName = new String(fileName.getBytes(), "ISO8859-1");
				}else {
					fileName = URLEncoder.encode(fileName, "utf8");
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}

			response.setCharacterEncoding("UTF-8");
			response.setContentType("application/vnd.ms-excel;charset=utf-8");// 設置contentType爲excel格式
			response.setHeader("Content-Disposition", "Attachment;Filename="+ fileName+".xls");
			wb.write(fos);
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

第一、

map是儲存數據的,不想用的話就在後面的for中手動添加單元格的值。map的數據來源可以是像現在的直接添加,也可以是數據庫查出來的。它只是儲存數據,用list或者其他的也行,只要是往單元格存值時有對應數據就行。

第二、

fileName就像這樣自己定義一個或者按照業務需求定義,try-catch的處理是針對不同的瀏覽器來的,否則文件名可能亂碼

第三、

response的幾個設置之前說了,是告訴瀏覽器我這個響應是需要你以下載的方式呈現的。

第四、

workbook寫入輸出流

第五、

excel的操作。
最後說這個是因爲操作excel可以單獨成一章,這裏簡單解釋下。excel文件的來源可以是已經存在的文件,通過流讀取。也可以是新創建的。操作excel文件就是先創建或者獲取sheet(工作表),再創建或者獲取row(第幾行),再創建或者獲取cell(單元格)往cell裏面set值或者get值就行。其中涉及合併單元格和單元格樣式我沒寫,資料很多。
網上很多資料用的數據類型,比如List<Map<String,Object>>,其實和map一樣,都是存儲數據的,可能他們的數據來源是數據庫。然後直接生成了一張和他們業務邏輯有關的excel表,所以一開始我沒看懂。我現在這個只是創建了一個表頭而已,因爲主要功能是實現前臺發送的請求去下載後臺的excel文件,能下載纔是我想要的。生成的excel表需要哪些東西再添加。

對了,前臺的請求我是用的一個button,綁定點擊事件,然後 location.href="xxx" 發送的請求

最後我之所以能弄出來是因爲參考這個博客:

http://blog.csdn.net/u014621859/article/details/54944059



LG

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章