office轉pdf(線上預覽)思路(java示例)
阿新 • • 發佈:2019-02-14
1.從view訪問到controller的思路
2.關於office轉換為pdf
實現手段可以參見openoffice轉pdf或者別的軟體,網上有具體的轉換手段,我這裡不多說;
大概程式碼如下,這裡的OfficeToPDFInfo是一個包含輸入輸入路徑等的一個Bean:
/** * 將Office文件轉換為PDF. 執行該函式需要用到OpenOffice, OpenOffice下載地址為 * http://www.openoffice.org/ * @param sourceFile * 原始檔, 絕對路徑. 可以是Office2003-2007全部格式的文件, Office2010的沒測試. 包括.doc, * .docx, .xls, .xlsx, .ppt, .pptx等. 示例: F:\\office\\source.doc * @param destFile * 目標檔案. 絕對路徑. 示例: F:\\pdf\\dest.pdf * @return 操作成功與否的提示資訊. 如果返回 -1, 表示找不到原始檔, 或url.properties配置錯誤; 如果返回 0, * 則表示操作成功; 返回1, 則表示轉換失敗 */ private static int office2PDF(OfficeToPDFInfo officeToPDFInfo) { String sourceFile=officeToPDFInfo.sourceUrl; String destFile=officeToPDFInfo.destUrl; String OpenOffice_HOME=officeToPDFInfo.openOfficeHOME; try { File inputFile = new File(sourceFile); if (!inputFile.exists()) { return -1;// 找不到原始檔, 則返回-1 } // 如果目標路徑不存在, 則新建該路徑 File outputFile = new File(destFile); if (!outputFile.getParentFile().exists()) { outputFile.getParentFile().mkdirs(); } //= "D:\\Program Files\\OpenOffice.org 3";//這裡是OpenOffice的安裝目錄, 在我的專案中,為了便於拓展介面,沒有直接寫成這個樣子,但是這樣是絕對沒問題的 // 如果從檔案中讀取的URL地址最後一個字元不是 '\',則新增'\' if (OpenOffice_HOME.charAt(OpenOffice_HOME.length() - 1) != '\\') { OpenOffice_HOME += "\\"; } // 啟動OpenOffice的服務 String command = OpenOffice_HOME + "program\\soffice.exe -headless -accept=\"socket,host=127.0.0.1,port=8100;urp;StarOffice.ServiceManager\" -nofirststartwizard"; Process pro = Runtime.getRuntime().exec(command); // connect to an OpenOffice.org instance running on port 8100 OpenOfficeConnection connection = new SocketOpenOfficeConnection( "127.0.0.1", 8100); connection.connect(); // convert DocumentConverter converter = new OpenOfficeDocumentConverter(connection); //DocumentConverter converter = new StreamOpenOfficeDocumentConverter(connection); converter.convert(inputFile, outputFile); // close the connection connection.disconnect(); // 關閉OpenOffice服務的程序 pro.destroy(); return 0; } catch (FileNotFoundException e) { e.printStackTrace(); return -1; } catch (ConnectException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return 1; }
public class OfficeToPDFInfo {
/**
* 轉換的來源路徑
*/
public String sourceUrl;
/**
* 轉換後的本地路徑
*/
public String destUrl;
/**
* 這裡是OpenOffice的安裝目錄
*/
public String openOfficeHOME;
/**
* 單個任務執行的超時時間;
*/
public Integer task_execution_timeout;
}
3.轉換佇列
為了更加合理的利用資源,一個轉換佇列是必不可少的,這裡用一個執行緒list作為執行緒佇列,用另外一個執行緒來管理這個佇列;
用一個map來記錄相關的狀態;
轉換的自定義Properties,其中轉換的並行度最好和其伺服器的cpu虛擬核心數量相同:
public class OfficeToPDFProperty { /** * 轉換後的本地儲存資料夾 */ public String destFolder; /** * 這裡是OpenOffice的安裝目錄 */ public String openOfficeHome=""; /** * 單個任務執行的超時時間; */ public Integer task_execution_timeout=60000; /** * 同時轉換的最大併發數量; */ public int maxThreadCount=0; /** * 轉換完成的狀態保持時間 */ public int convertionStatusKeepTime=0; /** * 轉換(包括失敗),最多convertionTryCount次; */ public int convertionTryCount=0; /** * 當前pdf轉換狀態的最大儲存數量,超過此數量後將會拋棄時間最久的狀態; */ public int convertionStatusMaxCount=1000; /** * 被轉換的office文件的檔案最大大小,超過此大小後,將不會轉換; * 預設100M,單位位元組; */ public int fileMaxSize=104857600; }
轉換的執行緒管理:
public class OfficeToPDFService {
/**
* 將執行前的執行緒加入執行緒池,執行開始後移出執行緒池;執行緒池中儲存的是當前等待轉換的執行緒佇列
*/
private static List<Thread> office2PDFThreadPool=new LinkedList<Thread>();
/**
* 當前正在執行的轉換執行緒的數量
*/
private static int convertionCount=0;
private static Thread initConvertionThread=null;
/**
* 初始化執行緒池的執行,每2秒鐘,檢查一次轉換的執行緒池
*/
private static synchronized void initConvertionThreadPool(){
OfficeToPDFProperty officeToPDFProperty=null;
try {
officeToPDFProperty = OfficeToPDFPropertyService.getOfficeToPDFProperty();
} catch (InstantiationException | IllegalAccessException | IOException e1) {
e1.printStackTrace();
}
final int maxCount=officeToPDFProperty.maxThreadCount;
if(initConvertionThread==null){
initConvertionThread=new Thread(new Runnable() {
@Override
public void run() {
while(true){
int i=0;
if(getConvertionCount()<maxCount&&getThreadWaitCount()>i){
Thread converThread=getOffice2PDFThreadByThreadPool(i);
if(!converThread.isAlive()){
converThread.start();
continue;
}
i++;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
initConvertionThread.start();
}
}
/**
* 將狀態為非結束狀態的轉換的檔案加入轉換池中
* 只轉換OfficeConverionStatus.NoStart的檔案
* @param path
* @param desPath
*/
public static void addOfficeFileToConvertionThreadPool(final String path,final String desPath) {
initConvertionThreadPool();
final String originFileName=FileUtils.getFileNameByPath(path);
OfficeConverionStatus status=MyConstants.getConvertionType(originFileName);
if(status!=OfficeConverionStatus.NoStart)
return;
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Ready);
final Thread thread=new Thread(new Runnable() {
@Override
public void run() {
decrementConvertionCount();
try {
incrementConvertionCount();
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Converting);
OfficeToPDFProperty officeToPDFProperty=OfficeToPDFPropertyService.getOfficeToPDFProperty();
OfficeToPDFInfo info=new OfficeToPDFInfo();
info.destUrl=desPath;
info.sourceUrl=path;
info.openOfficeHOME=officeToPDFProperty.openOfficeHome;
info.task_execution_timeout=officeToPDFProperty.task_execution_timeout;
int result=1;
int convertionTryCount=officeToPDFProperty.convertionTryCount;
while(result!=0&&convertionTryCount-->0){
try {
result=office2PDF(info);
} catch (Exception e) {
e.printStackTrace();
result=1;
}
}//end while
if(result==-1){
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.NoFile);
}else if(result==1)
{
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Faild);
}else if(result==0){
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Success);
}
} catch (InstantiationException e) {
e.printStackTrace();
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Faild);
} catch (IllegalAccessException e) {
e.printStackTrace();
MyConstants.putConvertionStatus(originFileName, OfficeConverionStatus.Faild);
} catch (IOException e) {
e.printStackTrace();
MyConstants.putConvertionStatus(originFileName,OfficeConverionStatus.Faild);
}finally{
removeThreadFromOffice2PDFThreadPool(Thread.currentThread());
}
}
});
addThreadTOOffice2PDFThreadPool(thread);
}
/**
* 得到當前等待的執行緒的數量
* @return
*/
public static synchronized int getThreadWaitCount(){
return office2PDFThreadPool.size();
}
public static synchronized Thread getOffice2PDFThreadByThreadPool(int index) {
return office2PDFThreadPool.get(index);
}
public static synchronized void addThreadTOOffice2PDFThreadPool(Thread office2pdfThread) {
office2PDFThreadPool.add(office2pdfThread);
}
private static synchronized void removeThreadFromOffice2PDFThreadPool(Thread office2pdfThread) {
office2PDFThreadPool.remove(office2pdfThread);
}
private synchronized static int getConvertionCount() {
return convertionCount;
}
private synchronized static void incrementConvertionCount() {
convertionCount = convertionCount+1;
}
private synchronized static void decrementConvertionCount(){
convertionCount = convertionCount-1;
}
4.轉換狀態的儲存:
public class MyConstants {
private static String[] officeFile
=new String[]{"doc","docx","ppt","pptx","xls","xlsx"};
public static String[] getOfficeFileExtentionNames(){
return officeFile;
}
/**
* 判斷是否是office檔案
* @param path
* @return
*/
public static boolean isOfficeFile(String path){
if(StringJudgeUtils.isEmpty(path))
return false;
for(int i=0;i<officeFile.length;i++){
String nameString=FileUtils.getFileExtension(path);
if(nameString.equalsIgnoreCase(officeFile[i])){
return true;
}
}
return false;
}
/**
*用來儲存轉換的狀態
**/
private static Map<String, OfficeConverionStatus> convertionTypes=new HashMap<String, OfficeConverionStatus>();
/**
*
* @param originFileName 轉換之前的檔名稱
* @return 當前轉換的狀態
*/
public static synchronized OfficeConverionStatus getConvertionType(String originFileName){
OfficeConverionStatus converionStatus=convertionTypes.get(originFileName);
if(converionStatus==null)
converionStatus=OfficeConverionStatus.NoStart;
return converionStatus;
}
/**
* 加入新的轉換狀態的時候,會自動移出舊的狀態;
* @param originFileName
* @param converionStatus 當前轉換的狀態
*/
public static synchronized void putConvertionStatus(String originFileName,OfficeConverionStatus converionStatus){
convertionTypes.put(originFileName,converionStatus);
putConvertionTime(originFileName, System.currentTimeMillis());
}
/**
* 將指定檔名的狀態移出
* @param originFileName
*/
private static synchronized void removeConvertionStatus(String originFileName){
convertionTypes.remove(originFileName);
}
/**
* 儲存執行緒轉換的結束時間和執行緒轉換的狀態相對應,轉換結束後24小時內沒有訪問結果的將會被清除;
*/
private static Map<String, Long> convertionTimeMap=new HashMap<String, Long>();
/**
*
* @param originFileName 轉換之前的檔名稱
* @return 當前轉換的狀態
*/
public static synchronized Long getConvertionTime(String originFileName){
Long converionTime=convertionTimeMap.get(originFileName);
if(converionTime==null)
converionTime=new Date(2000,1,1).getTime();
return converionTime;
}
public static synchronized int getConvertionTypesSize(){
return convertionTypes.size();
}
/**
* 加入新的轉換狀態的時候,會自動移出舊的狀態;
* 數量超過convertionStatusMaxCount會移出更多老舊狀態
* @param originFileName
* @param cTime
*/
private static synchronized void putConvertionTime(String originFileName,Long cTime){
convertionTimeMap.put(originFileName,cTime);
Set<String> keySet=convertionTimeMap.keySet();
OfficeToPDFProperty officeToPDFProperty;
try {
officeToPDFProperty = OfficeToPDFPropertyService.getOfficeToPDFProperty();
int keepTimeLong=officeToPDFProperty.convertionStatusKeepTime;
int convertionStatusMaxCount=officeToPDFProperty.convertionStatusMaxCount;
List<String> removeKeyStrings=new ArrayList<String>();
do{
for(String key:keySet){
Long timeLong=convertionTimeMap.get(key);
if(System.currentTimeMillis()-timeLong>keepTimeLong){
removeKeyStrings.add(key);
}
}
for(String key:removeKeyStrings){
convertionTimeMap.remove(key);
removeConvertionStatus(key);
}
keepTimeLong=(int)(keepTimeLong*0.95);
}while(getConvertionTypesSize()>convertionStatusMaxCount);
} catch (InstantiationException | IllegalAccessException | IOException e) {
e.printStackTrace();
}
}
/*public static synchronized void removeConvertionTime(String originFileName){
convertionTime.remove(originFileName);
}*/
}
5.小結
注意執行緒之間的加鎖互斥,沒有貼出的程式碼無關核心思想,因為時間原因,以後以機會可以做成模組,打包為jar形式,不過openoffice轉pdf的時候,
遇到部分ppt文件可能會出現轉換失敗的情況;