jacob调用office实现word文件转pdf文件的过程(完美格式和图片、兼容docx)

本文介绍使用Java和Jacob库将Word文档转换为PDF的详细过程,包括环境配置、代码实现及常见问题解决,确保格式完美迁移。

一、实现的思路

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.youkuaiyun.com/qq_31757133/article/details/52089212

在使用 LibreOffice 将文档导出为 PDF 时,部分用户报告出现总页码显示错误的问题。例如,文档实际页数为 10 页,但在 PDF 的页码信息中显示为其他数值,或在文档属性中显示的总页数不准确。这一问题可能影响文档的打印、归档分发流程。 造成此问题的原因可能包括文档中存在隐藏的分页符、分节符、页眉页脚设置异常,或者 LibreOffice过程中未能正确识别页数结构。此外,在命令行换时,未正确加载文档结构也可能导致页数统计错误。 为了解决此问题,可采取以下方法: - **手动检查文档结构** 在 LibreOffice Writer 中打开原始文档,启用“显示非打印字符”功能(点击 ¶ 按钮),查看是否存在不必要的分页符或分节符,并手动删除。确保文档的分节设置不会影响页码统计。 - **使用命令行参数优化过程** 在执行命令行换时,建议使用以下参数组合,以确保文档结构被整加载并正确渲染为 PDF: ```bash libreoffice --headless --convert-to pdf:writer_pdf_Export \ "--env:UserInstallation=file:///tmp/LibreOffice_Conversion_${RANDOM}" \ --outdir /output/path /input/document.docx \ --writer --norestore --nodefault --nolockcheck --nologo --nofirststartwizard ``` 其中 `--env:UserInstallation` 参数用于创建临时用户配置,避免因缓存或配置冲突导致页码识别错误;`--writer` 参数确保文档以 Writer 模加载,有助于提升页码识别的准确性;`--norestore` `--nologo` 等参数可避免不必要的界面元素干扰过程[^2]。 - **使用 JODConverter 等工具进行封装调用** 若需在 Java 应用中集成文档换功能,可借助 JODConverter 等库封装 LibreOffice换流程。通过 `OfficeDocumentConverter` 类调用换服务,可确保文档结构在过程中保持一致,从而避免页码信息丢失或错误: ```java OfficeManager officeManager = new DefaultOfficeManagerConfiguration().buildOfficeManager(); OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager); converter.convert(new File("document.docx")).as(DocumentType.DOCX) .to(new File("output.pdf")).as(DocumentType.PDF) .execute(); ``` 此方通过标准 API 调用 LibreOffice,可减少因命令行参数配置不当导致的页码统计问题[^4]。 - **更新 LibreOffice 到最新版本** LibreOffice 官方持续修复文档换中的各类问题,包括页码识别、格兼容性等。建议将 LibreOffice 升级至最新稳定版本,例如 LibreOffice 24.8.1,该版本修复了 89 个已知问题,提升了 DOCX、XLSX 等格兼容性,有助于减少页码显示错误的发生概率[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值