• java中使用jacob实现word转pdf文件下载


    引言

    如果你的项目是需要部署在linux环境下,这篇文章可以只看引言部分,如果可以部署在windows环境下,你可以继续阅读

    在最近的需求中,有需要实现word转pdf的功能,在此记录学习的过程。经过一段时间的查阅资料,发现大体有以下几种选择去实现该需求,我没有尝试成功的就不上代码了,跟大家在引言部分说明下原因。

    • jacob

      免费,效果好,缺点是必须windows环境,装wps或office

    • documents4j

      免费,效果好,缺点是必须windos环境,装office

    • asponse

      该方式需要收费,如果使用免费版本会有水印的存在,而且网上流传的license方法基本已经失效,想要使用,自己想办法

    • Spire.Doc

      该方式需要收费,免费版本仅仅支持转换前3页,效果好

    • poi

      该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题

    • XdocReport

      该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题

    • docx4j

      该方式不需要收费,但我使用该方式转换的文件会出现排版混乱的问题

    如果你只是在完成个人学习项目的需求,部署环境为linux,我推荐可以采用asponseSpire.Doc。如果你有足够的精力去精研,可以去尝试poi的方式。

    由于我这边项目部署是windows环境,所以这里选择 documents4j ,因为该方式相比于 jacob 不需要去修改 jdk 的原生环境,在下面我将给大家具体去实现并介绍我觉得还可以的两种方式documents4jjacob

    jacob

    环境搭建

    要求:

    • windows环境
    • 有WPS或Office(选择数据源)

    优点:

    • 免费
    • 转换效果好

    缺点:

    • 转换速度较慢
    • 必须windows环境
    • 需要改变jdk原环境
    1. 进入jacob.jar下载页面

      image-20220906211615067

    2. 下载zip包

      image-20220906211656098

    3. 解压压缩包后,可以看见其中有以下文件

      image-20220906211837066

    4. 选择自己电脑合适版本的dll文件,放入jdk中jre的bin目录中,即C:\Program Files\Java\jdk1.8.0_311\jre\bin

      image-20220906212059884

    5. 将需要使用的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;
    
    /**
     * 

    * *

    * * @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); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    非自定义线程池

    均速在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;
    
    /**
     * 

    * *

    * * @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)); } } } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    可选择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;
    
    /**
     * 

    * *

    * * @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(); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    测试

    测试我这里就不展示了,就大概说一下逻辑

    1. 判断文件类型,是否是word文档
    2. 判断文件是否存在
    3. word转换为pdf(转换出来的路径默认是word文件的资源路径)

    documents4j

    环境搭建

    要求:

    • windows环境
    • 有Office

    优点:

    • 免费
    • 转换效果好

    缺点:

    • 必须windows环境
    • 只支持docx格式

    引入maven依赖

    <dependency>
        <groupId>com.documents4jgroupId>
        <artifactId>documents4j-localartifactId>
        <version>1.1.1version>
    dependency>
    
    <dependency>
        <groupId>com.documents4jgroupId>
        <artifactId>documents4j-transformer-msoffice-wordartifactId>
        <version>1.1.1version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    代码示例

    执行该段程序,即可

    import com.documents4j.api.DocumentType;
    import com.documents4j.api.IConverter;
    import com.documents4j.job.LocalConverter;
    
    import java.io.File;
    import java.util.concurrent.TimeUnit;
    
    /**
     * 

    * *

    * * @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(); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    构建工具类

    这个是已经封装好的工具类,直接拿去用即可

    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;
    
    /**
     * 

    * word转换工具类 *

    * * @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(); } } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61

    测试

    这里就不展示了

    总结

    目前只是解决了在windows下如何将word转换为pdf的功能,如何在linux中去实现,目前还未解决。

  • 相关阅读:
    cuda编程学习——GPU加速/时间计时Clock 干货向(五)
    Nacos知识点
    PMP成绩如何查询?
    为什么你辛苦肝的博客没人看?搭框架、排版、画图技巧这些你真的懂么?
    基于FOC电路低次谐波抑制Simulink仿真
    基于JAVA医院挂号管理系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    Linux shell 处理文件路径文件名和后缀截取(basename和dirname无法满足的操作)
    1998年考研真题英语二(204)阅读理解翻译
    物流行业采购协同管理系统:规范采购体系,加快物流行业采购数字化升级
    《俞军产品方法论》笔记心得 01
  • 原文地址:https://blog.csdn.net/qq_49137582/article/details/126734818