1. 程式人生 > >Java實現Office線上預覽

Java實現Office線上預覽

上傳檔案是我們在開發中經常遇到的需求,而某些情況下,我們需要實現Office的線上預覽功能。

一.下載及安裝軟體

1.安裝OpenOffice軟體 ,該軟體的作用是將Office轉換為Pdf

該軟體是Apache旗下的一個免費的文書處理軟體,下載地址:Apache OpenOffice的連結

2.安裝Swftools軟體,作用是將Pdf轉換為Swf

3.安裝FlexPaper,該軟體的作用是解析並顯示SWF格式的檔案

4.執行完上述工作後,進入OpenOffice安裝目錄後啟動OpenOffice服務

執行命令:soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard


二.開發部分對應介紹

  準備相應開發工具jar包

  

 相關js包

  

 如果選用pdfobject.js可選擇不用FlexPaper的特性,因為該指令碼就是為了動態載入pdf。

 

  如果使用FlexPaper,必須將FlexPaperViewer.swf將客戶端檔案放在一起


 專案lib完整jar包圖:

 

 輔助轉換類DocConverter:

package com.itmyhome.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import com.artofsolving.jodconverter.DocumentConverter;
import com.artofsolving.jodconverter.openoffice.connection.OpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.connection.SocketOpenOfficeConnection;
import com.artofsolving.jodconverter.openoffice.converter.OpenOfficeDocumentConverter;

/**
 * doc docx格式轉換
 */
public class DocConverter {
	private static final int environment = 1;// 環境 1:windows 2:linux
	private String fileString="";// (只涉及pdf2swf路徑問題)
	private String outputPath = "";// 輸入路徑 ,如果不設定就輸出在預設的位置
	private String fileName="";
	private File pdfFile=null;
	private File swfFile=null;
	private File docFile=null;
	
	public DocConverter(String fileString) {
		ini(fileString);
	}

	/*
	  *重新設定file
	 *
	 * @param fileString
	 */
	public void setFile(String fileString) {
		ini(fileString);
	}
	/**
	 * 初始化
	 *
	 * @param fileString
	 */
	private void ini(String fileString) {
		this.fileString = fileString;
		fileName = fileString.substring(0, fileString.lastIndexOf("."));
		docFile = new File(fileString);
		pdfFile = new File(fileName + ".pdf");
		swfFile = new File(fileName + ".swf");
	}
	/**
	 * 轉為PDF
	 * OpenOffice的作用是將office轉換為pdf
	 * @param
	 */
	private void doc2pdf() throws Exception {
		if (docFile.exists()) {
			if (!pdfFile.exists()) {
				//啟動OpenOffice服務        soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard 
				OpenOfficeConnection connection = new SocketOpenOfficeConnection(8100);
				try {
					connection.connect();
					DocumentConverter converter = new OpenOfficeDocumentConverter(connection);
					converter.convert(docFile, pdfFile);
					// close the connection
					connection.disconnect();
					System.out.println("****pdf轉換成功,PDF輸出:" + pdfFile.getPath()+ "****");
				} catch (java.net.ConnectException e) {
					e.printStackTrace();
					System.out.println("****swf轉換器異常,openoffice服務未啟動!****");
					throw e;
				} catch (com.artofsolving.jodconverter.openoffice.connection.OpenOfficeException e) {
					e.printStackTrace();
					System.out.println("****swf轉換器異常,讀取轉換檔案失敗****");
					throw e;
				} catch (Exception e) {
					e.printStackTrace();
					throw e;
				}
			} else {
				System.out.println("****已經轉換為pdf,不需要再進行轉化****");
			}
		} else {
			System.out.println("****swf轉換器異常,需要轉換的文件不存在,無法轉換****");
		}
	}
	/**
	 * 轉換成 swf
	 * swftools是將pdf轉換為swf
	 */
	@SuppressWarnings("unused")
	private void pdf2swf() throws Exception {
		Runtime r = Runtime.getRuntime();
		if (!swfFile.exists()) {
			if (pdfFile.exists()) {
				if (environment == 1) {// windows環境處理
					try {
						Process p = r.exec("D:/swftools/pdf2swf.exe	"+ pdfFile.getPath() + " -o "+ swfFile.getPath() + " -T 9");
						System.out.println(loadStream(p.getInputStream()));
						System.err.println(loadStream(p.getErrorStream()));
						System.out.println(loadStream(p.getInputStream()));
						System.err.println("****swf轉換成功,檔案輸出:"
								+ swfFile.getPath() + "****");
						/*if (pdfFile.exists()) {
							pdfFile.delete();
						}*/
					} catch (IOException e) {
						e.printStackTrace();
						throw e;
					}
				} else if (environment == 2) {// linux環境處理
					try {
						Process p = r.exec("pdf2swf " + pdfFile.getPath()
								+ " -o " + swfFile.getPath() + " -T 9");
						System.out.print(loadStream(p.getInputStream()));
						System.err.print(loadStream(p.getErrorStream()));
						System.err.println("****swf轉換成功,檔案輸出:"
								+ swfFile.getPath() + "****");
						if (pdfFile.exists()) {
							pdfFile.delete();
						}
					} catch (Exception e) {
						e.printStackTrace();
						throw e;
					}
				}
			} else {
				System.out.println("****pdf不存在,無法轉換****");
			}
		} else {
			System.out.println("****swf已經存在不需要轉換****");
		}
	}
	static String loadStream(InputStream in) throws IOException {

		int ptr = 0;
		in = new BufferedInputStream(in);
		StringBuffer buffer = new StringBuffer();

		while ((ptr = in.read()) != -1) {
			buffer.append((char) ptr);
		}

		return buffer.toString();
	}
	/**
	 * 轉換主方法
	 */
	@SuppressWarnings("unused")
	public boolean conver() {

		if (swfFile.exists()) {
			System.out.println("****swf轉換器開始工作,該檔案已經轉換為swf****");
			return true;
		}

		if (environment == 1) {
			System.out.println("****swf轉換器開始工作,當前設定執行環境windows****");
		} else {
			System.out.println("****swf轉換器開始工作,當前設定執行環境linux****");
		}
		try {
			doc2pdf();
			pdf2swf();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}

		if (swfFile.exists()) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 返回檔案路徑
	 *
	 * @param
	 */
	public String getswfPath() {
		if (swfFile.exists()) {
			String tempString = swfFile.getPath();
			tempString = tempString.replaceAll("\\\\", "/");
			return tempString;
		} else {
			return "";
		}

	}
	/**
	 * 設定輸出路徑
	 */
	public void setOutputPath(String outputPath) {
		this.outputPath = outputPath;
		if (!outputPath.equals("")) {
			String realName = fileName.substring(fileName.lastIndexOf("/"),
					fileName.lastIndexOf("."));
			if (outputPath.charAt(outputPath.length()) == '/') {
				swfFile = new File(outputPath + realName + ".swf");
			} else {
				swfFile = new File(outputPath + realName + ".swf");
			}
		}
	}

}  

檔案上傳和介面呼叫類 FileController:

package com.itmyhome.web;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.itmyhome.util.DocConverter;

public class FileController extends HttpServlet {
    
