目錄

  • 一、方案選型對比
  • 二、添加 Maven 依賴
  • 三、核心工具類:DocxToPdfUtil
  • 四、Controller 示例
  • 五、Windows解決中文亂碼問題
  • 六、Linux解決中文亂碼問題
  • 七、總結


在日常項目開發中,我們經常遇到這樣的需求:


用户上傳 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解決中文亂碼問題

【SpringBoot高級篇】springboot實現上傳doc&docx文件格式轉pdf在線預覽_springboot上傳word ,pdf文件獲取顯示_Word


增加字體的類別

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

【SpringBoot高級篇】springboot實現上傳doc&docx文件格式轉pdf在線預覽_springboot上傳word ,pdf文件獲取顯示_Word_02

七、總結

  • 使用開源庫 docx4j
  • 無需安裝 Office 或 LibreOffice;
  • 保留常見樣式、圖片、表格;
  • 性能高、部署輕量。