前言:在實際開發中經常需要將數據庫的數據導出成excel文件,poi方式則是其中一種較為常用的導出框架。簡單讀取excel文件在之前的一篇有說明
本項目實現需求:user發出一個導出student信息的請求,直接下載包含所有student信息的excel文件到本機。只貼出關鍵代碼,未貼出的很簡單,自行腦補
整體流程(服務器端):接收請求------>取出數據庫數據------>將數據存成excel臨時文件------>通過響應頭讓瀏覽器下載此臨時文件------>刪除臨時文件
項目結構:
1.導入依賴
<!--poi--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.0</version> </dependency>
2.controller
package com.zjk.excel.controller; import com.zjk.excel.service.UserServiceI; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletResponse; import java.io.*; /** * @Auther: zjk * @Date: 2019/9/16 * @Description: */ @Controller @RequestMapping("/user") public class UserController { @Autowired UserServiceI userServiceI; @RequestMapping("/export") public void exportStu(HttpServletResponse response){ //設置默認的下載文件名 String name = "學生信息表.xlsx"; try { //避免文件名中文亂碼,將UTF8打散重組成ISO-8859-1編碼方式 name = new String (name.getBytes("UTF8"),"ISO-8859-1"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } //設置響應頭的類型 response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); //讓瀏覽器下載文件,name是上述默認文件下載名 response.addHeader("Content-Disposition","attachment;filename=\"" + name + "\""); InputStream inputStream=null; OutputStream outputStream=null; //在service層中已經將數據存成了excel臨時文件,並返回了臨時文件的路徑 String downloadPath = userServiceI.exportStu(); //根據臨時文件的路徑創建File對象,FileInputStream讀取時需要使用 File file = new File(downloadPath); try { //通過FileInputStream讀臨時文件,ServletOutputStream將臨時文件寫給瀏覽器 inputStream = new FileInputStream(file); outputStream = response.getOutputStream(); int len = -1; byte[] b = new byte[1024]; while((len = inputStream.read(b)) != -1){ outputStream.write(b); } //刷新 outputStream.flush(); } catch (Exception e) { e.printStackTrace(); } finally { //關閉輸入輸出流 try { if(inputStream != null) { inputStream.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } //最后才能,刪除臨時文件,如果流在使用臨時文件,file.delete()是刪除不了的 file.delete(); } }
3.service
package com.zjk.excel.service.impl; import com.zjk.excel.dao.StudentDao; import com.zjk.excel.dao.UserDao; import com.zjk.excel.entity.Student; import com.zjk.excel.service.UserServiceI; import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.io.*; import java.util.List; import java.util.UUID; /** * @Auther: zjk * @Date: 2019/9/16 * @Description: */ @Service public class UserService implements UserServiceI { //創建臨時文件存放的路徑 private String temp="d:\\temp\\excel\\"; @Autowired UserDao userDao; @Autowired StudentDao studentDao; @Override public String exportStu() { List<Student> list = studentDao.queryAllStu(); //創建工作簿 XSSFWorkbook xssfWorkbook = new XSSFWorkbook(); //創建工作表 XSSFSheet sheet = xssfWorkbook.createSheet(); xssfWorkbook.setSheetName(0,"學生信息表"); //創建表頭 XSSFRow head = sheet.createRow(0); String[] heads = {"編號","姓名","年齡","性別","手機號"}; for(int i = 0;i < 5;i++){ XSSFCell cell = head.createCell(i); cell.setCellValue(heads[i]); } for (int i = 1;i <= 4;i++) { Student student = list.get(i - 1); //創建行,從第二行開始,所以for循環的i從1開始取 XSSFRow row = sheet.createRow(i); //創建單元格,並填充數據 XSSFCell cell = row.createCell(0); cell.setCellValue(student.getS_id()); cell = row.createCell(1); cell.setCellValue(student.getS_name()); cell = row.createCell(2); cell.setCellValue(student.getS_age()); cell = row.createCell(3); cell.setCellValue("男".equals(student.getS_gender().trim())?"男":"女"); cell = row.createCell(4); cell.setCellValue(student.getS_tel()); } //創建臨時文件的目錄 File file = new File(temp); if(!file.exists()){ file.mkdirs(); } //臨時文件路徑/文件名 String downloadPath = file + "\\" +System.currentTimeMillis() + UUID.randomUUID(); OutputStream outputStream = null; try {
//使用FileOutputStream將內存中的數據寫到本地,生成臨時文件 outputStream = new FileOutputStream(downloadPath); xssfWorkbook.write(outputStream); outputStream.flush(); } catch (Exception e) { e.printStackTrace(); } finally { try { if(outputStream != null) { outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return downloadPath; } }
4.效果
WPS打開后:可以說是非常的丑陋了,接下來優化一下
在service中增加如下代碼:總體而言還是很麻煩的,創建CellStyle,還要在你想改變樣式的cell進行cell.setCellStyle(style1)才可以
*博主用的版本比較新,所以很多地方較舊版本有區別
//創建styleHead CellStyle styleHead = xssfWorkbook.createCellStyle(); styleHead.setFillForegroundColor(IndexedColors.SKY_BLUE.getIndex());//背景色 styleHead.setFillPattern(FillPatternType.SOLID_FOREGROUND); styleHead.setAlignment(HorizontalAlignment.CENTER);//水平居中 XSSFFont font = xssfWorkbook.createFont(); font.setBold(true);//加粗 font.setFontHeight((short)240);//字體大小 styleHead.setFont(font); //創建style1 CellStyle style1 = xssfWorkbook.createCellStyle(); style1.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.getIndex());//背景色 style1.setFillPattern(FillPatternType.SOLID_FOREGROUND); style1.setAlignment(HorizontalAlignment.CENTER);//水平居中 //創建style2 CellStyle style2 = xssfWorkbook.createCellStyle(); style2.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.getIndex());//背景色 style2.setFillPattern(FillPatternType.SOLID_FOREGROUND); style2.setAlignment(HorizontalAlignment.CENTER);//水平居中
sheet.setColumnWidth(4,3500);//給第5列設置寬度(tel欄)
優化后:
總結一下:
poi的簡單使用還是不難的,說白了就數據庫一個表對應一個sheet,表的一行對應一個row,表某一行的一個數據對應一個cell,嗯,就是這么簡單。
說到調樣式就非常頭疼了,而且新版本的較之前改動比較大,百度出來的東西很多都沒法用,勉強搗鼓了一些出來。
最后給自己打打氣-——世上無難事,只要肯登攀!
注意事項:
不要使用post請求,應該用get請求
最后推薦一個中文poi文檔:
https://www.cnblogs.com/fqfanqi/p/6172223.html