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;
}
最终导出的样子
结语:
一切实现在于自己,路人只留下脚印。