如何解决Apache POI导出xls时单元格样式超上限的IllegalStateException错误
问题根因
你代码的核心问题是单元格样式重复创建:
你在addContentMaintenanceHSSF方法中,每调用一次(也就是每添加一行数据),就执行workBook.createCellStyle()创建一个全新的样式实例,哪怕所有行的样式配置完全相同,也会生成新的样式对象。而XLS格式(Excel 97-2003)的工作簿最多支持4000个单元格样式,一旦你添加的行数超过4000,就会触发你遇到的上限异常。
关于不同服务器表现不同的原因:
大概率是两个环境实际生效的POI版本不一致:
- JBoss 4.2环境下要么加载了更低版本的POI(旧版本没有严格的样式上限校验逻辑,超出后不会主动抛异常),要么实际运行时导出的数据行数未达到4000的阈值。
- Wildfly环境下严格加载了你用的POI 3.17版本,该版本对样式上限的校验逻辑是强制生效的,超出后立刻抛出异常。
解决方案
核心修复:复用单元格样式
全局只创建一次通用样式,所有行的单元格共用同一个样式实例即可,不要每次添加行都新建样式,参考修改方案:
- 首先在初始化Workbook的阶段,就创建好内容行通用的样式
// 初始化工作簿时新增创建内容样式的逻辑,全局只执行一次 HSSFCellStyle contentStyle = workBook.createCellStyle(); contentStyle.setDataFormat((short) 7);
- 修改
addContentMaintenanceHSSF方法,将提前创建好的样式作为参数传入,删除方法内部创建样式的逻辑
public static HSSFWorkbook addContentMaintenanceHSSF(HSSFWorkbook workBook, ArrayList iptExcelContent, int rowNum, String name, CellStyle contentStyle) { HSSFRow row = workBook.getSheet(name).createRow((short) rowNum); LOG.debug("inside excel content method"); if(iptExcelContent!=null && !(iptExcelContent.isEmpty())){ for (int i = 0; i < iptExcelContent.size(); i++) { HSSFCell cellPlanId = row.createCell((short) i); cellPlanId.setCellType(HSSFCell.CELL_TYPE_NUMERIC); // 所有单元格复用同一个样式实例 cellPlanId.setCellStyle(contentStyle); if (iptExcelContent.get(i) != null) { String contentValue = ((String) iptExcelContent.get(i)); cellPlanId.setCellValue(contentValue); } else { cellPlanId.setCellValue(""); } } } return workBook; }
额外优化建议
- 如果数据量较大,建议改用XLSX格式导出,使用
SXSSFWorkbook实现流式写入,既可以突破XLS最多65536行的限制,也可以将单元格样式上限提升到64000个,性能表现更好。 - 可以排查Wildfly的类加载配置,排除服务器自带的POI包和项目依赖的POI包版本冲突的问题,确保运行时使用的是项目指定的POI版本。
内容的提问来源于stack exchange,提问作者Ashok Pandit
相关产品推荐
相关产品推荐

