Java实现Office在线预览

上传文件是我们在开发中经常遇到的需求,而某些情况下,我们需要实现Office的在线预览功能。

一.下载及安装软件

1.安装OpenOffice软件 ,该软件的作用是将Office转换为Pdf

该软件是Apache旗下的一个免费的文字处理软件,下载地址:Apache OpenOffice的链接

2.安装Swftools软件,作用是将Pdf转换为Swf

下载链接:Swftools官网下载

3.安装FlexPaper,该软件的作用是解析并显示SWF格式的文件

下载链接:FlexPaper官网链接

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。


版权声明:本文为tmac937436原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。