SpringBoot基于docx4j实现DOCX转PDF的具体方案

 更新时间:2025年11月09日 13:45:59   作者:Knight_AL  
在日常项目开发中,我们经常遇到用户上传 Word( .docx)文件,希望后台自动生成 PDF,用于下载、归档或在线预览,本文将介绍一个完全开源、部署简单、纯 Java 的实现方案,感兴趣的小伙伴可以跟着小编一起来看看

在日常项目开发中,我们经常遇到这样的需求:
用户上传 Word( .docx)文件,希望后台自动生成 PDF,用于下载、归档或在线预览。
网上方案很多——有收费的 Aspose、有重量级的 LibreOffice,也有轻量的 docx4j。

本文将介绍一个完全开源、部署简单、纯 Java 的实现方案:使用 docx4j 在 Spring Boot 中实现 .docx → .pdf 转换。

一、方案选型对比

方案是否开源外部依赖样式保真度部署复杂度备注
Apache POI + iText对复杂格式支持差
docx4j⭐⭐推荐,纯 Java
LibreOffice + JODConverter需安装 LibreOffice很高⭐⭐⭐部署复杂
Aspose.Words最高收费,商业许可

选择理由

  • docx4j 是纯 Java 实现,无需安装 Office 或 LibreOffice;
  • 开源(Apache 2.0 License),免费可商用;
  • 转换质量好,能保留图片、表格、页眉页脚;
  • 容易集成进 Spring Boot。

二、添加 Maven 依赖

在 pom.xml 中加入以下依赖:

<dependencies>
        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-core</artifactId>
            <version>11.4.8</version>
        </dependency>

        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-JAXB-ReferenceImpl</artifactId>
            <version>11.4.8</version>
        </dependency>

        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-export-fo</artifactId>
            <version>11.4.8</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.9</version>
        </dependency>

</dependencies>

三、核心工具类:DocxToPdfUtil

在 utils 包下创建 DocxToPdfUtil.java

package com.donglin.utils;

import org.docx4j.Docx4J;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;

import java.io.File;
import java.io.FileOutputStream;

public class DocxToPdfUtil {

    /**
     * 将 docx 文件转换为 PDF
     *
     * @param docxPath 输入文件路径
     * @param pdfPath  输出文件路径
     */
    public static void convert(String docxPath, String pdfPath) {
        try {
            // 1. 加载 Word 文档
            WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File(docxPath));

            // 2. 配置字体映射(防止中文乱码)
            Mapper fontMapper = new IdentityPlusMapper();
            PhysicalFonts.discoverPhysicalFonts();

            PhysicalFont simsun = PhysicalFonts.get("SimSun");
            if (simsun != null) {
                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", PhysicalFonts.get("SimSun"));
                PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
                wordMLPackage.setFontMapper(fontMapper);
            }

            // 3. 创建输出流并执行转换
            try (FileOutputStream os = new FileOutputStream(pdfPath)) {
                Docx4J.toPDF(wordMLPackage, os);
            }

            System.out.println("✅ PDF 生成成功:" + pdfPath);
        } catch (Exception e) {
            System.err.println("❌ 转换失败:" + e.getMessage());
        }
    }
}

四、Controller 示例

在 controller 包中创建一个上传接口:

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;

@RestController
@RequestMapping("/convert")
public class FileController {

    @GetMapping("/convertToPdf")
    public void convertToPdf(@RequestParam String filePath, HttpServletResponse response) throws Exception {
        // 1、 检查文件是否存在
        File inputFile = new File(filePath);
        if (!inputFile.exists()) {
            throw new RuntimeException("文件不存在: " + filePath);
        }

        // 2、 定义输出路径(临时文件)
        String pdfPath = filePath.replace(".docx", ".pdf");

        // 3、 调用转换工具
        DocxToPdfUtil.convert(filePath, pdfPath);

        // 4、 设置响应头并输出 PDF 文件
        response.setContentType("application/pdf");
        response.setHeader("Content-Disposition", "attachment; filename=" + new File(pdfPath).getName());
        try (FileInputStream fis = new FileInputStream(pdfPath);
             OutputStream os = response.getOutputStream()) {
            fis.transferTo(os);
            os.flush();
        }

        // 可选:删除临时 PDF 文件
        new File(pdfPath).delete();
    }
}

