Java POI 大資料生成Excel
阿新 • • 發佈:2018-11-13
POI 提供了 好幾種生成Excel的方式,檢視官方的API可以發現
第一種:HSSFWorkbook
針對是 EXCEL2003 版本,副檔名為 .xls;所以 此種的侷限就是 匯出的行數 至多為 65535 行,此種 因為行數不足七萬行 所以 一般不會發生 記憶體不足的情況(OOM)
第二種:XSSFWorkbook
這種形式的出現 是由於 第一種HSSFWorkbook 的侷限性而產生的,因為其所匯出的行數比較少,所以 XSSFWookbook應運而生 其 對應的是EXCEL2007+(1048576行,16384列)副檔名 .xlsx,最多可以 匯出 104 萬行,不過 這樣 就伴隨著一個問題---OOM 記憶體溢位,原因是 你所 建立的 book sheet row cell 等 此時是存在 記憶體的 並沒有 持久化,那麼 隨著 資料量增大 記憶體的需求量也就增大,那麼很大可能就是要 OOM了,那麼 怎麼解決呢?
第三種:SXSSFWorkbook poi.jar 3.8+
第二種遇到的問題該如何解決呢? 因為資料量過大 導致記憶體吃不消 那麼 可以 讓記憶體 到量持久化 嗎?
答案是 肯定的,
此種的情況 就是 設定 最大 記憶體條數 比如 設定 最大記憶體量為5000 rows --new SXSSFWookbook(5000),此時 當 行數 達到 5000 時,把 記憶體 持久化 寫到 檔案中,以此 逐步 寫入 避免OOM,那麼這樣 就完美解決了 大資料下 匯出 的問題;
明顯發現最後一種是處理大資料的最好方式:
//建立Excel的workbook 物件 SXSSFWorkbook workbook = new SXSSFWorkbook(1000); //迴圈生成多個Sheet 頁 如果需要 for(Map<String, Object> sheetTempMap : sheetList){ 建立sheet 頁名字 Sheet sheet = createSheetName(workbook, sheetTempMap); //get column map 獲取列頭和列屬性的Map 這部分的資料可以放到資料庫裡面,也可以寫道js 檔案上,方便靈活的生成列頭,線上也可直接修改。 Map<String, String> columnMap = getColumnMap(sheetTempMap,outputVO); if(CollectionUtils.isEmpty(columnMap)){ m_Logger.error("Column Map is empty,please setup."); return outputVO; } //create header createHeader(columnMap, workbook, sheet,0); //create line and write data //這裡使用Mybatis返回Map 的資料型別,這樣就可通過上面的columnMap直接獲取資料 List<Map<String, Object>> resultMap = getResultListMap(sheetTempMap); createLine(columnMap, resultMap, workbook, sheet); } List<File> files = new ArrayList<File>(); writeExcel(workbook,params,files); /** * create Header * @param workbook * @param sheetTempMap * @return */ private void createHeader(Map<String, String> columnMap,SXSSFWorkbook workbook, Sheet sheet,int currentRow) { CellStyle columnTopStyle = getColumnTopStyle(workbook); Row rowRowName = sheet.createRow(currentRow); int columnTemp = 0; for (Map.Entry<String, String> headerMap : columnMap.entrySet()) { Cell cellRowName = rowRowName.createCell(columnTemp); cellRowName.setCellType(1); XSSFRichTextString text = new XSSFRichTextString((String) headerMap.getKey()); cellRowName.setCellValue(text); cellRowName.setCellStyle(columnTopStyle); sheet.autoSizeColumn(columnTemp); columnTemp++; } } private void createLine(Map<String, String> columnMap,List<Map<String, Object>> resultMap, SXSSFWorkbook workbook,Sheet sheet) { CellStyle columnStyle = getStyle(workbook); int rowCount = 1; for (Map<String, Object> dataMap : resultMap) { int rowColunmCount = 0; Row row = sheet.createRow(rowCount); for (Map.Entry<String, String> rowMap : columnMap.entrySet()) { Cell cell = row.createCell(rowColunmCount); cell.setCellType(1); String currentValue = String.valueOf(dataMap.get(rowMap.getValue())); XSSFRichTextString text = new XSSFRichTextString(currentValue); if (String.valueOf(text).trim().equals("null".trim())) { text = new XSSFRichTextString(""); } cell.setCellValue(text); cell.setCellStyle(columnStyle); sheet.autoSizeColumn(rowColunmCount); rowColunmCount++; } rowCount++; } } /** * create sheet name * default vale is sheet1 * @param workbook * @param sheetTempMap * @return */ private Sheet createSheetName(SXSSFWorkbook workbook,Map<String, Object> sheetTempMap) { String sheetName = "sheet1"; if(sheetTempMap.containsKey("sheetName")){ sheetName = String.valueOf(sheetTempMap.get("sheetName")); } Sheet sheet = workbook.createSheet(sheetName); return sheet; } private Map<String,String> getColumnMap (){ //這裡使用了一個LinkedHashMap 使得資料有序化。 Map<String,String> columnMap = new LinkedHashMap<String, String>(); columnMap.put("列頭","列屬性"); return columnMap ; } //以下是header 和 row data 的style 可以參考下 public CellStyle getColumnTopStyle(SXSSFWorkbook workbook) { Font font = workbook.createFont(); font.setFontHeightInPoints((short) 11); font.setBoldweight((short) 700); font.setFontName("Courier New"); CellStyle style = workbook.createCellStyle(); style.setBorderBottom((short) 1); style.setBottomBorderColor((short) 10); style.setBorderLeft((short) 1); style.setLeftBorderColor((short) 8); style.setBorderRight((short) 1); style.setRightBorderColor((short) 8); style.setBorderTop((short) 1); style.setTopBorderColor((short) 8); style.setFont(font); style.setWrapText(false); style.setAlignment(CellStyle.ALIGN_CENTER); style.setVerticalAlignment((short) 1); style.setFillForegroundColor((short) 10); style.setFillPattern((short) 1); return style; } public CellStyle getStyle(SXSSFWorkbook workbook) { Font font = workbook.createFont(); font.setFontName("Courier New"); CellStyle style = workbook.createCellStyle(); style.setBorderBottom((short) 1); style.setBottomBorderColor((short) 8); style.setBorderLeft((short) 1); style.setLeftBorderColor((short) 1); style.setBorderRight((short) 1); style.setRightBorderColor((short) 8); style.setBorderTop((short) 1); style.setTopBorderColor((short) 8); style.setFont(font); style.setWrapText(false); style.setAlignment(CellStyle.ALIGN_CENTER); style.setVerticalAlignment((short) 1); return style; }
最終匯出的樣子
結語:
一切實現在於自己,路人只留下腳印。