公司业务:在线预览office文件,调研了一下,目前市场上免费的,比较合适的,也就是OpenOffice了,事已至此,干活。。。
思路:
1.利用 OpenOffice 以及 jodconverter 转换各种office文件为pdf格式
2.设置response的contentType为application/pdf,直接用IO将pdf文件输出就可以了(缺点:若用户使用ie浏览器则是下载而不是预览)
3.利用多进程--利用SpringMVC一个用户请求就有一个新的线程为此服务,但转换的openoffice进程只有一个,所以就算使用多线程还是相当于排队等一个转好了,下一个才会去转换。所以这里使用多进程(这里没有使用Process类)。
4.所有文件只转换一次--因为转换的pdf文件都放在某个目录下,所以只要我先判断对应的目录下有无该文件,若有就直接取出,若没有就去转换。
5.用锁处理并发转换问题--有这么一种情况,两个用户同时请求预览同一个文件,同时发现文件还为转换为pdf,同时去转换导致转换异常,这时可以考虑加锁去处理,如果有一方正在转换了,另一方就直接等待转换好去现成的就可以了
步骤:
1、去官网下载openOffice,并安装,下载地址:Apache OpenOffice - Official Download
2、引入相关jar,jar包不太好找,能从公共资源上pull下来的也就这些了,不过不用担心,对待普通的业务需求也够用了
compile group: 'org.jodconverter', name: 'jodconverter-core', version: '4.0.0-RELEASE'
compile group: 'org.openoffice', name: 'jurt', version: '3.0.1'
compile group: 'org.openoffice', name: 'ridl', version: '3.0.1'
compile group: 'org.openoffice', name: 'juh', version: '3.0.1'
compile group: 'org.openoffice', name: 'unoil', version: '3.0.1'
3、controller层
//调用转换方法
File file= storeService.wordToPDF(key);
if (file.exists()){
byte[] data = null;
try {
FileInputStream input = new FileInputStream(file);
data = new byte[input.available()];
input.read(data);
response.getOutputStream().write(data);
input.close();
} catch (Exception e) {
System.out.println(e);
}
}
4、service层,用注解管理,开启、关闭进程
@Component
public class LocalFileService{
private final static String PORTS = "ports";
private final static String PROPERTIES_FILE_NAME = "openOffice.properties";
private final static String[] ports =
PropertiesUtil.getPropertyByFileAndName(PROPERTIES_FILE_NAME,PORTS).split(",");
private static OfficeManager OfficeManager = null;
public static BlockingQueue<OfficeManager> OfficeManagerQueue = new LinkedBlockingDeque<OfficeManager>();
@PostConstruct
public void getOfficeManager() {
DefaultOfficeManagerBuilder builder = new DefaultOfficeManagerBuilder();
builder.setOfficeHome(getOfficeHome());
for(String port : ports){
builder.setPortNumbers(Integer.parseInt(port));
OfficeManager = builder.build();
try {
OfficeManager.start();
System.out.println("##############officeManager start !");
} catch (OfficeException e) {
//打印日志
System.out.println("start openOffice Fail!");
e.printStackTrace();
}
try {
//都放入阻塞队列中
OfficeManagerQueue.put(OfficeManager);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@PreDestroy
public void destroyOpenOfficeService(){
for(OfficeManager manager : OfficeManagerQueue){
try {
System.out.println("close all officeManager");
manager.stop();
} catch (OfficeException e) {
System.out.println("officeManager stop fail!"+e.getMessage());
e.printStackTrace();
}
}
}
}
5、转换工具类核心代码
public class Office2PDF {
private static Lock lock = new ReentrantLock();
private static Map fileMap = new ConcurrentHashMap<>(16);
private Office2PDF(){}
/**
* 将office格式的文件转为pdf
* @param sourceFilePath 源文件路径
* @return
*/
public static File openOfficeToPDF(String sourceFilePath,String saveDir){
return office2pdf(sourceFilePath,saveDir);
}
/**
* 将office文档转换为pdf文档
* @param sourceFilePath 原文件路径
* @return
*/
public static File office2pdf(String sourceFilePath,String saveDir){
OfficeManager officeManager = null;
File sourceFile = new File(sourceFilePath);
try{
if(StringUtil.isEmpty(sourceFilePath))
{
System.out.println("源文件路径为空");
//打印日志...
return null;
}
if(!sourceFile.exists())
{
System.out.println("源文件不存在");
//打印日志...
return null;
}
/*转换后文件路径*/
String afterConvertFilePath = getAfterConverFilePath(sourceFilePath,saveDir);
officeManager = OfficeManagerQueue.take();
System.out.println("blockingQueue taked , OfficeManagerQueue size :" + OfficeManagerQueue.size());
return convertFile(sourceFile,afterConvertFilePath,sourceFilePath,officeManager);
}catch (Exception e){
e.printStackTrace();
try {
OfficeManagerQueue.put(officeManager);
System.out.println("blockingQueue put , OfficeManagerQueue size :" + OfficeManagerQueue.size());
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
System.out.println("转换异常");
}
return null;
}
/**
* 转换文件
* @param sourceFile 原文件
* @param afterConvertFilePath 转换后存放位置
* @param sourceFilePath 原文件路径
* @param officeManager 转换器
* @return
*/
public static File convertFile(File sourceFile,
String afterConvertFilePath,String sourceFilePath,OfficeManager officeManager) throws OfficeException {
File outputFile = new File(afterConvertFilePath);
if(!outputFile.getParentFile().exists()){
//如果上级目录不存在也就是E:/pdfFile这个文件夹不存在则创建一个
outputFile.getParentFile().mkdirs();
}
OfficeDocumentConverter converter = new OfficeDocumentConverter(officeManager);
lock.lock();
if(fileMap.containsKey(sourceFile.getName()))
{
lock.unlock();
while(true) {
if (outputFile.exists()) {
// System.out.println("文件有了");
try {
OfficeManagerQueue.put(officeManager);
} catch (InterruptedException e) {
e.printStackTrace();
}
return outputFile;
}else{
converter.convert(sourceFile,outputFile);
try {
OfficeManagerQueue.put(officeManager);
} catch (InterruptedException e) {
e.printStackTrace();
}
return outputFile;
}
}
}
else
{
fileMap.put(sourceFile.getName(),sourceFile.getName());
if(outputFile.exists()){
lock.unlock();
// System.out.println("文件有了");
try {
OfficeManagerQueue.put(officeManager);
} catch (InterruptedException e) {
e.printStackTrace();
}
return outputFile;
}
}
lock.unlock();
converter.convert(sourceFile,outputFile);
try {
OfficeManagerQueue.put(officeManager);
//System.out.println("blockingQueue puted OfficeManagerQueue size :" + OfficeManagerQueue.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
return outputFile;
}
/**
* 获取转换后文件存放的路径
* @param sourceFilePath 源文件
* @return
*/
public static String getAfterConverFilePath(String sourceFilePath,String saveDir){
//截取源文件文件名
String sourceFileName = sourceFilePath.substring(sourceFilePath.lastIndexOf("/") + 1);
String suffStr=FileUtil.getFileSuffix(sourceFileName);
String nowName=saveDir+"/"+ sourceFileName.replaceAll( suffStr,".pdf");
return nowName;
}
/**
* 获取openOffice的安装目录
* @return
*/
public static String getOfficeHome(){
String osName = System.getProperty("os.name");
if(Pattern.matches("Windows.*",osName))
{
return "C:/Program Files (x86)/openOffice 4";
}
else if(Pattern.matches("Linux.*",osName))
{
return "/usr/temp";
}
else if (Pattern.matches("Mac.*",osName))
{
return "/Application/openOfficeSoft";
}
return null;
}
}
6、读取properties文件的工具类
package com.yhb.vortex.util;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Properties;
public class PropertiesUtil {
private String properiesName = "";
public PropertiesUtil() {
}
public PropertiesUtil(String fileName) {
this.properiesName = fileName;
}
public String readProperty(String key) {
String value = "";
InputStream is = null;
try {
is = PropertiesUtil.class.getClassLoader().getResourceAsStream(
properiesName);
Properties p = new Properties();
p.load(is);
value = p.getProperty(key);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return value;
}
public Properties getProperties() {
Properties p = new Properties();
InputStream is = null;
try {
is = PropertiesUtil.class.getClassLoader().getResourceAsStream(
properiesName);
p.load(is);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return p;
}
public void writeProperty(String key, String value) {
InputStream is = null;
OutputStream os = null;
Properties p = new Properties();
try {
is = new FileInputStream(properiesName);
p.load(is);
os = new FileOutputStream(PropertiesUtil.class.getClassLoader().getResource(properiesName).getFile());
p.setProperty(key, value);
p.store(os, key);
os.flush();
os.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (null != is)
is.close();
if (null != os)
os.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static String getPropertyByFileAndName(String propertyName, String key){
PropertiesUtil p=new PropertiesUtil(propertyName);
return p.readProperty(key);
}
}
7、properties文件
ports=9001,9002,9003,9004
8、前端js代码
handleFilePreview:function(file){
window.open("##填入你的controller路径##,"_blank");
}