Spring Boot 实现 DOCX 转 PDF(基于 docx4j)
本文介绍如何在 Spring Boot 项目中集成 docx4j 库实现 DOCX 到 PDF 的转换。内容涵盖环境搭建、依赖配置、核心转换代码实现、中文字体乱码处理、RESTful API 接口集成以及测试验证。重点解决了服务器端字体映射问题及内存管理优化,提供了一套轻量级、开源且不依赖外部 Office 软件的解决方案。

本文介绍如何在 Spring Boot 项目中集成 docx4j 库实现 DOCX 到 PDF 的转换。内容涵盖环境搭建、依赖配置、核心转换代码实现、中文字体乱码处理、RESTful API 接口集成以及测试验证。重点解决了服务器端字体映射问题及内存管理优化,提供了一套轻量级、开源且不依赖外部 Office 软件的解决方案。

将 DOCX 文档转换为 PDF 的需求非常普遍,常见场景包括:
有多种技术可以实现 DOCX 转 PDF,例如:
docx4j-export-FO 和 docx4j-export-PDF 模块,利用 Apache FOP (Formatting Objects Processor) 或其他渲染器将 DOCX 内容转换为 PDF。本指南使用其内置的 Plutext PDF 转换器(基于 docx4j-export-PDF)。因此,docx4j 提供了一个在 Spring Boot 应用中实现轻量级、开源、可移植的 DOCX 转 PDF 功能的优秀方案。
可以使用以下方式之一创建项目:
Spring Web 依赖,生成项目并下载。curl 或直接下载。项目创建后,确保基本的 Spring Boot 应用结构正常 (src/main/java, src/main/resources, pom.xml)。
在项目的 pom.xml 文件中,添加以下依赖:
<dependencies>
<!-- Spring Boot Starter Web (提供 RESTful 支持) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- docx4j 核心库 -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>11.4.4</version>
</dependency>
<!-- docx4j 导出 PDF 模块 (使用 Plutext PDF 转换器) -->
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-export-PDF</artifactId>
<version>11.4.4</version>
</dependency>
<!-- Apache FOP (可选,但 docx4j-export-PDF 内部可能使用或需要其部分功能) -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>fop</artifactId>
<version>2.7</version>
</dependency>
<!-- FOP 需要 XML Graphics Commons -->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>xmlgraphics-commons</artifactId>
<version>2.7</version>
</dependency>
<!-- 日志依赖 (SLF4J + Logback, 通常由 Spring Boot starter 提供) -->
</dependencies>
注意:
fop 和 xmlgraphics-commons 是为了避免 docx4j-export-PDF 在转换时可能因缺少某些类而报错(如 org.apache.xmlgraphics.util.MimeConstants)。虽然 Plutext 转换器可能不完全依赖它们,但添加它们是常见做法。spring-boot-starter-web 通常已经包含了 spring-boot-starter-logging,它提供了 SLF4J 接口和 Logback 实现。确保日志配置正确,以便记录转换过程中的信息或错误。运行 mvn clean install (或使用 IDE 的 Maven 工具) 下载依赖。
DOCX 转 PDF 的核心逻辑封装在一个 Service 类中。
WordprocessingMLPackage) 中。WordprocessingMLPackage 转换为 PDF 字节流或文件。WordprocessingMLPackage)docx4j 使用 WordprocessingMLPackage 对象来表示一个 DOCX 文档。可以从多种来源加载:
File 对象:从本地文件系统加载。InputStream:从输入流加载 (例如上传的文件流)。URL:从网络资源加载。import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
public WordprocessingMLPackage loadDocx(File docxFile) throws Docx4JException {
return WordprocessingMLPackage.load(docxFile);
}
public WordprocessingMLPackage loadDocx(InputStream inputStream) throws Docx4JException {
return WordprocessingMLPackage.load(inputStream);
}
PDFSettings)PDFSettings 对象允许你定制 PDF 输出。常用设置包括:
setFoProcessorName(String):设置使用的 FO 处理器。对于 docx4j-export-PDF,通常使用 "Plutext" (这是默认值)。setObfuscateFonts(boolean):是否混淆字体 (可能用于规避某些字体许可问题,慎用)。setFontMapping(MappedFonts):字体映射 (解决缺失字体问题,见 4.1 节)。setAccessibility(boolean):(实验性) 是否添加 PDF 可访问性标签。setRunOnly(boolean):(高级) 仅运行转换,不进行其他处理。import org.docx4j.convert.out.pdf.PdfConversion;
import org.docx4j.convert.out.pdf.PdfSettings;
public PdfSettings createPdfSettings() {
PdfSettings pdfSettings = new PdfSettings();
// 使用 Plutext 转换器 (通常是默认)
pdfSettings.setFoProcessorName("Plutext");
// 是否混淆字体 (一般保持 false)
pdfSettings.setObfuscateFonts(false);
// 其他设置...
return pdfSettings;
}
Docx4J.toPDF)docx4j 提供了便捷的方法 Docx4J.toPDF 来执行转换。它需要 WordprocessingMLPackage 和 PdfSettings,并输出到指定的 OutputStream。
import org.docx4j.Docx4J;
import org.docx4j.openpackaging.exceptions.Docx4JException;
public void convertToPdf(WordprocessingMLPackage wordMLPackage, PdfSettings pdfSettings, OutputStream outputStream) throws Docx4JException {
Docx4J.toPDF(wordMLPackage, outputStream, pdfSettings);
}
创建一个 Spring Service (DocxToPdfService) 来封装转换逻辑:
package com.example.docx2pdf.service;
import org.docx4j.Docx4J;
import org.docx4j.convert.out.pdf.PdfConversion;
import org.docx4j.convert.out.pdf.PdfSettings;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@Service
public class DocxToPdfService {
/**
* 将输入的 DOCX 文件流转换为 PDF,并写入输出流
*
* @param docxInputStream DOCX 文件输入流
* @param pdfOutputStream PDF 输出流
* @throws Docx4JException DOCX 处理或转换错误
* @throws IOException 流操作错误
*/
public void convertDocxToPdf(InputStream docxInputStream, OutputStream pdfOutputStream) throws Docx4JException, IOException {
// 1. 加载 DOCX 文档
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(docxInputStream);
// 2. 创建 PDF 设置 (使用默认或自定义设置)
PdfSettings pdfSettings = createPdfSettings();
// 3. 执行转换
Docx4J.toPDF(wordMLPackage, pdfOutputStream, pdfSettings);
// 4. 重要:确保刷新输出流 (通常在调用方处理关闭)
pdfOutputStream.flush();
}
/**
* (可选) 创建并配置 PDF 设置
*
* @return PdfSettings 对象
*/
private PdfSettings createPdfSettings() {
PdfSettings pdfSettings = new PdfSettings();
// 使用 Plutext 转换器 (通常是默认,显式设置也可)
pdfSettings.setFoProcessorName("Plutext");
// 设置其他选项,例如字体映射等 (见高级配置)
return pdfSettings;
}
/**
* 便捷方法:将 DOCX 文件转换为 PDF 文件
*
* @param inputDocxFile 输入 DOCX 文件
* @param outputPdfFile 输出 PDF 文件
* @throws Docx4JException
* @throws IOException
*/
public void convertDocxFileToPdfFile(File inputDocxFile, File outputPdfFile) throws Docx4JException, IOException {
try (FileOutputStream fos = new FileOutputStream(outputPdfFile)) {
convertDocxToPdf(new java.io.FileInputStream(inputDocxFile), fos);
}
}
}
关键点说明:
convertDocxToPdf 方法接受 InputStream 和 OutputStream,使其非常灵活,可以处理来自网络上传、文件系统或内存的数据流,并输出到文件、HTTP 响应或内存。try-with-resources 语句 (在 convertDocxFileToPdfFile 中) 确保 FileOutputStream 被正确关闭。在 convertDocxToPdf 方法中,流的关闭责任交给了调用者(例如,Controller 处理 HTTP 响应流)。flush() 确保所有缓冲的数据都写入输出流。createPdfSettings() 方法提供了配置扩展点。目前使用默认 Plutext 设置。问题描述: 如果 DOCX 文档中使用了服务器上未安装的字体(尤其是中文字体如宋体、黑体),转换后的 PDF 可能会出现字体替换(如显示为 Times New Roman)或方块乱码。
解决方案:
FontMapper 进行映射:docx4j 提供了 FontMapper 接口,允许你将 DOCX 中使用的字体名称映射到 PDF 中应该使用的字体名称或物理字体文件路径。这对于中文字体尤为重要!import org.docx4j.fonts.MappedFonts;
import org.docx4j.fonts.PhysicalFont;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.fonts.FontMapper;
private PdfSettings createPdfSettings() {
PdfSettings pdfSettings = new PdfSettings();
pdfSettings.setFoProcessorName("Plutext");
// 创建字体映射器
FontMapper fontMapper = new BestMatchingMapper(); // 或者 PhysicalFontMapper
// 关键:注册中文字体映射
// 假设服务器安装了 SimSun (宋体) 和 SimHei (黑体)
// 将 DOCX 中的 "宋体" 映射到物理字体 "SimSun"
fontMapper.put("宋体", PhysicalFonts.get("SimSun"));
fontMapper.put("SimSun", PhysicalFonts.get("SimSun"));
// 有时字体名是英文的
fontMapper.put("黑体", PhysicalFonts.get("SimHei"));
fontMapper.put("SimHei", PhysicalFonts.get("SimHei"));
// 如果需要,映射其他常用字体
fontMapper.put("Calibri", PhysicalFonts.get("Calibri")); // 假设服务器有
fontMapper.put("Arial", PhysicalFonts.get("Arial"));
// 将 FontMapper 设置到 PdfSettings 的 MappedFonts 中
MappedFonts mappedFonts = new MappedFonts();
mappedFonts.setMapper(fontMapper);
pdfSettings.setFontMapping(mappedFonts);
return pdfSettings;
}
说明:
PhysicalFonts.get(String fontName) 尝试查找系统中安装的、与给定名称匹配的物理字体。BestMatchingMapper 或 PhysicalFontMapper 是 FontMapper 的实现类,用于处理映射逻辑。src/main/resources/fonts),并使用 PhysicalFonts.addPhysicalFont(String path) 注册,然后在 FontMapper 中映射到这个注册的字体名。注意字体文件许可问题!// 示例:加载资源目录下的字体文件 (打包在 JAR 内)
PhysicalFonts.addPhysicalFont("/fonts/simsun.ttf"); // 注意路径,可能需要使用 ClassLoader
PhysicalFonts.addPhysicalFont("/fonts/simhei.ttf");
// 然后在 FontMapper 中映射
fontMapper.put("宋体", PhysicalFonts.get("simsun")); // 注意这里用的是注册时的名字,可能不是"SimSun"
PdfSettings 允许通过 org.docx4j.convert.out.pdf.PdfConversion 设置一些 PDF 属性。一种常见方式是创建 PdfConversion 实例进行配置:
private PdfSettings createPdfSettings() {
PdfSettings pdfSettings = new PdfSettings();
pdfSettings.setFoProcessorName("Plutext");
// 创建 PdfConversion 实例进行更详细的设置
PdfConversion pdfConversion = pdfSettings.getPdfConversion();
// 设置 PDF 标题、作者等元数据 (可选)
pdfConversion.setTitle("Converted Document");
pdfConversion.setAuthor("My Application");
// 设置 PDF 权限 (可选,需要了解 iText 的 PdfWriter 常量)
// 注意:docx4j 内部使用 iText 5.x (AGPL 许可) 或 Flying Saucer 等,权限设置可能受限或复杂。
// pdfConversion.setPdfPermissions(...); // 通常需要直接操作底层 iText PdfWriter
// 其他高级设置...
// pdfConversion.setPdfVersion(...);
// pdfConversion.setTagged(...); // 可访问性
return pdfSettings;
}
注意: 深入设置 PDF 权限 (PdfWriter 的 ALLOW_XXX 常量) 通常需要直接访问底层的 PDF 生成库 (如 iText)。docx4j 的抽象层可能无法方便地设置所有权限。如果对权限有严格要求,可能需要考虑其他更底层的 PDF 生成库,或者生成 PDF 后再使用其他库 (如 Apache PDFBox) 进行权限修改。使用 iText 5.x 需要注意其 AGPL 许可证对分发的要求。
转换过程可能遇到多种错误:
Docx4JException: DOCX 加载、解析或转换过程中的错误(例如文件损坏、格式不支持)。IOException: 流读写错误。OutOfMemoryError):处理大型复杂文档时。异常处理策略:
Docx4JException 和 IOException 抛给调用者 (Controller)。Logger) 详细记录错误信息、堆栈跟踪和可能相关的文档信息(注意隐私和安全),便于排查。import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service
public class DocxToPdfService {
private static final Logger logger = LoggerFactory.getLogger(DocxToPdfService.class);
public void convertDocxToPdf(InputStream docxInputStream, OutputStream pdfOutputStream) throws Docx4JException, IOException {
try {
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(docxInputStream);
PdfSettings pdfSettings = createPdfSettings();
Docx4J.toPDF(wordMLPackage, pdfOutputStream, pdfSettings);
pdfOutputStream.flush();
} catch (Docx4JException e) {
logger.error("DOCX 处理或转换失败", e);
throw e; // 重新抛出,由调用方处理
} catch (IOException e) {
logger.error("IO 操作失败", e);
throw e;
}
}
}
在 Controller 中处理:
@RestController
@RequestMapping("/api/convert")
public class ConversionController {
@Autowired
private DocxToPdfService docxToPdfService;
@PostMapping("/docx-to-pdf")
public ResponseEntity<Resource> convertDocxToPdf(@RequestParam("file") MultipartFile file) {
try {
// ... 创建临时文件或直接使用流 ...
ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream();
docxToPdfService.convertDocxToPdf(file.getInputStream(), pdfOutputStream);
ByteArrayResource resource = new ByteArrayResource(pdfOutputStream.toByteArray());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=converted.pdf")
.contentType(MediaType.APPLICATION_PDF)
.body(resource);
} catch (Docx4JException | IOException e) {
// 记录日志 (Controller 也可以有自己的 Logger)
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("转换失败:" + e.getMessage()); // 注意:简单返回字符串,生产环境应更友好
}
}
}
WordprocessingMLPackage 对象。处理大型或包含高分辨率图片的 DOCX 文件时,可能导致显著的堆内存消耗,甚至 OutOfMemoryError。优化建议:
-Xmx 参数设置更大的最大堆空间 (如 -Xmx1024m 或 -Xmx2048m)。WordprocessingMLPackage 中的 BinaryPart。@Async 或消息队列 (如 RabbitMQ, Kafka) 进行异步处理,避免阻塞 HTTP 请求线程。将转换任务提交到线程池,完成后通过通知 (如 WebSocket, 邮件,回调 URL) 或提供下载链接。InputStream, OutputStream。WordprocessingMLPackage 对象在转换完成后应解除引用,以便 GC 回收。创建一个 Controller 来提供 DOCX 转 PDF 的 HTTP 接口。通常使用 POST 请求接收上传的 DOCX 文件。
package com.example.docx2pdf.controller;
import com.example.docx2pdf.service.DocxToPdfService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@RestController
@RequestMapping("/api/convert")
public class ConversionController {
private final DocxToPdfService docxToPdfService;
@Autowired
public ConversionController(DocxToPdfService docxToPdfService) {
this.docxToPdfService = docxToPdfService;
}
@PostMapping("/docx-to-pdf")
public ResponseEntity<Resource> convertDocxToPdf(@RequestParam("file") MultipartFile file) {
// 1. 检查文件是否为空
if (file.isEmpty()) {
return ResponseEntity.badRequest().body("请上传一个 DOCX 文件");
}
// 2. 检查文件类型 (可选,非绝对可靠)
String contentType = file.getContentType();
if (contentType == null || !contentType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
return ResponseEntity.badRequest().body("仅支持 DOCX 格式 (.docx)");
}
// 3. 执行转换
try (ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream()) {
docxToPdfService.convertDocxToPdf(file.getInputStream(), pdfOutputStream);
// 4. 准备 PDF 响应
byte[] pdfBytes = pdfOutputStream.toByteArray();
ByteArrayResource resource = new ByteArrayResource(pdfBytes);
// 5. 构建响应:PDF 文件下载
String filename = file.getOriginalFilename();
if (filename != null) {
filename = filename.replaceFirst("\\.docx$", "") + ".pdf"; // 替换扩展名
} else {
filename = "converted.pdf";
}
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename)
.contentType(MediaType.APPLICATION_PDF)
.contentLength(pdfBytes.length)
.body(resource);
} catch (IOException | Docx4JException e) {
// 6. 处理错误
return ResponseEntity.internalServerError()
.body("转换失败:" + e.getMessage()); // 生产环境应返回更友好的错误对象
}
}
}
@RequestParam("file") MultipartFile file 接收上传的文件。Spring Boot 自动处理 multipart/form-data 请求。ByteArrayOutputStream。ByteArrayOutputStream 的内容转换为 ByteArrayResource。Content-Disposition: attachment; filename=...:提示浏览器下载文件,并指定文件名。Content-Type: application/pdf:声明响应体是 PDF 格式。Content-Length:设置文件大小。ByteArrayResource 作为响应体返回。使用临时文件 (替代方案):
对于非常大的文件,将整个 PDF 先写入内存 (ByteArrayOutputStream) 可能不高效或导致 OOM。可以考虑:
File.createTempFile())。docxToPdfService.convertDocxFileToPdfFile(inputTempFile, outputTempFile) 进行转换。FileSystemResource 或 InputStreamResource 包装输出 PDF 临时文件。finally 块中删除临时文件。try {
File inputTempFile = File.createTempFile("upload-", ".docx");
file.transferTo(inputTempFile); // 保存上传文件到临时位置
File outputTempFile = File.createTempFile("converted-", ".pdf");
docxToPdfService.convertDocxFileToPdfFile(inputTempFile, outputTempFile);
Path pdfPath = outputTempFile.toPath();
InputStreamResource resource = new InputStreamResource(new FileInputStream(outputTempFile));
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=converted.pdf")
.contentType(MediaType.APPLICATION_PDF)
.contentLength(Files.size(pdfPath))
.body(resource);
} finally {
// 尝试删除临时文件
if (inputTempFile != null) inputTempFile.delete();
if (outputTempFile != null) outputTempFile.delete();
}
使用 Postman:
POST 请求,URL 为 http://localhost:8080/api/convert/docx-to-pdf (端口可能不同)。Body 选项卡中选择 form-data。file (与 @RequestParam("file") 匹配) 的类型为 File 的参数。.docx 文件。Send。200 OK 响应,内容类型为 application/pdf,浏览器或 PDF 阅读器会自动下载或打开转换后的 PDF 文件。使用 curl:
curl -X POST -F "file=@/path/to/your/document.docx" http://localhost:8080/api/convert/docx-to-pdf --output converted.pdf
为 DocxToPdfService 编写单元测试,验证其核心转换功能。需要使用测试用的 DOCX 文件。
package com.example.docx2pdf.service;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StreamUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
public class DocxToPdfServiceTest {
@Autowired
private DocxToPdfService docxToPdfService;
@Test
public void testConvertSampleDocxToPdf() throws IOException, Docx4JException {
// 1. 从测试资源目录加载一个小的 DOCX 样本文件
ClassPathResource sampleDocxResource = new ClassPathResource("testfiles/sample.docx");
byte[] docxBytes = StreamUtils.copyToByteArray(sampleDocxResource.getInputStream());
// 2. 准备输入流和输出流
ByteArrayInputStream docxInputStream = new ByteArrayInputStream(docxBytes);
ByteArrayOutputStream pdfOutputStream = new ByteArrayOutputStream();
// 3. 执行转换
docxToPdfService.convertDocxToPdf(docxInputStream, pdfOutputStream);
// 4. 验证输出
byte[] pdfBytes = pdfOutputStream.toByteArray();
assertNotNull(pdfBytes);
assertTrue(pdfBytes.length > 0);
// 5. (可选) 简单验证 PDF 头
// PDF 文件通常以 "%PDF-" 开头
String pdfHeader = new String(pdfBytes, 0, 5);
assertEquals("%PDF-", pdfHeader);
// 6. (可选) 将 PDF 写入临时文件检查
File tempPdfFile = File.createTempFile("test-output", ".pdf");
Files.write(tempPdfFile.toPath(), pdfBytes);
System.out.println("Test PDF output: " + tempPdfFile.getAbsolutePath());
// 手动检查 tempPdfFile 是否正确
// tempPdfFile.deleteOnExit(); // 让 JVM 退出时删除
}
}
说明:
@SpringBootTest 加载 Spring 上下文并注入 DocxToPdfService。ClassPathResource 加载位于 src/test/resources/testfiles/sample.docx 的测试 DOCX 文件。%PDF- 开头。FontMapper 映射中文字体到服务器上已安装或注册的物理字体文件。NoClassDefFoundError 或 ClassNotFoundException?
pom.xml 中的依赖是否完整,特别是 docx4j, docx4j-export-PDF, fop, xmlgraphics-commons 的版本是否兼容且已下载。运行 mvn dependency:tree 检查依赖树。OutOfMemoryError)?
-Xmx),考虑异步处理,优化文档图片。Docx4J.toPDF 方法内部使用的是哪个 PDF 库?
PdfSettings 配置为使用 "Plutext" 时,docx4j-export-PDF 模块使用 Plutext 的 PDF 转换器。其底层在旧版本可能基于 iText 5.x (AGPL),新版本可能使用其他渲染器(如 Flying Saucer + iText 或 PDFBox)。务必注意其依赖库的许可证要求(特别是 iText AGPL 对分发的影响)。.doc 文件,docx4j 本身不直接支持加载。你需要先将 DOC 转换为 DOCX(例如使用 Apache POI 的 HWPF 组件读取 DOC 并写入 DOCX),或者使用其他专门处理 DOC 的库。本指南详细介绍了如何在 Spring Boot 应用中,使用开源的 docx4j 库实现 DOCX 文档到 PDF 的转换。内容包括:
docx4j 提供了一个相对轻量级、开源且不依赖外部 Office 软件的解决方案,非常适合集成到 Java 后端服务中。虽然处理极端复杂的文档或某些特殊元素时可能存在挑战,但对于大多数常见的业务文档转换需求,它是一个强大而实用的工具。通过本指南的步骤和注意事项,你应该能够成功地在 Spring Boot 应用中实现 DOCX 转 PDF 功能。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online