一、实现的思路
word转换pdf可能有很多插件可用,但是程序员不论实现什么功能之前,首先要思考业务场景!我的业务场景,对word格式的还原度要求很高,要完全一致无变化!一开始我是想用poi把word转成htm,然后用jsoup解析一下,再用Itext转成pdf。但是当我看到生成的html效果,我就放弃了……格式只保留的基本的雏形,什么分页符啊换行的说丢就丢了。还有一个libreOffice,这个插件写的代码少,大部分格式都能保留,但是缺少原版字体,导致跟原来的word还是不一样。目前还未能找到纯java对格式完美支持的备用方案,希望大神赐教…
通过度娘找到一种调用office的方法,jacob!这种方式能实现完美保留word格式,而且速度不还算慢,2页4秒,第一次生成后存为附件后面就可以n次愉快地下载了。但是这个方法也不是完全顺利,后面遇到一些奇葩问题度娘了很多都是无效的,所以决定总结一下。后续如果项目有问题还会继续更新此文!
二、准备
1、服务器环境:64位window sserver 2012、win10 操作系统
jdk1.6+tomcat7.x、jdk1.8+tomcat9.0.11
均是64位。
开发工具是myeclipse2017
2、java用到的jar包:jacob-1.18(据说低版本的连jdk1.6都不支持)
3、服务器要安装:office2007及以上(32或64位的2010、2013版本均通过)
4、dl文件:jacob-1.18-x64.dll、jacob-1.18-x86.dll
要放到…\Java\jdk1.8.0_181\jre\bin下,放到jdk下面的Bin会不兼容
三、代码
public void convertWordToPdf(String wordFile,String pdfRoot, String pdfName) throws Exception {
File file = new File(wordFile);
String pdfFile = pdfRoot + File.separator + pdfName;
if(file.exists()){
if (!file.isDirectory()) {
//判断word文件存不存在
//创建Pdf目录
File pdfBase = new File(pdfRoot);
if(!pdfBase.exists()){
pdfBase.mkdir();
}
ActiveXComponent app = null;
System.out.println("============开始转换============");
// 开始时间
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();
System.out.println("============打开文件: " + wordFile);
// 打开文档
Dispatch document = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch();
// 判断文件是否存在
File target = new File(pdfFile);
if (target.exists()) {
target.delete();
}
System.out.println("============另存为: " + pdfFile);
// 另存为,将文档报错为pdf,其中word保存为pdf的格式宏的值是17
Dispatch.call(document, "SaveAs", pdfFile, 17);
// 关闭文档
Dispatch.call(document, "Close", false);
// 结束时间
long end = System.currentTimeMillis();
System.out.println("============转换结束:" + (end - start) + "ms");
}catch(Exception e) {
logger.error("pdf转换发生异常convertWordToPdf:"+e.getLocalizedMessage());
throw new RuntimeException("pdf转换失败!请联系技术人员。");
}finally {
// 关闭office
if (app != null) {
app.invoke("Quit", new Variant[] {
});
}
//新增优化代码==============>关闭com的线程
ComThread.Release();
}
}
}
}
四、注意事项
1、项目启动不了: 刚开始把dll放到jdk下面的Bin了,改放jdk里面的jre\bin。
2、如果服务器是以服务形式启动tomcat,会报错:com.jacob.com.ComFailException: Can’t co-create object
需要配置权限:打开命令提示窗口,输入mmc comexp.msc 回车
在组件服务中展开:控制台–>组件服务–>计算机–>我的电脑–>DCOM配置–>找到Microsoft Office 97-2003的节点
右键选择属性–>标识选项卡–>勾选“下列用户”,输入计算机登陆账号和密码并确定。
PS:如果是本地开发,配置改成选择“交互式”用户(一般系统已默认,无需配置)
3、上一步配置的用户名,要和服务(本地)列表中,tomcat服务的登录用户一致!(对于限定了启动和关闭tomcat服务的登录账户来说,需要指定同样的账户给调用word权限)
4、确保版本统一,如安装的jdk是64位,操作系统、Tomcat要保持一致。
感谢的博客:
java将doc文件转换为pdf文件的三种方法(比较)
http://feifei.im/archives/93
POI转html报jar包错误
http://m.360sdn.com/java/2017/0119/13273.html
Jacob在服务器上不能使用的解决方法
https://blog.csdn.net/qq_31757133/article/details/52089212