Apache POI autoSizeColumn在Unix环境WebSphere9中失效问题排查
解决Unix服务器上POI autoSizeColumn() 抛出ArrayIndexOutOfBoundsException的问题
你遇到的这个问题,本质是POI 3.8版本在无图形界面的Unix环境下,自动调整列宽时依赖AWT字体渲染逻辑,而服务器端字体配置或版本bug导致的异常。虽然你已经尝试了-Djava.awt.headless=true和Arial字体配置,但早期POI版本对headless环境的字体处理确实存在不少坑。
问题根源拆解
POI 3.8的autoSizeColumn()方法会调用AWT的TextLayout来计算文本宽度,Unix环境下如果JVM无法正确找到或映射字体,就会在CompositeFont.getMapper()中触发数组越界——因为系统找不到可用的字体映射表,导致索引访问失败。
可行的解决方案
1. 升级POI版本(最推荐)
POI 3.8是2011年的老旧版本,后续版本(比如3.17及以上)彻底重构了列宽计算逻辑,不再依赖AWT的字体处理,修复了大量headless环境下的异常。你只需要替换项目中的poi-3.8.jar为最新稳定版的POI包(包括poi、poi-ooxml等相关依赖),这个问题大概率会直接消失。
2. 手动指定单元格字体并提前初始化
如果暂时无法升级POI,可以在代码中显式为所有单元格指定Arial字体,避免JVM动态查找字体时出错:
// 初始化Arial字体 HSSFFont font = workbook.createFont(); font.setFontName("Arial"); font.setFontHeightInPoints((short)12); // 创建单元格样式并应用字体 HSSFCellStyle style = workbook.createCellStyle(); style.setFont(font); // 给所有单元格应用这个样式 for (Row row : mySheet) { for (Cell cell : row) { cell.setCellStyle(style); } } // 再执行自动列宽调整 for (int colNum= 0; colNum <= 14; colNum++) { mySheet.autoSizeColumn(colNum); }
这样autoSizeColumn()会使用你指定的已知字体计算宽度,减少系统字体查找的不确定性。
3. 修复Unix环境的字体配置
确保Arial字体在服务器上正确安装并被JVM识别:
- 把Arial的TTF字体文件(比如
arial.ttf、arialbd.ttf)放到WebSphere使用的JRE的lib/fonts目录,同时确保运行WebSphere的用户对该目录有读取权限。 - 用
fc-list | grep Arial命令检查系统是否识别Arial字体,如果没有,需要安装fontconfig并配置字体路径,让系统能找到Arial。 - 可以尝试添加JVM参数
-Dsun.java2d.fontpath=/path/to/your/fonts,强制指定JVM的字体搜索路径。
4. 替换autoSizeColumn为手动计算列宽
如果以上方法都无效,可以放弃autoSizeColumn(),手动计算列宽:
// 自定义列宽计算逻辑,根据文本长度和字体大小估算 int defaultWidth = 10 * 256; // POI的列宽单位是1/256个字符宽度 for (int colNum= 0; colNum <= 14; colNum++) { int maxLength = 0; for (Row row : mySheet) { Cell cell = row.getCell(colNum); if (cell != null) { String cellValue = cell.toString(); maxLength = Math.max(maxLength, cellValue.length()); } } // 乘以系数,预留一些边距 int columnWidth = (maxLength + 2) * 256; mySheet.setColumnWidth(colNum, Math.min(columnWidth, 255 * 256)); // 最大列宽限制 }
这种方法不依赖AWT字体渲染,完全避免了字体相关的异常。
内容的提问来源于stack exchange,提问作者Vishwas
相关产品推荐
相关产品推荐

