Java实现在线预览附件 office转换PDF
因为项目是做OA这一块,有很多附件需要实现在线预览附件,在网上也看了很多相关的资料。主要实现方式就是 (openoffice+swftools+flexpaper)和(aspose+pdfjs预览)。
主要步骤:
1.需要先将文档转换为PDF文件。
2.用pdfjs预览PDF文件
转换步骤:
* 使用OpenOffice/Aspose 将ppt、word、excel、txt类型的文件转换为pdf
预览步骤:
* 高版本浏览器上,使用pdf.js直接预览PDF文件
* 低版本浏览器上,使用swftools将PDF文件转换为swf文件,再使用flexpaper预览swf(没有做这个步骤)
组件安装:
Aspose
由于OpenOffice的转换效果并不太佳,这里选择了Aspose
在Aspose官网下载Aspose的Java版本,主要选择
* Aspose.words
* Aspose.cells(Excel)
* Aspose.slides(PPT)
* Aspose.pdf
下载完成后,在工程中引用jar包即可。
功能实现:
这里采用的所有组件版本为:
名称 版本
Aspose.words 16.8.0
Aspose.cells 9.0.0
Aspose.slides 116.7.0
Aspose.pdf 11.8.0
文档转换为PDF
使用Aspose进行文档转换很简单,直接引入相应的jar包,调用save方法,转换为PDF即可。
注意:
1. 使用Aspose时,每一个模块(words,cells)都可能有相同的类,如License类,SaveOptions类,SaveFormat类。而在各自模块使用时,一定要用对应模块的类,这个坑我已爬过。
使用Aspose时,需要每次进行转换操作前调用设置License方法。
package com.ybg.pf.oamodule.work.module.convert.util;
import org.apache.log4j.Logger;
import java.io.FileInputStream;
import java.io.InputStream;
/**
* Aspose注册工具
*
* @author zhumin
* @version 1.0.0
* 2017年05月16日 15:58
* @since Jdk1.7
*/
public class AsposeLicenseUtil {
private static InputStream inputStream = null;
private static Logger logger = Logger.getLogger(AsposeLicenseUtil.class);
/**
* 获取License的输入流
*
* @return
*/
private static InputStream getLicenseInput() {
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
try {
String path = contextClassLoader.getResource("license.xml").toURI().getPath();
inputStream = new FileInputStream(path);
} catch (Exception e) {
logger.error("license not found!", e);
}
return inputStream;
}
/**
* 设置License
*
* @return true表示已成功设置License, false表示失败
*/
public static boolean setWordsLicense() {
InputStream licenseInput = getLicenseInput();
if (licenseInput != null) {
try {
com.aspose.words.License aposeLic = new com.aspose.words.License();
aposeLic.setLicense(licenseInput);
return aposeLic.getIsLicensed();
} catch (Exception e) {
logger.error("set words license error!", e);
}
}
return false;
}
/**
* 设置License
*
* @return true表示已成功设置License, false表示失败
*/
public static boolean setCellsLicense() {
InputStream licenseInput = getLicenseInput();
if (licenseInput != null) {
try {
com.aspose.cells.License aposeLic = new com.aspose.cells.License();
aposeLic.setLicense(licenseInput);
return true;
} catch (Exception e) {
logger.error("set cells license error!", e);
}
}
return false;
}
/**
* 设置License
*
* @return true表示已成功设置License, false表示失败
*/
public static boolean setSlidesLicense() {
InputStream licenseInput = getLicenseInput();
if (licenseInput != null) {
try {
com.aspose.slides.License aposeLic = new com.aspose.slides.License();
aposeLic.setLicense(licenseInput);
return aposeLic.isLicensed();
} catch (Exception e) {
logger.error("set ppt license error!", e);
}
}
return false;
}
/**
* 设置Aspose PDF的license
* @return true表示设置成功,false表示设置失败
*/
public static boolean setPdfLicense() {
InputStream licenseInput = getLicenseInput();
if (licenseInput != null) {
try {
com.aspose.pdf.License aposeLic = new com.aspose.pdf.License();
aposeLic.setLicense(licenseInput);
return true;
} catch (Exception e) {
logger.error("set pdf license error!", e);
}
}
return false;
}
}
word文档转换代码实例:
package com.ybg.pf.oamodule.work.module.convert.service.impl;
import com.aspose.words.Document;
import com.aspose.words.PdfSaveOptions;
import com.aspose.words.SaveFormat;
import com.ybg.pf.oamodule.work.module.convert.domain.ConvertStatus;
import com.ybg.pf.oamodule.work.module.convert.service.File2PdfService;
import com.ybg.pf.oamodule.work.module.convert.util.AsposeLicenseUtil;
import org.apache.log4j.Logger;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 将doc文档转换为pdf文件
*
* @author zhumin
* @version 1.0.0
* 2017年05月16日 15:58
* @since Jdk1.7
*/
public class Doc2PdfServiceImpl implements File2PdfService {
private Logger logger = Logger.getLogger(getClass());
@Override
public ConvertStatus convert2Pdf(InputStream inputStream, OutputStream outputStream) {
try {
if (AsposeLicenseUtil.setWordsLicense()) {
Document doc = new Document(inputStream);
// insertWatermarkText(doc, "水印水印"); // 添加水印
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
pdfSaveOptions.setSaveFormat(SaveFormat.PDF);
pdfSaveOptions.getOutlineOptions().setHeadingsOutlineLevels(3); // 设置3级doc书签需要保存到pdf的heading中
pdfSaveOptions.getOutlineOptions().setExpandedOutlineLevels(1); // 设置pdf中默认展开1级
doc.save(outputStream, pdfSaveOptions);
inputStream.close();
outputStream.flush();
outputStream.close();
return ConvertStatus.SUCCESS;
} else {
return ConvertStatus.LICENSE_ERROR;
}
} catch (Exception e) {
return ConvertStatus.CONVERT_DOC2PDF_ERROR;
}
}
}
其他格式就不附下面会提供代码下载。
预览流程:先在后台下载附件到项目指定临时目录,在读取下载文件转换为PDF存储到临时目录
这是目录结构:convertFile附件下载存放目录 outputFilePDF存储目录
package com.ybg.pf.oamodule.common.util;
import com.ybg.pf.framework.library.util.FileRWUtils;
import com.ybg.pf.framework.library.util.LogUtil;
import com.ybg.pf.oamodule.work.module.convert.domain.ConvertStatus;
import com.ybg.pf.oamodule.work.module.convert.service.File2PdfService;
import com.ybg.pf.oamodule.work.module.convert.service.impl.Doc2PdfServiceImpl;
import com.ybg.pf.oamodule.work.module.convert.service.impl.Excel2PdfServiceImpl;
import com.ybg.pf.oamodule.work.module.convert.service.impl.PPT2PdfServiceImpl;
import org.apache.commons.lang.StringUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by Administrator on 2017/5/11.
* 在线预览工具类
* 文件下载工具
*/
public class PreviewUtils {
//转换服务
private static File2PdfService fileConvertService;
/**
* office转换PDF
* @param fileName 需要转换的文件名
* @return
* @throws Exception
*/
public static ConvertStatus officeConversionPDF(String fileName) throws Exception{
//获取文件后缀
String suffix = fileName.substring(fileName.lastIndexOf(".")+1,fileName.length());
String fileNames = fileName.substring(0,fileName.lastIndexOf("."));
//根据后缀判断文件类型实例化对应服务层
if (StringUtils.equalsIgnoreCase(suffix,"docx") || StringUtils.equalsIgnoreCase(suffix,"doc")){
fileConvertService = new Doc2PdfServiceImpl();
}else if (StringUtils.equalsIgnoreCase(suffix,"pptx") || StringUtils.equalsIgnoreCase(suffix,"ppt")){
fileConvertService = new PPT2PdfServiceImpl();
}else if (StringUtils.equalsIgnoreCase(suffix,"xlsx") || StringUtils.equalsIgnoreCase(suffix,"xls")){
fileConvertService = new Excel2PdfServiceImpl();
}
ConvertStatus convertStatus = null;
//获取需要转换文档的所在路径
File officeFile = new File(savePath()+File.separator+fileName);
File outputFile = new File(outPDFPath(fileNames) +File.separator+ fileNames+".pdf");//PDF保存文件路径
//如果文件是 PDF 不用转换直接复制到指定目录
if (StringUtils.equalsIgnoreCase(suffix,"pdf")){
FileRWUtils.copyFile(officeFile.getPath(),outPDFPath(fileNames));
return convertStatus;
}
if (!outputFile.exists()){
InputStream inputStream = new FileInputStream(officeFile);
OutputStream outputStream = new FileOutputStream(outputFile);
//开始转换
convertStatus = fileConvertService.convert2Pdf(inputStream, outputStream);
}
return convertStatus;
}
/**
* 根据PDF文件名获取PDF存储地址
* @param fileName PDF文件名
* @return
* 没有加.toURI() 有可能中文路径会乱码 加上获取会出错
*/
public static String outPDFPath(String fileName) throws Exception{
String pathName = PreviewUtils.class.getClassLoader().getResource("").getPath();
//文件保存位置 如果文件夹不存在创建文件夹
File saveDir = new File(pathName+File.separator+"outputFile");
if(!saveDir.exists()){
saveDir.mkdir();
}
return saveDir.getPath();
}
/**
* 获取文件保存路径
* @return
*/
public static String savePath(){
String pathName = PreviewUtils.class.getClassLoader().getResource("").getPath();
//文件保存位置 如果文件夹不存在创建文件夹
File saveDir = new File(pathName+File.separator+"convertFile");
if(!saveDir.exists()){
saveDir.mkdir();
}
return saveDir.getPath();
}
/**
* 从网络Url中下载文件
* @param urlStr 下载地址
* @param fileName 文件名
* @param savePath 保存地址
* @throws IOException
*/
public static boolean downLoadFromUrl(String urlStr,String fileName,String savePath){
File file = new File(savePath+File.separator+fileName);
//文件是否已存在
if(file.exists()){
return true;
}
try {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
//设置超时间为30秒
conn.setConnectTimeout(30*1000);
//防止屏蔽程序抓取而返回403错误
conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
//得到输入流
InputStream inputStream = conn.getInputStream();
//获取自己数组
byte[] getData = readInputStream(inputStream);
FileOutputStream fos = new FileOutputStream(file);
if (getData == null){
return false;
}
fos.write(getData);
if(fos!=null){
fos.close();
}
if(inputStream!=null){
inputStream.close();
}
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK){
return true;
}
} catch (IOException e) {
LogUtil.error("附件下载转换PDF出错!",e);
}
return false;
}
/**
* 从输入流中获取字节数组
* @param inputStream
* @return
* @throws IOException
*/
public static byte[] readInputStream(InputStream inputStream) throws IOException {
byte[] buffer = new byte[1024];
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while((len = inputStream.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bos.close();
return bos.toByteArray();
}
}
由于我们要集成到自己的工程中来,所以此处直接copy了viewer.html页面,修改为了我们工程需要的view_pdfjs.jsp ,其中做了一些修改删除了部分不需要的功能
下面是我修改过后的预览页面 效果图:
<%@ page import="com.ybg.pf.oamodule.common.constant.JspCommonConstant" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
String qiyehaoProje