SpringBoot基于docx4j實現(xiàn)DOCX轉(zhuǎn)PDF的具體方案
在日常項目開發(fā)中,我們經(jīng)常遇到這樣的需求:
用戶上傳 Word( .docx)文件,希望后臺自動生成 PDF,用于下載、歸檔或在線預(yù)覽。
網(wǎng)上方案很多——有收費的 Aspose、有重量級的 LibreOffice,也有輕量的 docx4j。
本文將介紹一個完全開源、部署簡單、純 Java 的實現(xiàn)方案:使用 docx4j 在 Spring Boot 中實現(xiàn) .docx → .pdf 轉(zhuǎn)換。
一、方案選型對比
| 方案 | 是否開源 | 外部依賴 | 樣式保真度 | 部署復(fù)雜度 | 備注 |
|---|---|---|---|---|---|
| Apache POI + iText | ? | 無 | 中 | ? | 對復(fù)雜格式支持差 |
| docx4j | ? | 無 | 高 | ?? | 推薦,純 Java |
| LibreOffice + JODConverter | ? | 需安裝 LibreOffice | 很高 | ??? | 部署復(fù)雜 |
| Aspose.Words | ? | 無 | 最高 | ? | 收費,商業(yè)許可 |
選擇理由:
- docx4j 是純 Java 實現(xiàn),無需安裝 Office 或 LibreOffice;
- 開源(Apache 2.0 License),免費可商用;
- 轉(zhuǎn)換質(zhì)量好,能保留圖片、表格、頁眉頁腳;
- 容易集成進(jìn) 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 包下創(chuàng)建 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 文件轉(zhuǎn)換為 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("華文細(xì)黑", PhysicalFonts.get("STXihei"));
fontMapper.put("宋體擴(kuò)展", PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("新細(xì)明體", PhysicalFonts.get("SimSun"));
// ?? 修復(fù) “宋體(正文)/宋體(標(biāo)題)” 亂碼
PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
PhysicalFonts.put("新細(xì)明體", PhysicalFonts.get("SimSun"));
wordMLPackage.setFontMapper(fontMapper);
}
// 3. 創(chuàng)建輸出流并執(zhí)行轉(zhuǎn)換
try (FileOutputStream os = new FileOutputStream(pdfPath)) {
Docx4J.toPDF(wordMLPackage, os);
}
System.out.println("? PDF 生成成功:" + pdfPath);
} catch (Exception e) {
System.err.println("? 轉(zhuǎn)換失敗:" + e.getMessage());
}
}
}
四、Controller 示例
在 controller 包中創(chuàng)建一個上傳接口:
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、 調(diào)用轉(zhuǎn)換工具
DocxToPdfUtil.convert(filePath, pdfPath);
// 4、 設(shè)置響應(yīng)頭并輸出 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 發(fā)送請求:
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("華文細(xì)黑", PhysicalFonts.get("STXihei"));
fontMapper.put("宋體擴(kuò)展", PhysicalFonts.get("simsun-extB"));
fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));
fontMapper.put("新細(xì)明體", PhysicalFonts.get("SimSun"));
// ?? 修復(fù) “宋體(正文)/宋體(標(biāo)題)” 亂碼
PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));
PhysicalFonts.put("新細(xì)明體", PhysicalFonts.get("SimSun"));
wordMLPackage.setFontMapper(fontMapper);
六、Linux解決中文亂碼問題
在 Linux 環(huán)境中安裝 Windows 字體
新建字體文件夾
sudo mkdir -p /usr/share/fonts/win_font
拷貝 Windows 字體文件
將 Windows 10 系統(tǒng)中路徑為 C:\Windows\Fonts 的字體文件
拷貝到 Linux 的 /usr/share/fonts/win_font 目錄中。
加載字體文件
進(jìn)入字體目錄并執(zhí)行以下命令:
cd /usr/share/fonts/win_font sudo mkfontscale # 生成字體縮放文件 sudo mkfontdir # 生成字體目錄索引 sudo fc-cache -fv # 刷新字體緩存
查看字體安裝情況
執(zhí)行以下命令查看中文字體是否成功加載:
fc-list :lang=zh

七、總結(jié)
- 使用開源庫 docx4j;
- 無需安裝 Office 或 LibreOffice;
- 保留常見樣式、圖片、表格;
- 性能高、部署輕量。
以上就是SpringBoot基于docx4j實現(xiàn)DOCX轉(zhuǎn)PDF的具體方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot DOCX轉(zhuǎn)PDF的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring Boot 中嵌入式 Servlet 容器自動配置原理解析
這篇文章主要介紹了Spring Boot 中嵌入式 Servlet 容器自動配置原理解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11
SpringBoot使用RedisTemplate.delete刪除指定key失敗的解決辦法
本文主要介紹了SpringBoot使用RedisTemplate.delete刪除指定key失敗的解決辦法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-03-03
Springboot報錯java.lang.NullPointerException: null問題
這篇文章主要介紹了Springboot報錯java.lang.NullPointerException: null問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
一文詳解如何配置MyBatis實現(xiàn)打印可執(zhí)行的SQL語句
在MyBatis中,動態(tài)SQL是一個強(qiáng)大的特性,允許我們在XML映射文件或注解中編寫條件語句,根據(jù)運行時的參數(shù)來決定SQL的具體執(zhí)行內(nèi)容,這篇文章主要給大家介紹了關(guān)于如何配置MyBatis實現(xiàn)打印可執(zhí)行的SQL語句的相關(guān)資料,需要的朋友可以參考下2024-08-08