	private static final long serialVersionUID = 1L;
	// 儲存檔案的目錄
	private static String PATH_FOLDER = "/";
	// 存放臨時檔案的目錄
	private static String TEMP_FOLDER = "/";
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		 doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 獲得磁碟檔案條目工廠
				DiskFileItemFactory factory = new DiskFileItemFactory();

				// 如果沒以下兩行設定的話,上傳大的 檔案 會佔用 很多記憶體,
				// 設定暫時存放的 儲存室 , 這個儲存室,可以和 最終儲存檔案 的目錄不同
				/**
				 * 原理 它是先存到 暫時儲存室,然後在真正寫到 對應目錄的硬碟上, 按理來說 當上傳一個檔案時,其實是上傳了兩份,第一個是以 .tem
				 * 格式的 然後再將其真正寫到 對應目錄的硬碟上
				 */
				factory.setRepository(new File(TEMP_FOLDER));
				// 設定 快取的大小,當上傳檔案的容量超過該快取時,直接放到 暫時儲存室
				factory.setSizeThreshold(1024 * 1024);

				// 高水平的API檔案上傳處理
				ServletFileUpload upload = new ServletFileUpload(factory);

		
					// 提交上來的資訊都在這個list裡面
					// 這意味著可以上傳多個檔案
					// 請自行組織程式碼
				try{
					@SuppressWarnings("unchecked")
					List<FileItem> list = upload.parseRequest(request);
					// 獲取上傳的檔案
					FileItem item = getUploadFileItem(list);
					// 獲取檔名
					String filename = getUploadFileName(item);



					String filetype = filename.substring(filename.lastIndexOf(".") + 1,
							filename.length());

					filename = Long.toString(System.currentTimeMillis()) + "."
							+ filetype;

					System.out.println("存放目錄:" + PATH_FOLDER);
					System.out.println("檔名:" + filename);

					// 真正寫到磁碟上
					item.write(new File(PATH_FOLDER, filename)); // 第三方提供的
			

				
					
	
						String newDir = Long.toString(System.currentTimeMillis());
				
				
						//呼叫轉換類DocConverter,並將需要轉換的檔案傳遞給該類的構造方法
						DocConverter d = new DocConverter(PATH_FOLDER + "/" + filename);
						//呼叫conver方法開始轉換,先執行doc2pdf()將office檔案轉換為pdf;再執行pdf2swf()將pdf轉換為swf;
						d.conver();
						System.out.println(d.getswfPath());
						//生成swf相對路徑,以便傳遞給flexpaper播放器
						String swfpath = "upload"+d.getswfPath().substring(d.getswfPath().lastIndexOf("/"));
						System.out.println(swfpath);
						//將相對路徑放入sessio中儲存
					
						String pdfpath=swfpath.substring(0, swfpath.lastIndexOf(".")+1)+"pdf";
						Map map=new HashMap();
						map.put("swfpath", swfpath);
						map.put("pdfpath", pdfpath);
					    HttpSession session=request.getSession();
					    session.setAttribute("path", map);
					  
					    File file = new File(PATH_FOLDER+"/"+filename);
					    file.delete();
				}catch (Exception e) {
					// TODO: handle exception
					response.sendRedirect("upload_error.jsp");
				}finally{
					  request.getRequestDispatcher("/upload_ok.jsp").forward(request, response);
				}
					
				
			
	}

