doc转swf,主流文档在线查看有关问题解决方案
引言:
最近项目中对上传的文件需要在线查看功能(就是不用下载到本地,可以直接在网页里打开的查看),通过几周的研究终于搞定,在此总结下共有同样需求的同仁查询和使用。
原理:
通常的在线查看功能都是使用文档转换工具,把原始文档转换成swf文档,然后通过网页直接展示文档内容。
解决方案:
在前期技术研究的过程中,发现有三种解决方案,他们分别是:
1、使用 FlextPaper + Pdf2swf 组合。
缺点是只能提供pdf转换成swf然后在线查看。要支持其他格式的话,需要先转成pdf,这样的话效率有点低。不过网上这种方式的资料挺多的。
2、使用FlashPaper 把文档转成swf直接显示
这种方式的好处在于支持多种格式的文档转换,支持的文档格式包括(doc、docx、xls、xlsx、pdf、txt, ppt、pptx), ppt、pptx的支持效果不怎么好,转换有些慢,要支持这两种方式的话,有专有的转换工具。
原来准备使用FlashPaper转换成swf文档,然后使用FlexPaper显示的,但是发现使用FlexPaper显示FlashPaper转成的swf存在问题,不能显示swf内容,而且不停的闪。后来想起浏览器可以直接支持swf显示的。使用<object><embed>标签即可。
还有一个好处就是这个工具免费。
缺点就是: 最后版本2.2,发布于2008年5月,此后不再支持;支持winxp, server2003等,不支持win7系统;
3、使用Print2Flash把文档转换成swf直接显示
这个东西比FlashPaper更强大,功能更全面,而且提供各种系统的支持。是一个非常不错的工具。
缺点就是:需要money,有需求的公司可以使用。
我的方案:
我选用的第二种方案,免费,而且对各种当前流行的文档都支持,同时服务器是window server 2003。下面说下具体的程序吧。
1、FlashPaper的安装
可以在网上下载 FlashPaper2.2绿色版,地址: http://download.****.net/detail/walkerjong/4420486
下载安装程序后,可以点击install.bat安装FlashPaper,若出现下面的错误:
flashpaper AddPrinterDriver stage 13: error 126 - 找不到指定的模块
错误原因: 安装操作系统的时候没有开启系统还原功能,FlashPaper需要使用该功能。
解决方案: 把安装文件包里的srclient.dll文件拷贝到c:/windows/system32/目录下。
当然也可以使用java程序自动安装,下面是我的工具类代码:FlashPaperUtil.java
package org.study.isap.common.util; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Scanner; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; public class FlashPaperUtil { private static final Logger logger = Logger.getLogger(FlashPaperUtil.class); // flashPaper的存放位置 public static final String FLASH_PAPER_DIR = "bin/flashPaper2_2"; // 转换各种格式的文档为swf的命令 public static final String FLASH_PAPER_CMD = "FlashPrinter.exe"; /* swf的跨域访问策略文件,只有部署了该文件在集群服务器上才能相互访问swf。 * 部署地址: 服务器的根目录下。例如:http://localhost.com/crossdomain.xml */ public static final String crossDomain = "crossdomain.xml"; private static final File flashPaperDir = initDir(); static { Thread t = new InstallThread(); t.start(); } private FlashPaperUtil(){ } private static File initDir(){ File dir = new File(FileUtil.getWebRootPath(), FLASH_PAPER_DIR); logger.debug("flashPaperDir["+dir.getAbsolutePath()+"]"); return dir; } /** * 卸载flashPaper。 */ private static void uninstall(){ String uninstallCmd = "uninstall.bat"; try { String cmd =new File(flashPaperDir, uninstallCmd).getAbsolutePath(); Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(cmd, null, flashPaperDir); try { process.waitFor(); logger.debug("============= FlashPaper 卸载信息如下 ==============="); Scanner scanner = new Scanner(process.getErrorStream()); try{ while(scanner.hasNextLine()){ logger.error(scanner.nextLine()); } }finally{ scanner.close(); } scanner = new Scanner(process.getInputStream()); try{ while(scanner.hasNextLine()){ logger.debug(scanner.nextLine()); } }finally{ scanner.close(); } } catch (InterruptedException e) { logger.error(e); }finally{ process.destroy(); } runtime = null; logger.info("卸载FlashPaper成功,cmd["+cmd+"]"); } catch (IOException e) { logger.error(e); logger.error("卸载FlashPaper时出现错误。"); } } /** * 安装flashPaper。 */ private static void install(){ String installCmd = "install.bat"; if(checkInstallEnvironment()){ try { String cmd =new File(flashPaperDir, installCmd).getAbsolutePath(); Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(cmd, null, flashPaperDir); try { process.waitFor(); logger.debug("============= FlashPaper 安装信息如下 ==============="); Scanner scanner = new Scanner(process.getErrorStream()); try{ while(scanner.hasNextLine()){ logger.error(scanner.nextLine()); } }finally{ scanner.close(); } scanner = new Scanner(process.getInputStream()); try{ while(scanner.hasNextLine()){ logger.debug(scanner.nextLine()); } }finally{ scanner.close(); } } catch (InterruptedException e) { logger.error(e); }finally{ process.destroy(); } runtime = null; logger.info("安装FlashPaper成功,cmd["+cmd+"]"); } catch (IOException e) { logger.error(e); logger.error("安装FlashPaper时出现错误。"); } } } /** * 检查安装flashPaper的环境。 * @return */ private static boolean checkInstallEnvironment(){ String systemRoot = System.getenv("SystemRoot"); File dest = new File(systemRoot, "system32/srclient.dll"); logger.debug("操作系统安装路径["+systemRoot+"]"); if(!dest.exists()){ String srcFile = "srclient.dll"; try { File src = new File(flashPaperDir, srcFile); FileUtil.copyFile(src, dest); return true; } catch (FileNotFoundException e) { logger.error(e); logger.error("找不到要拷贝的源文件["+srcFile+"]"); } catch (IOException e) { logger.error(e); logger.error("复制文件出错, 源文件["+srcFile+"], 目标文件["+dest.getAbsolutePath()+"]"); } logger.error("您的环境不能自动安装FlashPaPer,需要手动安装,安装程序位置/WEB-INF/classes/"+FLASH_PAPER_DIR); return false; }else{ return true; } } /** * 使用flashpaper将文档格式转换生产swf文件。 * 支持格式: office(word、excel),pdf, txt等主流格式。 * @param path * @return */ public static File fileToSwf(String input, String output){ File inputFile = new File(input); File outputFile = new File(output); return fileToSwf(inputFile, outputFile); } /** * 使用flashpaper将文档格式转换生产swf文件。 * 支持格式: office(word、excel),pdf, txt等主流格式。 * @param path * @return */ public static File fileToSwf(File input, File output){ if(input == null || !input.exists()){ logger.error("要转换为swf的文件为空或不存在!"); return null; } if(output.exists()){ logger.info("swf["+output+"]已经存在。"); return output; } String printerCmd = new File(flashPaperDir, FLASH_PAPER_CMD).getAbsolutePath(); String cmd = printerCmd+" "+input.getAbsolutePath()+" -o "+output.getAbsolutePath(); logger.debug("fileToSwf cmd["+cmd+"]"); try { Process process = Runtime.getRuntime().exec(cmd, null, flashPaperDir); try {//等待转换完成 process.waitFor(); } catch (InterruptedException e) { logger.error(e); } Scanner scanner = new Scanner(process.getErrorStream()); try{ if(scanner.hasNext()){ while(scanner.hasNextLine()){ logger.error(scanner.nextLine()); } } }finally{ scanner.close(); // 关闭进程释放资源 process.destroy(); } } catch (IOException e) { logger.error("转换文档为swf失败, path["+input.getAbsolutePath()+"]", e); } return output; } private static class InstallThread extends Thread { public InstallThread(){ setDaemon(true); } public void run(){ uninstall(); install(); } } }
FileUtil.java 文件如下:
package org.study.isap.common.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Logger; import org.springframework.util.StringUtils; public class FileUtil { private static final Logger logger = Logger.getLogger(FileUtil.class); // web工程的文件系统根目录 (/**/isap) private static final String webRootPath; // web工程的URL根目录 (http://***.**/isap) private static String webRootUrl; static { webRootPath = initWebFileBase(); webRootUrl = null; } private FileUtil(){ } private static String initWebFileBase(){ String classPath = FileUtil.class.getClassLoader().getResource("").getFile(); int index = classPath.lastIndexOf("/WEB-INF/classes"); if(index != -1){ String fileBase = classPath.substring(0, index); logger.info("获取isap文件系统根路径成功, webFileBase["+fileBase+"]"); return fileBase; }else{ logger.error("获取isap文件系统根路径错误,请检查是否有/WEB-INF/classes路径。path["+classPath+"]"); return ""; } } //------------------ 路径相关 ----------------- /** * 返回web工程的文件系统的绝对路径。 * @return */ public static String getWebRootPath(){ return webRootPath; } /** * 把相对webFileBase的path转换成url形式的字符串。 * 例如:<br/> * 输入: /uploadFiles/project/file/test.doc <br/> * 输出:http://127.0.0.1:8080/isap/uploadFiles/project/file/test.doc <br/> * @param request * @param path * @return */ public static String getDocUrl(HttpServletRequest request, String path){ if(!StringUtils.hasLength(webRootUrl)){ webRootUrl = request.getScheme()+"://"+request.getLocalAddr()+":"+request.getLocalPort()+request.getContextPath(); } if(StringUtils.hasLength(path)){ if(path.startsWith("http://")){ return path; } path = path.replace('\\', '/'); }else{ return webRootUrl; } if(!path.startsWith("/")){ return webRootUrl+"/"+path; } return webRootUrl+path; } // ----------------------- 文件名和文件类型相关 ---------------- /** * 获取文件名称。 */ public static String getFileName(String docUrl){ int index = docUrl.lastIndexOf("/"); if(index != -1){ return docUrl.substring(index+1); }else{ return docUrl; } } /** * 获取文件类型, 返回带点号的文件类型。例如“.doc” * * @param docUrl * @return */ public static String getFileType(String docUrl){ int index = docUrl.lastIndexOf("."); if(index != -1){ return docUrl.substring(index); }else{ return docUrl; } } /** * 获得输入路径下,同名文件的swf文件。 <br /> * * @param path * @param fileType * @return */ public static String getSwfFile(String path){ String swfPath = null; if(StringUtils.hasLength(path)){ int index = path.lastIndexOf("."); if(index != -1){ swfPath = path.substring(0, index)+".swf"; } } return swfPath; } public static File getSwfFile(File file) { String swfpath = getSwfFile(file.getAbsolutePath()); return new File(swfpath); } // ---------- 复制文件 --------- public static void copyFile(File src, File dest) throws IOException{ File dir = dest.getParentFile(); if(!dir.exists()){ dir.mkdirs(); } BufferedInputStream input = null; BufferedOutputStream output = null; try{ input = new BufferedInputStream(new FileInputStream(src)); output = new BufferedOutputStream(new FileOutputStream(dest)); int length = 0, flushCount=0; byte[] buffer = new byte[4*1024]; while((length = input.read(buffer)) >= 0){ output.write(buffer, 0, length); flushCount++; if(flushCount%5==0){ output.flush(); } } }finally{ FileUtil.closeOutputStream(output); FileUtil.closeInputStream(input); } } // ------------- 关闭文件流 -------------------- /** * 关闭输入流。 * @param input */ public static void closeInputStream(InputStream input){ if(input != null){ try { input.close(); } catch (IOException e) { logger.error("关闭输入文件失败!"); logger.error(e); } } } /** * 关闭输出流。 * @param output */ public static void closeOutputStream(OutputStream output){ if(output != null){ try { output.close(); } catch (IOException e) { logger.error("关闭输出文件失败!"); logger.error(e); } } } }
说明: 下载下来的flashPaper安装程序解压后放置在 WebContent/bin/目录下。
程序自动的时候自动安装,若检测到没有使用系统还原功能,自动拷贝文件到系统system32目录下。
2、在上面贴出的代码中,使用FlashPaperUtil. fileToSwf()函数即可完成对可支持文档的转换。即转成swf文件。
3、显示转成成的swf文件。
displaySwf.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" %> <%@ taglib prefix="c" uri="/WEB-INF/tld/c.tld" %> <% String webRoot = request.getContextPath(); %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <base href="<%=webRoot%>/view/common/" /> <title>在线显示文档</title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <style type="text/css" media="screen"> html,body{ margin: 0px; padding: 0px; overflow: hidden; height: 100%; } #content{ width:100%; height:100%; MARGIN: 0px auto; } </style> </head> <body> <c:if test="${swfUrl!=null}"> <div id="content"> <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0" width="100%" height="100%" > <param name="movie" value="${swfUrl}" /> <param name="quality" value="high" /> <param name="allowFullScreen" value="true" /> <embed pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" src="${swfUrl}" allowfullscreen="true" quality="high" width="100%" height="100%" > </embed> </object> </div> </c:if> <c:if test="${swfUrl==null}"> <div class="box error center" style="width:60%;"> <h1>没有指定要显示的文档路径!</h1> </div> </c:if> </body> </html>
处理请求的controller类中相关方法:
/** * 显示在线文档。 * @return */ @RequestMapping("show") public String show(String swfUrl, HttpServletRequest request){ request.setAttribute("swfUrl", swfUrl); return "common/displaySwf"; }
请求显示在线文档的url如下:
http://localhost:8080/isap/fileManage/show.action?swfUrl=http://192.168.1.100/isap_doc/1341818769265.swf
注: 在FlashPaper转各类文档的时候,看到他们相关程序打开了要转的文件,然后转换的。所以碰到问题的时候注意检查一下几点:
1、服务器上是否安装相关文档的打开程序,例如office 2007 --> docx;
2、检查服务器上的Print Spoller服务是否启动,虚拟打印需要用到该服务;
3、还是失败的话,用cmd运行FlashPaper安装程序下的install.bat, 查看错误原因。
ok,至此为止已经完成各种文档的转换和显示问题,希望能有同样需求的同仁们少走弯路。