我用的 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值就行。其中涉及合併單元格和單元格樣式我沒寫,資料很多。
對了,前臺的請求我是用的一個button,綁定點擊事件,然後 location.href="xxx" 發送的請求
最後我之所以能弄出來是因爲參考這個博客:
http://blog.csdn.net/u014621859/article/details/54944059