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;
}
最終導出的樣子
結語:
一切實現在於自己,路人只留下腳印。