SpringBoot-文件在线预览解决方案-基于OpenOffice及jacob

项目中有一个需求:实现文件(主要是Office文件)的在线预览,根据前端需求,Office文件须要转换成pdf或者html方可在浏览器中打开预览,那么后端须要将文件转为pdf/格式返回地址给前端。目前,了解到的解决方案大概有两种,一种是基于Apache组织下的开源项目:OpenOffice,一种是使用jacob桥接方案。两种方案都可实现需求,可是在使用过程当中遇到些许波折与坑,写在这里,与你们共勉。html

方案1、OpenOffice前端

  OpenOffice.org 是一套跨平台的办公室软件套件,能在Windows、Linux、MacOS X (X11)和 Solaris 等操做系统上执行。它与各个主要的办公室软件套件兼容。OpenOffice.org 是自由软件,任何人均可以避免费下载、使用及推广它(来自 :百度百科)。java

 

  由于他是开源的,因此提供了可供java等开发语言开发的API,在此基础上,咱们可使用它来完成一些功能的转换、开发。数据库

开发流程:apache

  (1)安装OpenOfficewindows

    由于用到其功能,所以首先须要安装它,下载地址:https://cwiki.apache.org/confluence/display/OOOUSERS/AOO+4.1.6+Release+Notes后端

  安装过程简单,直接下一步便可。浏览器

  (2)SpringBoot集成Open Office服务器

    首先引入jar包:以下是必须的app

由于有些jar包,maven仓库找不到,因此我把它放在了项目中,而后在pom文件中进行了引用

这里须要注意的是,引入jar包后,还须要在intelliJ Idea中设置project Structer引入。

(3)工具类编写

  这里支持的是全部的Office文件以及txt文件,包括03版和07版均兼容。

核心代码:

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

这里须要注意的是:在使用以前须要先启动安装的Open Office服务,windows启动命令:

在安装该软件的地方进入

openOffice4/program 目录,而后cmd执行:

soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard


通过测试,该方法可用,

 

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

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

 

经过网上查资料,发现根本没有解决方法,所以该方案不得不放弃,若是你们有什么好的解决方案,欢迎留言讨论,不胜感激!

方案2、使用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)核心代码

/**
     *
     * @Title: ppt2PDF
     * @Description: 转换ppt为office
     * @param @param inputFile
     * @param @param pdfFile
     * @param @return    设定文件
     * @return boolean    返回类型
     * @throws
     */
    public static boolean ppt2PDF(String inputFile,String pdfFile){
        try{
            System.out.println("PowerPoint.Application............");
            ActiveXComponent app = new ActiveXComponent("PowerPoint.Application");
            //app.setProperty("Visible", msofalse);
            Dispatch ppts = app.getProperty("Presentations").toDispatch();
            Dispatch ppt = Dispatch.call(ppts,
                    "Open",
                    inputFile,
                    true,//ReadOnly
                    true,//Untitled指定文件是否有标题
                    false//WithWindow指定文件是否可见
            ).toDispatch();

            Dispatch.call(ppt,
                    "SaveAs",
                    pdfFile,
                    ppSaveAsPDF
            );
            Dispatch.call(ppt, "Close");
            app.invoke("Quit");
            return true;
        }catch(Exception e){
            return false;
        }
    }

    /**
     *
     * @Title: word2PDF
     * @Description: 转换word文档为pdf
     * @param @param inputFile
     * @param @param pdfFile
     * @param @return    设定文件
     * @return boolean    返回类型
     * @throws
     */
    public static boolean word2PDF(String inputFile,String pdfFile){
        try{
            //打开word应用程序
            ActiveXComponent app = new ActiveXComponent("Word.Application");
            //设置word不可见
            app.setProperty("Visible", false);
            //得到word中全部打开的文档,返回Documents对象
            Dispatch docs = app.getProperty("Documents").toDispatch();
            //调用Documents对象中Open方法打开文档,并返回打开的文档对象Document
            Dispatch doc = Dispatch.call(docs,
                    "Open",
                    inputFile,
                    false,
                    true
            ).toDispatch();
            //调用Document对象的SaveAs方法,将文档保存为pdf格式
        /*
        Dispatch.call(doc,
                    "SaveAs",
                    pdfFile,
                    wdFormatPDF     //word保存为pdf格式宏,值为17
                    );
                    */
            Dispatch.call(doc,
                    "ExportAsFixedFormat",
                    pdfFile,
                    wdFormatPDF     //word保存为pdf格式宏,值为17
            );
            //关闭文档
            Dispatch.call(doc, "Close",false);
            //关闭word应用程序
            app.invoke("Quit", 0);
            return true;
        }catch(Exception e){
            return false;
        }
    }

    /**
     *
     * @Title: excel2PDF
     * @Description: 转换excel为PDF
     * @param @param inputFile
     * @param @param pdfFile
     * @param @return    设定文件
     * @return boolean    返回类型
     * @throws
     */
    public static boolean excel2PDF(String inputFile,String pdfFile){
        try{
            ActiveXComponent app = new ActiveXComponent("Excel.Application");
            app.setProperty("Visible", false);
            Dispatch excels = app.getProperty("Workbooks").toDispatch();
            Dispatch excel = Dispatch.call(excels,
                    "Open",
                    inputFile,
                    false,
                    true
            ).toDispatch();
            Dispatch.call(excel,
                    "ExportAsFixedFormat",
                    xlTypePDF,
                    pdfFile
            );
            Dispatch.call(excel, "Close",false);
            app.invoke("Quit");
            return true;
        }catch(Exception e){
            return false;
        }
    }
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包,致使找不到方法。按这种方法顺利解决的问题,你们若是有这个问题,能够按这两个方法尝试解决。

相关文章
相关标签/搜索