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 或更高,视数据量调整。
  • 将环境检测与验证脚本写入部署文档,便于回归与迁移。
相关推荐
aFakeProgramer14 小时前
Linux版本兼容问题及RTA-VRTE环境配置笔记
linux·笔记
Zhu75814 小时前
在Ubuntu24快速配置专用SFTP
linux·sftp
码农客栈14 小时前
Linux 内核顶层 Makefile 详解
linux
Embedded-Xin15 小时前
Rust学习——Cargo工具
linux·学习·架构·rust·嵌入式
weixin_4357761115 小时前
2026年长沙托育vi设计从风格定位到元素运用的设计方法
linux·运维·服务器·python
benjiangliu16 小时前
LINUX系统-19-库制作与原理(一)
linux·运维·服务器
FriendshipT17 小时前
Ubuntu 20.04 下使用 Ollama 本地部署 AI 大模型
linux·人工智能·python·深度学习·ubuntu
bellus-17 小时前
win11使用ubuntu 26.04
linux·运维·ubuntu
略略略咯咯18 小时前
centos更换镜像源
linux·运维·centos
j7~18 小时前
【Linux】二十七.线程篇四《Linux多线程编程:线程互斥(互斥量的底层到封装)、线程安全和冲入、死锁》---详解
linux·开发语言·c++·线程安全·死锁·线程互斥·重入