使用 Documents4j 处理 Word 转 PDF
能实现这个功能的框架有很多,在满足免费开源并且效果不错的前提下,决定采用 Documents4j 进行转换。
Documents4j 策略
Documents4j 有两个策略,一个是本地策略,一个是远程策略,分别对应的架包是:
- 本地策略
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-local</artifactId>
<version>1.0.3</version>
</dependency>
- 远程策略
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-client</artifactId>
<version>1.0.3</version>
</dependency>
Documents4j 的转换,可以理解为需要依托于微软的:MicrosoftWord / Excel。在本地机器上开发时(Win 电脑),使用本地策略,是可以完成转换的。但部署到 Linux 服务器上后就不能。
问题分析:
- Win 电脑系统,默认已经有 MicrosoftWord / Excel 了。而服务器上的 Linux 系统并没有对应的服务,因此需要安装对应的插件。这里安装:LibreOffice。(安装教程这里省略不做详述)安装成功后使用命令测试验证:
libreoffice7.1 --invisible --convert-to pdf:writer_pdf_Export /home/demo.docx --outdir /home/
可以成功,但代码运行还是失败。 - 使用命令
/usr/bin/libreoffice7.1 --headless --accept=”socket,host=127.0.0.1,port=8100;urp;”- -nofirststartwizard &
启动 LibreOffice。启动成功后,代码运行还是失败。 - 使用远程策略,在 Win 电脑上安装 LibreOffice,然后代码里指向对应的地址。
官网说明:
- JVM 在 MS Windows 平台上运行,该平台附带 Microsoft Scripting Host for VBS(对于所有现代版本的 MS Windows 都是如此)。
- 安装的 MS Word 版本为 2007 或更高版本。仅当安装 PDF 插件时才支持 PDF 转换。该插件包含在 Word 2010 及更高版本的 MS Word 中。
- 启动时 MS Word 尚未运行
LocalConverter
。对于由另一个 .NET 实例运行的 MS Word 实例尤其如此LocalConverter
。 (如前所述,请注意,对于在不同 JVM 上运行或由不同类加载器加载的实例也是如此。)- MS Word 已为运行 JVM 的用户正确激活和配置。因此,MS Word 不需要在程序启动或任何其他向导时进行任何配置。
- 当使用 JVM 应用程序
LocalConverter
作为服务运行时,请注意下面的 MS Windows 服务配置文件中有关使用 MS Word 的信息。
引入架包
<!--word转pdf-->
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-client</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-transformer-msoffice-word</artifactId>
<version>1.0.3</version>
</dependency>
<!--远程调用需要的架包-->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
核心代码
// 转换后的文件信息, PDF 文件
File fileOut = new File(path);
// 临时文件
File tempPath = new File(temp);
// 远程地址
@Value("${spring.documents4j.url}")
private String documents4jUrl;
// 完成转换的代码,远程转换使用代码 RemoteConverter
IConverter converter = RemoteConverter.builder().baseFolder(tempPath).baseUri(documents4jUrl).build();
converter.convert(file.getInputStream()).as(DocumentType.DOCX).to(new FileOutputStream(fileOut)).as(DocumentType.PDF).execute();
// 完整核心代码
try (InputStream inputStream = file.getInputStream(); FileOutputStream outputStream = new FileOutputStream(fileOut)) {
IConverter converter = RemoteConverter.builder().baseFolder(tempPath).baseUri(documents4jUrl).build();
converter.convert(inputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();
} catch (Exception e) {
throw new Exception("文件转换时发生异常: " + e.getMessage());
} finally {
// 删除临时文件
Files.deleteIfExists(Paths.get(path + pdfName));
}
安装服务
- 下载并安装:documents4j-server-standalone-1.1.8-shaded.jar。
https://repo1.maven.org/maven2/com/documents4j/documents4j-server-standalone/1.1.8/
documents4j-server-standalone-1.1.8-shaded.jar 的运行依赖 jdk,需要实现在 Win 电脑上安装 jdk。
- 编写运行脚本,重命名为.bat 文件。
@echo off
%1 mshta vbscript:CreateObject("WScript.Shell").Run("%~s0 ::",0,FALSE)(window.close)&&exit
java -jar D:\documents4j\documents4j-server-standalone-1.1.8-shaded.jar http://192.168.xxxx:9998 > D:\documents4j\documents4j.log 2>&1 &
exit
- 启动脚本,代码即可执行,后续代码部署到 Linux 也可以执行转换服务。(代码里需要配置好 documents4j-server-standalone 运行的地址和端口)
扩展思考
- 使用本地策略时,如果 Linux 上已经安装 LibreOffice,并成功运行,那么上述代码里的 spring.documents4j.url 换成 Linux 上已经启动的地址,是否可行。
- 把 Linux 上 LibreOffice 运行命令打包成 JAVA 代码,直接调用是否可行。