java实现word转pdf文件下载
**
引言
如果你的项目是需要部署在linux
环境下,这篇文章可以只看引言部分,如果可以部署在windows
环境下,你可以继续阅读
在最近的需求中,有需要实现word转pdf的功能,在此记录学习的过程。经过一段时间的查阅资料,发现大体有以下几种选择去实现该需求,我没有尝试成功的就不上代码了,跟大家在引言部分说明下原因。
-
jacob
免费,效果好,缺点是必须windows环境,装wps或office
-
documents4j
免费,效果好,缺点是必须windos环境,装office
-
asponse
该方式需要收费,如果使用免费版本会有水印的存在,而且网上流传的license方法基本已经失效,想要使用,自己想办法
-
Spire.Doc
该方式需要收费,免费版本仅仅支持转换前3页,效果好
-
poi
该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题
-
XdocReport
该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题
-
docx4j
该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题
如果你只是在完成个人学习项目的需求,部署环境为linux,我推荐可以采用asponse
或Spire.Doc
。如果你有足够的精力去精研,可以去尝试poi
的方式。
由于我这边项目部署是windows环境,所以这里选择 documents4j
,因为该方式相比于 jacob
不需要去修改 jdk 的原生环境,在下面我将给大家具体去实现并介绍我觉得还可以的两种方式documents4j
和jacob
。
jacob
环境搭建
要求:
- windows环境
- 有WPS或Office(选择数据源)
优点:
- 免费
- 转换效果好
缺点:
- 转换速度较慢
- 必须windows环境
- 需要改变jdk原环境
-
-
下载zip包
-
解压压缩包后,可以看见其中有以下文件
-
选择自己电脑合适版本的
dll
文件,放入jdk中jre的bin目录中,即C:\Program Files\Java\jdk1.8.0_311\jre\bin
-
将需要使用的jar包在项目中引入即可(如果需要使用maven方式引入,请自行去搜索如何引入)
代码示例
经过从网上搜查的资料,我将其整理成了3个方式的工具类,都可以直接使用
- 自定义线程池方式:该方式可以减少转换所需的时间,只是在类初始化的时候时间有点慢
- 非自定义线程池:这个方式我个人来感觉是最满足官方要求的,使用自定义线程池的方式我认为有点不符合规范,但目前还发现问题
- 可选择wps还是office方式:根据当前环境是安装的wps还是office来选择
ActiveXComponent
自定义线程池方式
初始化20多秒,后面每次都是3秒左右
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* <p>
*
* </p>
*
* @author:雷子杰
* @date:2022/9/6
*/
@Slf4j
@Component
//Word.Application
public class TestUtil {
//word 转换为 pdf 的格式宏,值为 17
private static final int WORD_FORMAT_PDF = 17;
// 线程池队列
private static BlockingQueue<Dispatch> dispatchPool = new LinkedBlockingQueue<>();
// 线程池大小
private static int MAX_DISPATCH_SIZE = 10;
static {
long start = System.currentTimeMillis();
for (int i = 0; i < MAX_DISPATCH_SIZE; i++) {
// 这里需要根据当前环境安装的是 MicroSoft Office还是WPS来选择
// 如果安装的是WPS,则需要使用 KWPS.Application
// 如果安装的是微软的 Office,需要使用 Word.Application
ActiveXComponent axc = new ActiveXComponent("Word.Application");
axc.setProperty("Visible", false);
axc.setProperty("AutomationSecurity", new Variant(3));
Dispatch dispatch = axc.getProperty("Documents").toDispatch();
dispatchPool.add(dispatch);
}
long end = System.currentTimeMillis();
log.debug("初始化线程池队列时间:"+(end-start));
}
/**
* Word 转 PDF
* @param wordFile Word文件全路径
* @param pdfFile Pdf全路径
*/
public static void wordToPdf(String wordFile, String pdfFile) {
log.debug("Word转PDF开始启动...");
long start = System.currentTimeMillis();
Dispatch dispatch = null;
try {
File outFile = new File(pdfFile);
// 如果目标文件存在,则先删除
if (outFile.exists()) {
outFile.delete();
}
//获取阻塞队列中disoatch
dispatch =getDispatch();
Dispatch document = Dispatch.call(dispatch, "Open", wordFile, false, true).toDispatch();
//Dispatch.call(document, "ExportAsFixedFormat", pdfFile, WORD_FORMAT_PDF);
Dispatch.call(document, "SaveAs", pdfFile, WORD_FORMAT_PDF);
Dispatch.call(document, "Close", false);
long end = System.currentTimeMillis();
log.info("word转pdf时间:" + (end - start) + "ms");
} catch (Exception e) {
log.error("Word转PDF出错:" + e.getMessage());
return;
} finally {
if (dispatch != null) {
//将dispathch添加回去阻塞队列中
relaseDispatch(dispatch);
}
}
}
@SneakyThrows
private static Dispatch getDispatch() {
return dispatchPool.take();
}
@SneakyThrows
private static void relaseDispatch(Dispatch dispatch) {
dispatchPool.add(dispatch);
}
}
非自定义线程池
均速在9秒左右
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
/**
* <p>
*
* </p>
*
* @author:雷子杰
* @date:2022/9/6
*/
@Slf4j
public class Test2Util {
public static void convertWordToPdf(String wordFile,String pdfFile){
File file = new File(wordFile);
if(file.exists()){
if (!file.isDirectory()) { //判断word文件存不存在
ActiveXComponent app = null;
log.debug("============开始转换============");
// 开始时间
long start = System.currentTimeMillis();
try {
//新增优化代码==============>初始化com的线程
// ComThread.InitSTA(); 仅允许线程池里面的一个线程执行,其他线程都被锁住
ComThread.InitMTA(true); //允许同时有多个WORD进程运行
// 打开word
app = new ActiveXComponent("Word.Application");
// 设置word不可见
app.setProperty("Visible", false);
// 获得所有打开的文档
Dispatch documents = app.getProperty("Documents").toDispatch();
log.debug("============打开文件: " + wordFile);
// 打开文档
Dispatch document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
// 判断文件是否存在
File target = new File(pdfFile);
if (target.exists()) {
target.delete();
}
// 另存为,将文档保存为pdf,其中word保存为pdf的格式宏的值是17
Dispatch.call(document, "SaveAs", pdfFile, 17);
// 关闭文档
Dispatch.call(document, "Close", false);
// 结束时间
long end = System.currentTimeMillis();
System.out.println("word转换pdf时间:" + (end - start) + "ms");
}catch(Exception e) {
log.error("pdf转换发生异常convertWordToPdf:"+e.getLocalizedMessage());
throw new RuntimeException("pdf转换失败!请联系技术人员。");
}finally {
// 关闭office
if (app != null) {
long start2 = System.currentTimeMillis();
app.invoke("Quit", new Variant[] {});
long end2 = System.currentTimeMillis();
log.debug("关闭office的时间:"+(end2-start2));
}
long start3 = System.currentTimeMillis();
//新增优化代码==============>关闭com的线程
ComThread.Release();
long end3 = System.currentTimeMillis();
log.debug("关闭com线程的时间:"+(end3-start3));
}
}
}
}
}
可选择WPS还是office方式
import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import lombok.SneakyThrows;
import java.io.File;
import java.nio.file.Files;
import java.util.Objects;
/**
* <p>
*
* </p>
*
* @author:雷子杰
* @date:2022/9/6
*/
public class WordToPdfUtils {
/** word 转换为 pdf 的格式宏,值为 17 */
private static final int WORD_FORMAT_PDF = 17;
private static final String MS_OFFICE_APPLICATION = "Word.Application";
private static final String WPS_OFFICE_APPLICATION = "KWPS.Application";
/**
* 微软Office Word转PDF
* 如果无法转换,可能需要下载 SaveAsPDFandXPS.exe 插件并安装
* @param wordFile Word文件
* @param pdfFile Pdf文件
*/
public static void msOfficeToPdf(String wordFile, String pdfFile) {
wordToPdf(wordFile, pdfFile, MS_OFFICE_APPLICATION);
}
/**
* WPS Office Word转PDF
* @param wordFile Word文件
* @param pdfFile Pdf文件
*/
public static void wpsOfficeToPdf(String wordFile, String pdfFile) {
wordToPdf(wordFile, pdfFile, WPS_OFFICE_APPLICATION);
}
/**
* Word 转 PDF
* @param wordFile Word文件
* @param pdfFile Pdf文件
* @param application Office 应用
*/
private static void wordToPdf(String wordFile, String pdfFile, String application) {
Objects.requireNonNull(wordFile);
Objects.requireNonNull(pdfFile);
Objects.requireNonNull(application);
ActiveXComponent app = null;
Dispatch document = null;
try {
File outFile = new File(pdfFile);
// 如果目标路径不存在, 则新建该路径,否则会报错
if (!outFile.getParentFile().exists()) {
Files.createDirectories(outFile.getParentFile().toPath());
}
// 如果目标文件存在,则先删除
if (outFile.exists()) {
outFile.delete();
}
// 这里需要根据当前环境安装的是 MicroSoft Office还是WPS来选择
// 如果安装的是WPS,则需要使用 KWPS.Application
// 如果安装的是微软的 Office,需要使用 Word.Application
app = new ActiveXComponent(application);
app.setProperty("Visible", new Variant(false));
app.setProperty("AutomationSecurity", new Variant(3));
Dispatch documents = app.getProperty("Documents").toDispatch();
document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
Dispatch.call(document, "ExportAsFixedFormat", pdfFile, WORD_FORMAT_PDF);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (document != null) {
Dispatch.call(document, "Close", false);
}
if (app != null) {
app.invoke("Quit", 0);
}
ComThread.Release();
}
}
}
测试
测试我这里就不展示了,就大概说一下逻辑
- 判断文件类型,是否是word文档
- 判断文件是否存在
- word转换为pdf(转换出来的路径默认是word文件的资源路径)
documents4j
环境搭建
要求:
- windows环境
- 有Office
优点:
- 免费
- 转换效果好
缺点:
- 必须windows环境
- 只支持docx格式
引入maven依赖
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-local</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.documents4j</groupId>
<artifactId>documents4j-transformer-msoffice-word</artifactId>
<version>1.1.1</version>
</dependency>
代码示例
执行该段程序,即可
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* <p>
*
* </p>
*
* @author:雷子杰
* @date:2022/9/8
*/
public class wordToPdf {
public static void main(String[] args) {
//示例:File wordFile = "D:\\SimpleSolution\\Data\\Welcome to Word.docx";
File wordFile = new File( "需要转换的word文件全路径");
File target = new File( "转换后pdf文件路径" );
IConverter converter = LocalConverter.builder()
.baseFolder(new File("D:\\SimpleSolution\\Data"))
.workerPool(20, 25, 2, TimeUnit.SECONDS)
.processTimeout(30, TimeUnit.SECONDS)
.build();
try {
converter
.convert(wordFile).as(DocumentType.MS_WORD)
.to(target).as(DocumentType.PDF)
.execute();
}finally {
converter.shutDown();
}
}
}
构建工具类
这个是已经封装好的工具类,直接拿去用即可
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* <p>
* word转换工具类
* </p>
*
* @author:雷子杰
* @date:2022/9/8
*/
@Slf4j
public class WordConvertUtil {
/**
* 使用document4j
* word转换为pdf
*
* @param wordPath word全路径
* @param pdfPath 转换成的pdf全路径
*/
public static void wordToPdf(String wordPath,String pdfPath){
/*
根据传进来的全路径,转化为文件对象
*/
File source = new File(wordPath);
File target = new File(pdfPath);
/*
Local converter
*/
IConverter converter = LocalConverter.builder()
//临时文件路径,word文件的目录,之后会更换一个固定的
.baseFolder(new File(source.getParent()))
.workerPool(20, 25, 2, TimeUnit.SECONDS)
.processTimeout(30, TimeUnit.SECONDS)
.build();
/*
The API
*/
try {
converter
.convert(source).as(DocumentType.MS_WORD) //来源文件(可为流形式)、文件类型
.to(target).as(DocumentType.PDF) //转换成的文件(可为流形式),文件类型
.execute();
}finally {
//关闭转换器
converter.shutDown();
}
}
}
测试
这里就不展示了
总结
目前只是解决了在windows下如何将word转换为pdf的功能,如何在linux中去实现,目前还未解决。
更多推荐
所有评论(0)