Apache POI 5.0 XSSF单元格修改字体无法保存问题求助
问题分析与解决方案
你的问题核心在于Apache POI中Font是工作簿级别的共享对象,直接通过CellStyle.getFont()修改属性会影响所有引用该Font的单元格样式,而不是当前CellStyle独有的设置。
为什么会出现这种情况?
在你的代码逻辑里:
- 每次调用
writeCell时,你传入wb.createCellStyle()创建的新样式,再通过newStyle.cloneStyleFrom(cell.getCellStyle())复制原样式。但这一步复制的只是样式的引用,新样式的Font还是原单元格样式的Font实例,并没有被克隆成新对象。 - 当你执行
newStyle.getFont().setFontHeightInPoints(...)时,修改的是这个共享Font实例的属性。后续处理其他单元格时,如果又把该Font的字号改回20,所有使用这个Font的单元格都会同步变成20号字——这就是测试点0(单个单元格处理后)显示正确,但所有单元格处理完成后(测试点1)全部变回默认字号的根本原因。
修复方案
你需要为每个需要不同字号的样式创建独立的Font实例,而不是直接修改共享的Font对象。修改后的writeCell方法如下:
private void writeCell(Student stu, XSSFCell cell, XSSFCellStyle newStyle) { // 复制原单元格样式的基础属性 newStyle.cloneStyleFrom(cell.getCellStyle()); cell.setCellValue(stu.getName()); // 关键修复:创建新的Font实例,克隆原Font的所有属性 XSSFFont originalFont = cell.getCellStyle().getFont(); XSSFFont newFont = cell.getSheet().getWorkbook().createFont(); newFont.cloneStyleFrom(originalFont); // 修改新Font的字号 newFont.setFontHeightInPoints((short) (stu.isLongName() ? 17 : 20)); // 将新Font绑定到当前样式 newStyle.setFont(newFont); // 填充颜色逻辑保持不变 newStyle.setFillForegroundColor(stu.isBoarding() ? IndexedColors.PALE_BLUE.getIndex() : IndexedColors.LIGHT_GREEN.getIndex()); newStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); cell.setCellStyle(newStyle); }
额外优化建议
考虑到Excel格式对工作簿中CellStyle和Font的数量有上限,你可以提前缓存不同字号+颜色组合的样式,避免重复创建对象:
- 维护一个
Map,用「字号+颜色标识」作为键,对应的CellStyle作为值。 - 处理单元格时,先检查Map中是否已有对应样式,没有再创建并存入Map。
这样修改后,每个需要不同字号的单元格都会使用独立的Font实例,字号设置就能正确保存到输出文件中了。
内容的提问来源于stack exchange,提问作者RocketDev
相关产品推荐
相关产品推荐

