Java Word转PDF性能实测:纯代码vs原生引擎

发布时间:2026/10/2 2:24:51
Java Word转PDF性能实测:纯代码vs原生引擎 Java实现Word转PDF的两种常见方案和性能实测更新时间是2026年01月13日, 具体时刻为09:03:36, 作者是。这篇文章对比了Java后端开发中Word转PDF的两种常见方案, 也就是纯Java实现和调用原生引擎这两种方式, 下面小编会和大家详细地介绍具体的实现方法都有哪些内容。这篇文章拿Java后端开发里面把Word变成PDF的俩种办法做了个对比, 一个是用纯Java的方式去搞, 一个是去调那个原生引擎。咱们通过能直接跑起来的Java代码去测了一通, 看了看单次转变要花多少时间, 还有热启动或者是冷启动要花多少时间, 再有个稳定性这些个指标都考虑到了。那个测试用的环境是JDK17这个版本, 配的是8核的那个CPU, 内存是16GB这么大, 拿的是一个有20页的那种文档来试的, 这文档里头有中文的, 还有图啊表什么的都在里面。该项目把完整的Maven依赖配置摆出来, 还把两种转换方案的实现代码也给提供出来了。在技术路线上面, 它采用的是XSL-FO加上FOP这种组合方式。而且呢, 它还特别仔细、特别详细地把中文字体映射问题给处理好了。接下来的测试结果, 会把这个事儿说清楚, 也就是会揭示这两种方案在真实应用场景下面究竟是个什么情况。许多讨论仅仅停留在人们口头相传觉得速度更快的层面, 但与此同时并没有提供可供查验的代码, 也没有展示确凿的数据, 更不存在能够被重复进行的实验结果。使用那些能够在计算机上面顺利执行下去的Java程序代码片段, 来对两者之间存在的实际性能方面的差异情况进行核实与确认。一、测试目标与原则测试目标测试原则二、针对测试环境之三的情况, 需要对项目的整体结构进行了解。pdf-bench/├─ pom.xml├─ /这个部分下面紧跟着的是文件名, 也就是.docx。这个目录的路径是从源码开始, 一直到主要的Java代码位置。├─ .java├─ .java├─ .java└─ 该文件名称为 Stats, 并且其后缀为 .java。四、对于Maven这种构建工具的依赖关系管理, 我们通常需要去修改那个叫做pom.xml的文件。-- docx4j --org.docx4jdocx4j-core11.4.8org.docx4jdocx4j-JAXB-ReferenceImpl11.4.8org.docx4jdocx4j-export-fo11.4.8-- Apache FOP --org.apache.xmlgraphicsfop2.9-- docx4j --org.docx4jdocx4j-core11.4.8org.docx4jdocx4j-JAXB-ReferenceImpl11.4.8org.docx4jdocx4j-export-fo11.4.8-- Apache FOP --org.apache.xmlgraphicsfop2.9五、 实现将内容转换成PDF格式的目标。public class LibreOfficeConverter {private final String soffice;public LibreOfficeConverter(String soffice) {this.soffice soffice;}public void convert(Path docx, Path outDir) throws Exception {ProcessBuilder pb new ProcessBuilder(soffice,--headless,--nologo,--nolockcheck,--nodefault,--nofirststartwizard,--convert-to, pdf,--outdir, outDir.toString(),docx.toString());pb.redirectErrorStream(true);Process p pb.start();int code p.waitFor();if (code ! 0) {throw new RuntimeException(LibreOffice failed, exit code);}}}记得把 改成C:\ Files\\\.exe六、 转 PDF 实现public class Docx4jConverter {public void convert(Path docx, Path pdf) throws Exception {// 1️⃣ 加载 WordWordprocessingMLPackage wordMLPackage WordprocessingMLPackage.load(docx.toFile());// 2️⃣ 字体映射核心IdentityPlusMapper fontMapper new IdentityPlusMapper();// 宋体核心兜底PhysicalFont simsun PhysicalFonts.get(SimSun);if (simsun null) {throw new RuntimeException(未找到 SimSun 字体请确认系统已安装宋体);}fontMapper.put(SimSun, simsun);// 常用中文字体映射 fontMapper.put(隶书, PhysicalFonts.get(LiSu));fontMapper.put(宋体, PhysicalFonts.get(SimSun));fontMapper.put(微软雅黑, PhysicalFonts.get(Microsoft YaHei));fontMapper.put(黑体, PhysicalFonts.get(SimHei));fontMapper.put(楷体, PhysicalFonts.get(KaiTi));fontMapper.put(新宋体, PhysicalFonts.get(NSimSun));fontMapper.put(华文行楷, PhysicalFonts.get(STXingkai));fontMapper.put(华文仿宋, PhysicalFonts.get(STFangsong));fontMapper.put(仿宋, PhysicalFonts.get(FangSong));fontMapper.put(幼圆, PhysicalFonts.get(YouYuan));fontMapper.put(华文宋体, PhysicalFonts.get(STSong));fontMapper.put(华文中宋, PhysicalFonts.get(STZhongsong));fontMapper.put(等线, PhysicalFonts.get(SimSun));fontMapper.put(等线 Light, PhysicalFonts.get(SimSun));fontMapper.put(华文琥珀, PhysicalFonts.get(STHupo));fontMapper.put(华文隶书, PhysicalFonts.get(STLiti));fontMapper.put(华文新魏, PhysicalFonts.get(STXinwei));fontMapper.put(华文彩云, PhysicalFonts.get(STCaiyun));fontMapper.put(方正姚体, PhysicalFonts.get(FZYaoti));fontMapper.put(方正舒体, PhysicalFonts.get(FZShuTi));fontMapper.put(华文细黑, PhysicalFonts.get(STXihei));fontMapper.put(宋体扩展, PhysicalFonts.get(simsun-extB));fontMapper.put(仿宋_GB2312, PhysicalFonts.get(FangSong_GB2312));fontMapper.put(新細明體, PhysicalFonts.get(SimSun));// 修复 “宋体正文/ 宋体标题/ 台岛字体” 乱码 PhysicalFonts.put(PMingLiU, simsun);PhysicalFonts.put(新細明體, simsun);// 3️⃣ 设置到 Word 包wordMLPackage.setFontMapper(fontMapper);// 4️⃣ 转 PDFtry (OutputStream os Files.newOutputStream(pdf)) {Docx4J.toPDF(wordMLPackage, os);}}}采用的是XSL-FO配合FOP这样的技术路线。七、性能统计工具P50 / P95public class Stats {private final List times new ArrayList();public void add(long nanos) {times.add(nanos);}public void print(String name) {Collections.sort(times);double avg times.stream().mapToLong(x - x).average().orElse(0) / 1e6;double p50 times.get(times.size() / 2) / 1e6;double p95 times.get((int)(times.size() * 0.95)) / 1e6;System.out.printf(%s - avg%.2fms, p50%.2fms, p95%.2fms%n,name, avg, p50, p95);}}八、压测主程序public class BenchMain {public static void main(String[] args) throws Exception {Path docx Path.of(samples/sample.docx);Path out Path.of(out);Files.createDirectories(out);LibreOfficeConverter lo new LibreOfficeConverter(soffice);Docx4jConverter d4j new Docx4jConverter();int rounds 5;// LibreOfficeStats loStats new Stats();for (int i 0; i rounds; i) {long t0 System.nanoTime();lo.convert(docx, out);loStats.add(System.nanoTime() - t0);}// docx4jStats d4jStats new Stats();for (int i 0; i rounds; i) {long t0 System.nanoTime();d4j.convert(docx, out.resolve(d4j_ i .pdf));d4jStats.add(System.nanoTime() - t0);}loStats.print(LibreOffice);d4jStats.print(docx4j);}}九、实测结果** 稳定快 **十、导致这种状况的原因究竟会是什么呢?执行路径docx(xml)→ JAXB它是指向 Java对象的。它会被转换成XSL-FO格式。→ FOP 排版→ PDF执行路径docx→ 原生排版引擎→ PDF十一、结论如果你是 Java 后端做真实业务文档转换只适合导出来可能有问题正常