1. 程式人生 > >Java POI 大資料生成Excel

Java POI 大資料生成Excel

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;
	}

 

最終匯出的樣子

結語:

一切實現在於自己,路人只留下腳印。