項目中有一個需求:實現文件(主要是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 }
這裏須要注意的是:在使用以前須要先啓動安裝的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; } }
測試結果:直接上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包,致使找不到方法。按這種方法順利解決的問題,你們若是有這個問題,能夠按這兩個方法嘗試解決。