Apache POI 在 Linux 无图形界面环境下因字体配置问题导致Excel导出失败的解决方案

问题描述

  • 在阿里云ECS(Alibaba Cloud Linux 3)上,使用 Apache POI 的 SXSSFWorkbook 导出 Excel 时出现 NullPointerException
  • 服务器为无图形界面环境,JDK 为 OpenJDK 1.8(headless)。

环境信息(关键信息)

  • 操作系统:阿里云ECS(Alibaba Cloud Linux 3 - 无图形界面环境)
  • JDK:OpenJDK 1.8.0_412
  • JDK 类型:java-1.8.0-openjdk-headless
  • Apache POI:3.14

错误堆栈(核心片段)

text 复制代码
java.lang.NullPointerException
 at org.apache.poi.ss.util.SheetUtil.getDefaultCharWidth(SheetUtil.java:254)
 at org.apache.poi.xssf.streaming.SXSSFSheet.<init>(SXSSFSheet.java:77)
 at org.apache.poi.xssf.streaming.SXSSFWorkbook.createAndRegisterSXSSFSheet(...)

问题分析

  • 根因:AWT 字体系统在无图形界面环境初始化不完整,SXSSFWorkbook 创建时需要计算默认字符宽度,触发 NPE。
  • 现象触发条件:服务器无图形环境(DISPLAY 为空)、未装 X11 相关库;headless JDK 对字体配置更严格。

关键检测命令与结果(摘要)

bash 复制代码
# 图形/字体/Java环境
DISPLAY:
ls -la /usr/share/fonts/       # 存在 dejavu 目录
rpm -qa | grep -i x11          # 未安装X11包
java -Djava.awt.headless=true -version
# 输出:openjdk version "1.8.0_412" ...

# JDK 信息
which java                     # /usr/bin/java
java -XshowSettings:properties -version | grep -E 'java.version|java.home|os.name|os.version'
# java.home=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.412...  os.name=Linux

# POI 版本
find /root/chp-fbs -name '*.jar' -exec jar -tf {} \; 2>/dev/null | grep -i poi | head -5 || echo '未找到POI相关JAR
# BOOT-INF/lib/poi-ooxml-3.14.jar
# BOOT-INF/lib/poi-3.14.jar
# BOOT-INF/lib/poi-ooxml-schemas-3.14.jar

解决方案

  1. 添加 JVM 参数(尝试但未完全解决)
bash 复制代码
java -Djava.awt.headless=true -jar your-app.jar

说明:可启动,但导出仍报 NPE,仅 headless 参数不足以补齐字体环境。

  1. 安装字体包与图形字体支持(最终解决)
bash 复制代码
yum install -y fontconfig \
    dejavu-fonts-common \
    dejavu-sans-fonts \
    dejavu-serif-fonts \
    dejavu-sans-mono-fonts \
    java-1.8.0-openjdk-devel
fc-cache -fv

安装后(节选输出):

复制代码
/usr/share/fonts/dejavu: caching, new cache contents: 21 fonts
/usr/bin/fc-cache-64: succeeded

结论:安装字体 + headless 参数后,SXSSFWorkbook 对象创建正常。

  1. 备用方案:使用 XSSFWorkbook替代SXSSFWorkbook
  • 特点:不依赖 AWT 字体,适合中小数据量,内存开销更高(XSSFWorkbook 会全量驻内存,数据量很大时确实更占内存并可能 OOM)
  • 示例(仅演示,不含项目真实代码):
java 复制代码
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class TestXSSF {
    public static void main(String[] args) throws Exception {
        XSSFWorkbook workbook = new XSSFWorkbook();
    }
}

(可选)测试 SXSSFWorkbook 的最小示例

java 复制代码
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import java.io.FileOutputStream;
public class TestSXSSF {
    public static void main(String[] args) throws Exception {
        SXSSFWorkbook wb = new SXSSFWorkbook();
        Sheet s = wb.createSheet("测试");
        Row r = s.createRow(0); r.createCell(0).setCellValue("测试数据");
        try (FileOutputStream out = new FileOutputStream("/tmp/test_sxssf.xlsx")) {
            wb.write(out);
        }
        wb.close();
    }
}

解决方案验证过程

  1. 验证字体安装
bash 复制代码
fc-list | head -10
# 显示 DejaVu 系列字体(如 DejaVuSans.ttf)
fc-cache -fv
# /usr/share/fonts/dejavu: ... 21 fonts
  1. 验证 Java AWT 运行环境
bash 复制代码
java -Djava.awt.headless=true -version
# openjdk version "1.8.0_412" ...
  1. 验证Excel导出接口
bash 复制代码
curl -s 'http://192.168.0.100/xxx/export?page=1&rows=10' \
  -H 'Accept: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' \
  -o /tmp/test_export.xlsx
ls -la /tmp/test_export.xlsx
file /tmp/test_export.xlsx     # Microsoft Excel 2007+

最佳实践建议

  • 组合使用:安装字体包 + -Djava.awt.headless=true
  • 大数据量优先 SXSSFWorkbook;若环境受限或数据量中小,可用 XSSFWorkbook
  • 控制导出规模(如分页≤1万行),必要时分段导出或改 CSV。
  • 为导出任务分配足够堆内存:-Xmx1024m 或更高,视数据量调整。
  • 将环境检测与验证脚本写入部署文档,便于回归与迁移。
相关推荐
2401_837088506 分钟前
Redis的vim基本操作
linux·编辑器·vim
馨谙10 分钟前
标题:Linux 系统中的“保险库管理员”:深入浅出理解 /etc/shadow 文件
linux·运维·服务器
---学无止境---13 分钟前
Linux中zonelist分配策略初始化
linux
撬动未来的支点1 小时前
【Linux内核】Linux系统启动之旅
linux
乌萨奇也要立志学C++2 小时前
【Linux】基础IO(一)Linux 文件操作从入门到实践:系统调用、文件描述符、重定向,为自定义Shell添加重定向
linux·运维·chrome
liujing102329296 小时前
stm32大项目阶段20251015
linux
嵌入式郑工7 小时前
LINUX驱动开发: 设备和驱动是怎么匹配的?
linux·运维·服务器
会飞的小菠菜8 小时前
大量Excel工作簿中的图片怎么批量提取出来
excel·导出·图片·提取·批量·保存·另存为
nongcunqq8 小时前
abap 操作 excel
java·数据库·excel
郭式云源生法则8 小时前
归档及压缩、重定向与管道操作和综合使用,find精确查找、find处理查找结果、vim高级使用、vimdiff多文件使用
linux·运维·服务器