使用 Postman 发送请求:

GET http://localhost:8080/convertToPdf?filePath=filePath=E:/ai/report.docx

选择一个 .docx 文件上传,即可生成同名 .pdf 文件。

五、Windows解决中文乱码问题

增加字体的类别

                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", PhysicalFonts.get("SimSun"));
                PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));
                wordMLPackage.setFontMapper(fontMapper);

六、Linux解决中文乱码问题

在 Linux 环境中安装 Windows 字体

新建字体文件夹

sudo mkdir -p /usr/share/fonts/win_font

拷贝 Windows 字体文件

将 Windows 10 系统中路径为 C:\Windows\Fonts 的字体文件
拷贝到 Linux 的 /usr/share/fonts/win_font 目录中。

加载字体文件

进入字体目录并执行以下命令:

cd /usr/share/fonts/win_font
sudo mkfontscale       # 生成字体缩放文件
sudo mkfontdir         # 生成字体目录索引
sudo fc-cache -fv      # 刷新字体缓存

查看字体安装情况

执行以下命令查看中文字体是否成功加载:

fc-list :lang=zh

七、总结

  • 使用开源库 docx4j
  • 无需安装 Office 或 LibreOffice;
  • 保留常见样式、图片、表格;
  • 性能高、部署轻量。

以上就是SpringBoot基于docx4j实现DOCX转PDF的具体方案的详细内容,更多关于SpringBoot DOCX转PDF的资料请关注脚本之家其它相关文章!

相关文章

  • 关于SpringBoot单元测试(cobertura生成覆盖率报告)

    关于SpringBoot单元测试(cobertura生成覆盖率报告)

    这篇文章主要介绍了关于SpringBoot单元测试(cobertura生成覆盖率报告),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Springboot接收文件与发送文件实例教程

    Springboot接收文件与发送文件实例教程

    最近工作中遇到个需求,springboot简单的上传文档或者图片,并且进行操作,操作完后进行保存指定路径,下面这篇文章主要给大家介绍了关于Springboot接收文件与发送文件的相关资料,需要的朋友可以参考下
    2023-05-05
  • 深入解析SpringBatch适配器

    深入解析SpringBatch适配器

    Spring Batch是Spring的一个子项目,使用Java语言并基于Spring框架为基础开发,使得已经使用 Spring 框架的开发者或者企业更容易访问和利用企业服务,本文给大家介绍SpringBatch适配器的相关知识,感兴趣的朋友一起看看吧
    2021-11-11
  • JVM与操作系统之间的关系详解

    JVM与操作系统之间的关系详解

    JVM与操作系统之间是依赖与被依赖的关系,JVM依赖于操作系统提供的资源和服务,同时JVM也起到了抽象与隔离的作用,为Java程序提供了一个统一的、与平台无关的运行环境,提高了Java程序的安全性
    2025-03-03
  • 跟我学Java Swing之游戏设计(1)

    跟我学Java Swing之游戏设计(1)

    跟我学Java Swing之游戏设计(1)...
    2006-12-12
  • springboot网站应用使用第三方qq登录的实现过程

    springboot网站应用使用第三方qq登录的实现过程

    这篇文章主要介绍了springboot网站应用使用第三方qq登录,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09
  • Java异常链表throw结构assert详细解读

    Java异常链表throw结构assert详细解读

    这篇文章主要给大家介绍了关于Java中方法使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-08-08
  • Java中键盘输入的几种常见方式小结

    Java中键盘输入的几种常见方式小结

    本文主要介绍了Java中键盘输入的几种常见方式小结,主要是三种方式IO流、Scanner类、BufferedReader写入,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • SpringBoot结合HTMX实现高效Web开发实战

    SpringBoot结合HTMX实现高效Web开发实战

    在当今的 Web 开发领域,前后端分离已成为主流趋势,本文将介绍一种轻量级的解决方案,结合 Spring Boot 与 HTMX,实现高效简洁的前后端分离开发,感兴趣的可以了解下
    2025-07-07
  • Java中的线程池如何实现线程复用

    Java中的线程池如何实现线程复用

    这篇文章主要介绍了Java中的线程池如何实现线程复用问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03

最新评论