介紹
Apache POI 是一個處理Miscrosoft Office各種文件格式的開源項目。我們可以使用 POI 在 Java 程序中對Miscrosoft Office各種文件進行讀寫操作。PS: 一般情況下,POI 都是用于操作 Excel 文件,如圖:
Apache POI 的應用場景:
- 銀行網銀系統導出交易明細
- 各種業務系統導出Excel報表
- 批量導入業務數據
入門案例
- 導入Apache POI的maven坐標:
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId>
</dependency>
- 數據寫入Excel文件:
public class POITest {/*** 通過POI創建Excel,并寫入文件內容*/public static void write() throws Exception {// 在內存中創建一個Excel文件XSSFWorkbook excel = new XSSFWorkbook();// 在Excel文件中創建一個sheet頁XSSFSheet sheet = excel.createSheet("info");// 在sheet頁中創建行對象,rownum的編號從0開始,寫1表示創建第2行XSSFRow row = sheet.createRow(1);// 在行中創建單元格, columnIndex也是從0開始,使用setCellValue寫入文本內容row.createCell(1).setCellValue("姓名");row.createCell(2).setCellValue("城市");// 創建新的一行row = sheet.createRow(2);row.createCell(1).setCellValue("張三");row.createCell(2).setCellValue("成都");row = sheet.createRow(3);row.createCell(1).setCellValue("李四");row.createCell(2).setCellValue("北京");FileOutputStream out = new FileOutputStream("/home/zxy/Projects/info.xlsx");excel.write(out);// 關閉資源out.close();excel.close();}public static void main(String[] args) throws Exception{write();}
}
運行效果:
- 從Excel中讀取數據
/*** 通過POI讀取Excel中的內容* @throws Exception*/public static void read() throws Exception{// 讀取磁盤上已經存在的Excel文件FileInputStream in = new FileInputStream(new File("/home/zxy/Projects/info.xlsx"));XSSFWorkbook excel = new XSSFWorkbook(in);// 讀取Excel文件中的第一個Sheet頁XSSFSheet sheet = excel.getSheetAt(0);// 獲取sheet頁中數據所在最后一行的行號int lastRowNum = sheet.getLastRowNum();for (int i = 1; i <= lastRowNum; i++) {// 獲得某一行XSSFRow row = sheet.getRow(i);// 獲得單元格對象String cellValue1 = row.getCell(1).getStringCellValue();String cellValue2 = row.getCell(2).getStringCellValue();System.out.println(cellValue1 + " " + cellValue2);}// 關閉資源excel.close();in.close();}public static void main(String[] args) throws Exception{read();}
效果:
應用
場景:導出(并下載)商戶最近30天的運營數據
注意:對導出數據的請求并沒有返回數據,因為報表導出功能本質上是文件下載,服務端會通過輸出流將Excel文件下載到客戶端瀏覽器。
實現步驟:
- 設計Excel模板文件
- 查詢近30天的運營數據
- 將查詢到的運營數據寫入模板文件
- 通過輸出流將Excel文件下載到客戶端瀏覽器
雖然POI可以設置文件的字體、字號、合并單元格等格式,但這會使得代碼變得非常復雜,所以提前在文本編輯器中設置好Excel的模版文件,然后通過讀取模版文件來填充數據,從而可以簡化代碼。
具體代碼:
controller部分:
/*** 導出運營數據報表* @param response*/@GetMapping("/export")@ApiOperation("導出運營數據報表")public void export(HttpServletResponse response){reportService.exportBusinessData(response);}
Service部分:
/*** 導出運營數據報表* @param response*/void exportBusinessData(HttpServletResponse response);
重點: Service的實現類中對應的方法:
/*** 導出運營數據報表** @param response*/@Overridepublic void exportBusinessData(HttpServletResponse response) {// 1. 查詢數據庫,獲取營業數據 --- 查詢最近30天的數據LocalDate dateBegin = LocalDate.now().minusDays(30);LocalDate dateEnd = LocalDate.now().minusDays(1);// 查詢概覽數據BusinessDataVO businessData = workspaceService.getBusinessData(LocalDateTime.of(dateBegin, LocalTime.MIN), LocalDateTime.of(dateEnd, LocalTime.MAX));// 2. 通過POI將數據寫入到Excel文件中InputStream in = this.getClass().getClassLoader().getResourceAsStream("template/運營數據報表模板.xlsx");try {// 基于模板文件創建一個新的Excel文件XSSFWorkbook excel = new XSSFWorkbook(in);// 獲取表格文件的Sheet頁XSSFSheet sheet = excel.getSheet("Sheet1");// 填充數據——時間sheet.getRow(1).getCell(1).setCellValue("時間:" + dateBegin + "至" + dateEnd);// 獲取第4行XSSFRow row = sheet.getRow(3);row.getCell(2).setCellValue(businessData.getTurnover());row.getCell(4).setCellValue(businessData.getOrderCompletionRate());row.getCell(6).setCellValue(businessData.getNewUsers());// 獲取第5行row = sheet.getRow(4);row.getCell(2).setCellValue(businessData.getValidOrderCount());row.getCell(4).setCellValue(businessData.getUnitPrice());// 填充明細數據for (int i = 0; i < 30; i++) {LocalDate date = dateBegin.plusDays(i);// 查詢某一天的數據BusinessDataVO businessDataVO = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));// 獲得某一行row = sheet.getRow(7 + i);row.getCell(1).setCellValue(date.toString());row.getCell(2).setCellValue(businessDataVO.getTurnover());row.getCell(3).setCellValue(businessDataVO.getValidOrderCount());row.getCell(4).setCellValue(businessDataVO.getOrderCompletionRate());row.getCell(5).setCellValue(businessDataVO.getUnitPrice());row.getCell(6).setCellValue(businessDataVO.getNewUsers());}// 3. 通過輸出流將Excel文件下載到客戶端瀏覽器ServletOutputStream out = response.getOutputStream();excel.write(out);// 關閉資源out.close();excel.close();} catch (IOException e) {throw new RuntimeException(e);}}
代碼細節補充:
workspaceService.getBusinessData:
@Overridepublic BusinessDataVO getBusinessData(LocalDateTime begin, LocalDateTime end) {/*** 營業額:當日完成訂單的總額* 有效訂單:當日完成訂單的數量* 訂單完成率:有效訂單數 / 總訂單數* 新增用戶:當日新增用戶的數量*/Map map = new HashMap();map.put("begin",begin);map.put("end",end);// 查詢訂單總數Integer totalOrderCount = orderMapper.getByMap(map);map.put("status", Orders.COMPLETED);// 營業額Double turnover = orderMapper.sumByMap(map);turnover = turnover ==null? 0.0 :turnover;// 有效訂單數Integer validOrderCount = orderMapper.getByMap(map);Double unitPrice = 0.0;Double orderCompletionRate = 0.0;if(totalOrderCount != 0 && validOrderCount != 0){// 訂單完成率orderCompletionRate = validOrderCount.doubleValue() / totalOrderCount;//平均客單價unitPrice = turnover / validOrderCount;}// 新增用戶數Integer newUsers = userMapper.countByMap(map);return BusinessDataVO.builder().turnover(turnover).validOrderCount(validOrderCount).orderCompletionRate(orderCompletionRate).unitPrice(unitPrice).newUsers(newUsers).build();}
實現效果: