Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 1370|回复: 0

[默认分类] SpringBoot-文件在线预览解决方案-基于OpenOffice及jacob

[复制链接]
  • TA的每日心情
    开心
    2021-12-13 21:45
  • 签到天数: 15 天

    [LV.4]偶尔看看III

    发表于 2020-8-13 17:22:36 | 显示全部楼层 |阅读模式
    项目中有一个需求:实现文件(主要是Office文件)的在线预览,根据前端需求,Office文件需要转换成pdf或者HTML方可在浏览器中打开预览,那么后端需要将文件转为pdf/格式返回地址给前端。目前,了解到的解决方案大概有两种,一种是基于Apache组织下的开源项目:OpenOffice,一种是使用jacob桥接方案。两种方案均可实现需求,但是在使用过程中遇到些许波折与坑,写在这里,与大家共勉。
    方案一、OpenOffice
      OpenOffice.org 是一套跨平台的办公室软件套件,能在Windows、Linux、MacOS X (X11)和 Solaris 等操作系统上执行。它与各个主要的办公室软件套件兼容。OpenOffice.org 是自由软件,任何人都可以免费下载、使用及推广它(来自 :百度百科)。

      
      因为他是开源的,所以提供了可供java等开发语言开发的API,在此基础上,我们可以使用它来完成一些功能的转换、开发。
    开发流程:
      (1)安装OpenOffice
        因为用到其功能,因此首先需要安装它,下载地址:https://cwiki.apache.org/confluence/display/OOOUSERS/AOO+4.1.6+Release+Notes
      安装过程简单,直接下一步即可。
      (2)Springboot集成Open Office
        首先引入jar包:如下是必须的

    因为有些jar包,maven仓库找不到,所以我把它放在了项目中,然后在pom文件中进行了引用

    这里需要注意的是,引入jar包后,还需要在intelliJ Idea中设置project Structer引入。
    (3)工具类编写
      这里支持的是所有的Office文件以及txt文件,包括03版和07版均兼容。
    核心代码:



      
    1. 1 /**
    2. 2      * 转换文件成pdf
    3. 3      *
    4. 4      * @param :
    5. 5      * @throws IOException
    6. 6      */
    7. 7     public static void fileTopdfbak(File docInputFile, String toFilePath, String type) {
    8. 8         String timesuffix = UUID.randomUUID().toString();
    9. 9         String pdfFileName = null;
    10. 10         if("doc".equals(type)||"docx".equals(type)){
    11. 11             pdfFileName = timesuffix.concat(".pdf");
    12. 12         }else if("xls".equals(type)||"xlsx".equals(type)){
    13. 13             pdfFileName = timesuffix.concat(".pdf");
    14. 14         }else if("ppt".equals(type) || "pptx".equals(type)){
    15. 15             pdfFileName = timesuffix.concat(".pdf");
    16. 16         }else if("txt".equals(type)){
    17. 17             pdfFileName = timesuffix.concat(".pdf");
    18. 18         }else{
    19. 19             return ;
    20. 20         }
    21. 21
    22. 22         String realPath=toFilePath+pdfFileName;
    23. 23         File pdfOutputFile = new File(realPath);
    24. 24         if (pdfOutputFile.exists()){
    25. 25             pdfOutputFile.delete();
    26. 26         }
    27. 27         String contextpath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort();
    28. 28         String url = contextpath +EnumUtil.CONVERT_PDF_PATH.getCode()+pdfFileName;
    29. 29         System.out.println("文件服务器路径:"+url);
    30. 30         pdfOutputFile.createNewFile();
    31. 31 //            docInputFile.createNewFile();
    32. 32         OpenOfficeConnection connection = new SocketOpenOfficeConnection("127.0.0.1",8100);
    33. 33         System.out.println("connection:"+connection);
    34. 34         connection.connect();
    35. 35         // convert
    36. 36         DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection);
    37. 37         if(null!=docInputFile){
    38. 38             converter.convert(docInputFile, pdfOutputFile);
    39. 39         }
    40. 40         connection.disconnect();
    41. 41         // 转换完之后删除word文件
    42. 42 //        docInputFile.delete();
    43. 43     }
    复制代码

      
    View Code

    这里需要注意的是:在使用之前需要先启动安装的Open Office服务,windows启动命令:
    在安装该软件的地方进入
    openOffice4/program 目录,然后cmd执行:
    1. [b]soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard
    2. [/b]经过测试,该方法可用,
    复制代码


      
    1. 但是,项目中有个需求,大文件(超过2G)也需要在线预览,于是,试了下800兆的文件,测试过程中,出现了问题,800兆的文件出现了转换失败的情况,而且观察内存使用情况,发现内存使用较高,运行慢,出错后内存不会释放,报错信息:
    复制代码


    意思大概是内存分配错误,运行OpenOffice的可视化工具,直接用这个软件好像800M的ppt也打不开,后来查资料得知,通过设置可以增加内存,但是尝试了几次,发现可设置的内存最大到256M

      

    通过网上查资料,发现根本没有解决方法,因此该方案不得不放弃,如果大家有什么好的解决方案,欢迎留言讨论,不胜感激!
    方案二、使用jacob
      首先,我们需要知道什么是jacob,官方文档中有一句话:JACOB is a JAVA-COM Bridge that allows you to call COM Automation components from Java. It uses JNI to make native calls to the COM libraries. JACOB runs on x86 and x64 environments supporting 32 bit and 64 bit JVMs,翻译过了就是:Jacob是一个Java-COM桥,允许您调用COM自动化组件。不难理解,该方案提供了java和COM(ComponentObjectModel,组件对象模型)之间的一个桥梁,个人理解类似于数据库提供的驱动。
      该方案的实现过程就是通过java来调用window中的Office来达到文件格式转换的目的,类似于我们打开一个文档,选择另存为其他格式的过程。因为在Windows操作平台下,众多以COM形式提供的组件模块,如DirectX多媒体软件包、OLEDB/ADO数据库组件系统等,极大地丰富了操作系统的功能。由于COM机制允许任意两组件之间相互通信而不必关心是在何种计算机上的何种操作系统下运行,也不用关心组件是使用何种语言编制的,这使COM技术拥有了强大的生命力。而我们需要的是Office的组件,因此,需要jacob来建立windows和Java之间的桥梁。
    开发过程:
    (1)下载jacob.jar及相关dll文件
      因为在maven仓库中有该jar包,直接引入,也可直接下载:http://www.java2s.com/Code/Jar/j/Downloadjacob1143jar.htm

    另外,还需要jacob-1.14.3-x64.dll(系统64位),jacob-1.14.3-x86.dll(系统32位),可以百度自行下载,这里需要注意的是版本一定要和jar包的版本保持一致。将下载好的文件拷贝一下两个目录:
    C:\Windows\System32(64位),D:\Program Files\Java\jre1.8.0_131\bin jre的安装目录,注意不是jdk里面的jre,网上有说将拷贝至jdk下面的jre/bin下的,估计是环境不一样,我试过会报错。
    (2)核心代码



      
    1. /**
    2.      *
    3.      * @Title: ppt2PDF
    4.      * @Description: 转换ppt为office
    5.      * @param @param inputFile
    6.      * @param @param pdfFile
    7.      * @param @return    设定文件
    8.      * @return boolean    返回类型
    9.      * @throws
    10.      */
    11.     public static boolean ppt2PDF(String inputFile,String pdfFile){
    12.         try{
    13.             System.out.println("PowerPoint.Application............");
    14.             ActiveXComponent app = new ActiveXComponent("PowerPoint.Application");
    15.             //app.setProperty("Visible", msofalse);
    16.             Dispatch ppts = app.getProperty("Presentations").toDispatch();
    17.             Dispatch ppt = Dispatch.call(ppts,
    18.                     "Open",
    19.                     inputFile,
    20.                     true,//ReadOnly
    21.                     true,//Untitled指定文件是否有标题
    22.                     false//WithWindow指定文件是否可见
    23.             ).toDispatch();
    24.             Dispatch.call(ppt,
    25.                     "SaveAs",
    26.                     pdfFile,
    27.                     ppSaveAsPDF
    28.             );
    29.             Dispatch.call(ppt, "Close");
    30.             app.invoke("Quit");
    31.             return true;
    32.         }catch(Exception e){
    33.             return false;
    34.         }
    35.     }
    36.     /**
    37.      *
    38.      * @Title: word2PDF
    39.      * @Description: 转换word文档为pdf
    40.      * @param @param inputFile
    41.      * @param @param pdfFile
    42.      * @param @return    设定文件
    43.      * @return boolean    返回类型
    44.      * @throws
    45.      */
    46.     public static boolean word2PDF(String inputFile,String pdfFile){
    47.         try{
    48.             //打开word应用程序
    49.             ActiveXComponent app = new ActiveXComponent("Word.Application");
    50.             //设置word不可见
    51.             app.setProperty("Visible", false);
    52.             //获得word中所有打开的文档,返回Documents对象
    53.             Dispatch docs = app.getProperty("Documents").toDispatch();
    54.             //调用Documents对象中Open方法打开文档,并返回打开的文档对象Document
    55.             Dispatch doc = Dispatch.call(docs,
    56.                     "Open",
    57.                     inputFile,
    58.                     false,
    59.                     true
    60.             ).toDispatch();
    61.             //调用Document对象的SaveAs方法,将文档保存为pdf格式
    62.         /*
    63.         Dispatch.call(doc,
    64.                     "SaveAs",
    65.                     pdfFile,
    66.                     wdFormatPDF     //word保存为pdf格式宏,值为17
    67.                     );
    68.                     */
    69.             Dispatch.call(doc,
    70.                     "ExportAsFixedFormat",
    71.                     pdfFile,
    72.                     wdFormatPDF     //word保存为pdf格式宏,值为17
    73.             );
    74.             //关闭文档
    75.             Dispatch.call(doc, "Close",false);
    76.             //关闭word应用程序
    77.             app.invoke("Quit", 0);
    78.             return true;
    79.         }catch(Exception e){
    80.             return false;
    81.         }
    82.     }
    83.     /**
    84.      *
    85.      * @Title: excel2PDF
    86.      * @Description: 转换excel为PDF
    87.      * @param @param inputFile
    88.      * @param @param pdfFile
    89.      * @param @return    设定文件
    90.      * @return boolean    返回类型
    91.      * @throws
    92.      */
    93.     public static boolean excel2PDF(String inputFile,String pdfFile){
    94.         try{
    95.             ActiveXComponent app = new ActiveXComponent("Excel.Application");
    96.             app.setProperty("Visible", false);
    97.             Dispatch excels = app.getProperty("Workbooks").toDispatch();
    98.             Dispatch excel = Dispatch.call(excels,
    99.                     "Open",
    100.                     inputFile,
    101.                     false,
    102.                     true
    103.             ).toDispatch();
    104.             Dispatch.call(excel,
    105.                     "ExportAsFixedFormat",
    106.                     xlTypePDF,
    107.                     pdfFile
    108.             );
    109.             Dispatch.call(excel, "Close",false);
    110.             app.invoke("Quit");
    111.             return true;
    112.         }catch(Exception e){
    113.             return false;
    114.         }
    115.     }
    复制代码

      
    View Code

    测试结果:直接上800M的ppt,测试结果:

      
    经过测试,只要是微软Office能打开的文件,都可以完成转换。
    (4)问题及坑
      开发过程中,发现测试在本地可行,发布到服务器报错,内容如下:
    java.lang.NoSuchMethodError: com.jacob.com.Dispatch.call(Lcom/jacob/com/Dispatch;Ljava/lang/String;[Ljava/lang/Object;)Lcom/jacob/com/Variant;
    at com.thupdi.project.utils.OfficeToPDFUtils.ppt2PDF(OfficeToPDFUtils.java:99)
    at com.thupdi.project.utils.OfficeToPDFUtils.convert2PDF(OfficeToPDFUtils.java:69)

    方法找不到,应该是缺少jar包或者jar包冲突导致的。
    解决方案,找到之前引用的jar包,因为之前在项目中导入过jacob.jar包,所以导致冲突。还有一种可能就是maven打包的时候没有把项目中引用的jar包(非maven引入)一并打入war/jar包,导致找不到方法。按这种方法顺利解决的问题,大家如果有这个问题,可以按这两个方法尝试解决。
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-4-20 09:08 , Processed in 0.398713 second(s), 51 queries .

    Powered by Discuz! X3.4

    © 2001-2017 Comsenz Inc.

    快速回复 返回顶部 返回列表