	@Override
	public void init(ServletConfig config) throws ServletException {
		ServletContext servletCtx = config.getServletContext();
		// 初始化路徑
		// 儲存檔案的目錄
		PATH_FOLDER = servletCtx.getRealPath("upload");
		// 存放臨時檔案的目錄,存放xxx.tmp檔案的目錄
		TEMP_FOLDER = servletCtx.getRealPath("uploadTemp");
	}
	private FileItem getUploadFileItem(List<FileItem> list) {
		for (FileItem fileItem : list) {
			if (!fileItem.isFormField()) {
				return fileItem;
			}
		}
		return null;
	}

	private String getUploadFileName(FileItem item) {
		// 獲取路徑名
		String value = item.getName();
		// 索引到最後一個反斜槓
		int start = value.lastIndexOf("/");
		// 擷取 上傳檔案的 字串名字,加1是 去掉反斜槓,
		String filename = value.substring(start + 1);

		return filename;
	}
    
}

使用pdf.js方案的程式碼和效果圖如下:

 


使用OpenOffice方案的程式碼和效果圖如下:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<%  
        Map map=(Map)session.getAttribute("path");
        
%> 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>預覽檔案</title>
    
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	    <script type="text/javascript" src="js/jquery.js"></script>
  <script type="text/javascript" src="js/flexpaper_flash.js"></script>
  <script type="text/javascript" src="js/flexpaper_flash_debug.js"></script>
<!--   <script type="text/javascript" src="js/swfobject.js"></script> -->
  <script type="text/javascript" src="js/pdfobject.js"></script> 
  <style type="text/css" media="screen">   
            html, body  { height:100%; }  
            body { margin:0; padding:0; overflow:auto; }     
            #flashContent { display:none; }  
        </style>  

  </head>
  
  <body>
       <div style="position:absolute;left:50px;top:10px;">  
            <a id="viewerPlaceHolder" style="width:820px;height:650px;display:block"></a>  
              
            <script type="text/javascript">   
               var fp = new FlexPaperViewer(     
                         'FlexPaperViewer',  
                         'viewerPlaceHolder', { config : {  
                         SwfFile : escape('<%=map.get("swfpath")%>'),
                         Scale : 0.6,   
                         ZoomTransition : 'easeOut',//變焦過渡  
                         ZoomTime : 0.5,  
                         ZoomInterval : 0.2,//縮放滑塊-移動的縮放基礎[工具欄]  
                         FitPageOnLoad : true,//自適應頁面  
                         FitWidthOnLoad : true,//自適應寬度  
                         FullScreenAsMaxWindow : false,//全屏按鈕-新頁面全屏[工具欄]  
                         ProgressiveLoading : false,//分割載入  
                         MinZoomSize : 0.2,//最小縮放  
                         MaxZoomSize : 3,//最大縮放  
                         SearchMatchAll : true,  
                         InitViewMode : 'Portrait',//初始顯示模式(SinglePage,TwoPage,Portrait)  
                            
                         ViewModeToolsVisible : true,//顯示模式工具欄是否顯示  
                         ZoomToolsVisible : true,//縮放工具欄是否顯示  
                         NavToolsVisible : true,//跳頁工具欄  
                         CursorToolsVisible : false,  
                         SearchToolsVisible : true,  
                            PrintPaperAsBitmap:false,  
                         localeChain: 'en_US'  
                         }});  
            </script>              
        </div>  
  </body>

</html>

總結:

  因為OpenOffice目前不是完全開源,一次效能夠處理的Office有限,小編建議使用pdf.js。