您現在的位置是:首頁 > 運動

服務端WORD檔案模板書籤替換、轉換檔案型別的另類實現(原始碼)

由 空中智囊 發表于 運動2022-01-24
簡介jar: 即永中為開發者提供的SDK,可以將jar匯入到工程中3、編寫WORD檔案處理服務元件處理word檔案的程式碼片段,詳細程式碼請在文後下載原始碼查閱** * 將word檔案轉換為對應格式的檔案的位元組陣列 * @param type

為什麼word裡替換不成功

文章最後提供原始碼下載地址

市面上處理文字的的辦公軟體有很多,包括WPS、MSOffice、永中OFFICE,當然還有開源的openoffice、liboffice等。我們在專案開發過程中經常會遇到預覽word檔案,資料庫中資料自動填充word模板等需求。現在能夠滿足以上需求的技術有很多,服務端可透過POI\aspose等處理,也可透過客戶端呼叫OFFICE元件處理,本人曾經在這方便做了很多測試,最終發現相容性最好的、介面對JAVA程式設計師最友好的就屬永中OFFICE,因為它基本就是JAVA實現的,使用起來非常方便。

我的測試環境使用的是永中2016版本,它執行要求JRE1。6,且我發現它應該是對JRE進行過重構,按永中SDK要求編寫程式碼透過自ORACAL官網下載的jdk1。6編譯後執行是失敗的,現在都2021年了,我們的專案絕大多數都JDK1。8以上版本了,那麼怎麼讓SDK相容我們的專案呢?怎麼實現標題中提到的兩個需求呢?下面我說說我的處理方法吧:

1、下載永中軟體並安裝(官網下載即可)

2、安裝後開啟安裝路徑可以看到如下圖

服務端WORD檔案模板書籤替換、轉換檔案型別的另類實現(原始碼)

永中軟體安裝目錄

JRE:即永中軟體的執行環境

Yozo_Office。jar: 即永中為開發者提供的SDK,可以將jar匯入到工程中

3、編寫WORD檔案處理服務元件

處理word檔案的程式碼片段,詳細程式碼請在文後下載原始碼查閱 /** * 將word檔案轉換為對應格式的檔案的位元組陣列 * @param type 將word檔案轉換成的檔案格式 pdf、html\ofd\txt\xml * @return * @throws IOException */ public byte[] convertFile(String type) throws IOException { int typePdf = FileConstants。TYPE_PDF; if(“html”。equals(type。toLowerCase())) {//此功能轉換後亂碼,後期可採用 this。workbook。saveAs(“D:/2。html”); 方式儲存html後,將位元組返回 typePdf= FileConstants。FILETYPE_HTML; }else if(“ofd”。equals(type。toLowerCase())) { typePdf= FileConstants。TYPE_OFD; // 這個是不成功的,應該是版本太低 }else if(“txt”。equals(type。toLowerCase())) { typePdf = FileConstants。TYPE_TXT; }else if(“xml”。equals(type。toLowerCase())) { typePdf = FileConstants。FILETYPE_XML; }else if(“doc”。equals(type。toLowerCase())||“xls”。equals(type。toLowerCase())||“ppt”。equals(type。toLowerCase())) { typePdf = FileConstants。TYPE_MS; }else if(“docx”。equals(type。toLowerCase())||“xlsx”。equals(type。toLowerCase())||“pptx”。equals(type。toLowerCase())) { typePdf = FileConstants。TYPE_MS_EX; } return this。workbooks。getWorkbookAsByteArray(workbook, typePdf); }/** * 替換word模板中的書籤 * @param jsonObject 資料內容 {“bookmarkname”:”test“} */ public void replaceBookMark(JSONObject jsonObject) { BookMarks bookMarks = this。document。getBookMarks(); BookMark[] allBookmarks = bookMarks。getAllBookmarks(); for(BookMark bookMark:allBookmarks){ String name = bookMark。getName(); TextRange range = bookMark。getRange(); //if(name!=null)name=name。replace(“PO_”,“”); String value = “”; Object o = jsonObject。get(name); if(o!=null){ value=jsonObject。get(name)。toString(); } try { range。insertText(value); }catch (Exception e){ range。insertText(value); } } }/** * 匯出資料成excel檔案 * @param jsonObject 資料內容 {“bookmarkname”:”test“} */public byte[] exportData2File(JSONArray taskArray,int allrow) {}

4、(重點)解決word檔案處理元件與我們的專案檔案互動問題

本人透過SOCKET即時通訊服務解決資料互動問題

/** * 檔案傳輸Server端
* 功能說明: * @Author 空中智囊 * @Date 2016年09月01日 * @version 1。0 */public class SocketService extends ServerSocket { private static final int SERVER_PORT = 8899; // 服務端埠 private WordUtil wordUtil=null; public SocketService() throws Exception { super(SERVER_PORT); this。wordUtil=new WordUtil(); } /** * 使用執行緒處理每個客戶端傳輸的檔案 * @throws Exception */ public void load() throws Exception { System。out。println(“服務端啟動,監聽埠為:”+SERVER_PORT); while (true) { // server嘗試接收其他Socket的連線請求,server的accept方法是阻塞式的 Socket socket = this。accept(); socket。setSoTimeout(1200000); /** * 我們的服務端處理客戶端的連線請求是同步進行的, 每次接收到來自客戶端的連線請求後, * 都要先跟當前的客戶端通訊完之後才能再處理下一個連線請求。 這在併發比較多的情況下會嚴重影響程式的效能, * 為此,我們可以把它改為如下這種非同步處理與客戶端通訊的方式 */ // 每接收到一個Socket就建立一個新的執行緒來處理它 new Thread(new Task(socket,wordUtil))。start(); } } /** * 入口 * @param args */ public static void main(String[] args) { try { SocketService server = new SocketService(); // 啟動服務端 server。load(); } catch (Exception e) { e。printStackTrace(); } }}/** * 處理客戶端傳輸過來的檔案執行緒類 */public class Task implements Runnable { @Override public void run() { System。out。println(“===客戶端連線成功=====”); System。out。println(“****************************************************************”); SimpleDateFormat format=new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”); /** * 轉換要求的格式 */ try { /********************************讀取檔案資訊********************************/ dis = new DataInputStream(socket。getInputStream()); // 檔名和長度 String fileName = dis。readUTF();//1、檔名字 long fileLength = dis。readLong();//2、長度 String toext = dis。readUTF();//3、副檔名 String taskType=dis。readUTF();//4、檔案操作型別 System。out。println(“針對檔案的操作型別=====”+taskType); String valueObject=dis。readUTF();//5、替換書籤的值 System。out。println(format。format(new Date())+“:開始接收檔案”); ByteArrayOutputStream bos = new ByteArrayOutputStream((int)fileLength); byte[] bytes = new byte[1024]; int length = 0; while((length = dis。read(bytes, 0, bytes。length)) != -1) { bos。write(bytes, 0, length); } byte[] filebytes = bos。toByteArray(); System。out。println(“原始檔案大小=====”+fileLength+“,實際接收檔案大小=”+filebytes。length); /********************************讀取檔案資訊結束********************************/ dos = new DataOutputStream(socket。getOutputStream()); /********************************校驗檔案資訊********************************/ boolean process=true; if(fileLength>0){ }else{ dos。writeUTF(“error”); dos。flush(); dos。writeUTF(“檔案沒有任何內容,請重新傳送”); dos。flush(); process=false; } if(filebytes。length!=fileLength){ dos。writeUTF(“error”); dos。flush(); dos。writeUTF(“接受檔案與實際檔案大小不符合,請重新傳送檔案”); dos。flush(); process=false; } /********************************校驗檔案資訊結束********************************/ /********************************處理檔案********************************/ if(process){ byte[] fileBytes=null; this。wordUtil。openFile(filebytes,fileName);//開啟院檔案 //workbook =workbooks。createWorkbookFromByteArray(filebytes,fileName); String lowerExt = toext。toLowerCase(); if(“convertFile”。equals(taskType)){ System。out。println(“開始將檔案[”+fileName+“]轉換成====”+lowerExt); fileBytes=this。wordUtil。convertFile(lowerExt); System。out。println(format。format(new Date())+“:轉換”+toext+“完成”); }else if(“replaceBookMark”。equals(taskType)){ System。out。println(“開始將檔案[”+fileName+“]書籤進行替換====”); JSONObject jsonObject = JSONObject。fromObject(valueObject); this。wordUtil。replaceBookMark(jsonObject); fileBytes = this。wordUtil。convertFile(lowerExt); System。out。println(“===============替換書籤完成============”); }else if(“exportTask”。equals(taskType)) {//處理業務資料 匯出任務資料 System。out。println(“開始匯出業務資料====”+valueObject); ServiceUtil serviceUtil = new ServiceUtil(this。wordUtil); JSONObject jsonObject = JSONObject。fromObject(valueObject); fileBytes = serviceUtil。exportData2File(jsonObject。getJSONArray(“datalist”), jsonObject。getInt(“size”)); System。out。println(“===============匯出業務資料完成============”); } /********************************處理檔案結束********************************/ if(fileBytes==null){ dos。writeUTF(“error”); dos。flush(); dos。writeUTF(“處理檔案過程中錯誤”); dos。flush(); process=false; } /********************************返回處理過的檔案********************************/ if(process){ dos。writeUTF(“info”);//檔案處理完成,將資訊返回到客戶端 dos。flush(); int fileBytelength = fileBytes。length;//轉換後的檔案長度 System。out。println(format。format(new Date())+“:======== 服務端開始傳送檔案流,檔案大小(”+getFormatFileSize(fileBytelength)+“) ========”); dos。writeLong(fileBytelength); dos。flush(); dos。write(fileBytes, 0, fileBytelength);//將檔案一起寫入到輸出流傳送 dos。flush(); System。out。println(format。format(new Date())+“:======== 傳送檔案流成功 ========”); } /********************************返回處理過的檔案完成********************************/ } } catch (Exception e) { String error = e。toString(); System。out。println(“error===================”+error); StackTraceElement[] stackTrace = e。getStackTrace(); for(StackTraceElement s:stackTrace){ int lineNumber = s。getLineNumber(); String methodName = s。getMethodName(); String className = s。getClassName(); String filename = s。getFileName(); System。out。print(“err:”+filename+“ ”+className+“ ”+methodName+“ ”+lineNumber); System。out。println(“”); } try { dos。writeUTF(“error”); dos。flush(); dos。writeUTF(“處理檔案過程中錯誤==”+e。toString()); dos。flush(); }catch (Exception ex){ String exrror =ex。toString(); System。out。println(“返回資料處理錯誤資訊===================”+exrror); } }finally { System。out。println(“關閉資源”); try { if(wordUtil!=null)wordUtil。close(); socket。close(); } catch (Exception e) { String error = e。toString(); System。out。println(error); e。printStackTrace(); } System。out。println(“****************************************************************”); }}/** * 檔案傳輸Clinet端
* 功能說明: * @Author 空中智囊 * @Date 2016年09月01日 * @version 1。0 */public class SocketClient extends Socket { public static final Logger LOGGER = LoggerFactory。getLogger(SocketClient。class); private static final String SERVER_IP = “127。0。0。1”; // word檔案元件處理服務IP地址 private static final int SERVER_PORT = 8899; // word檔案元件處理服務埠 private int soTimeout = 60000; // 服務連結超時時間 60s private Socket client = this; private FileInputStream fis; private DataOutputStream dos; private DataInputStream dis; private FileOutputStream fos; public SocketClient(String listenip, int listenport) throws Exception { super(listenip, listenport); this。setSoTimeout(this。soTimeout); LOGGER。info(“Cliect[port:” + this。client。getLocalPort() + “] 成功連線服務端”); } public SocketClient() throws Exception { super(SERVER_IP, SERVER_PORT); this。setSoTimeout(this。soTimeout); LOGGER。info(“Cliect[port:” + this。client。getLocalPort() + “] 成功連線服務端”); } public SocketClient(String listenip, int listenport, int soTimeout) throws Exception { super(listenip, listenport); this。setSoTimeout(soTimeout); LOGGER。info(“Cliect[port:” + this。client。getLocalPort() + “] 成功連線服務端”); } /** * 處理word檔案 * @param srcRealPath 模板word檔案路徑絕對地址 * @param descRealPath 處理後的檔案存放地址絕對路徑 * @param taskType 處理檔案的型別 convertFile/replaceBookMark/exportTask * @param jsonObject 傳給服務端的資料物件,這個引數可根據服務端需求進行調整 * @return 處理結果 */public JSONObject processOffice(String srcRealPath, String descRealPath, String taskType, JSONObject jsonObject) { JSONObject rtnObject = new JSONObject(); String code = “200”; String message = “”; try { File file = new File(srcRealPath); if (!file。exists() || !file。canWrite()) { code = “200”; message = “檔案不存在,或已被佔用”; rtnObject。element(“code”, code); rtnObject。element(“message”, message); JSONObject var41 = rtnObject; return var41; } LOGGER。info(srcRealPath + “===>” + descRealPath); if (file。exists() && file。canWrite()) { String filename = file。getName(); this。fis = new FileInputStream(file); this。dos = new DataOutputStream(this。client。getOutputStream()); this。dos。writeUTF(filename);//檔名字 this。dos。flush(); this。dos。writeLong(file。length());//檔案長度 this。dos。flush(); String ext = descRealPath。substring(descRealPath。lastIndexOf(“。”) + 1, descRealPath。length()); this。dos。writeUTF(ext);//原始檔字尾名字 this。dos。flush(); this。dos。writeUTF(taskType);//任務型別 this。dos。flush(); if (YOZOOfficeUtil。PROCESS_TYPE_CONVERTFILE。equals(taskType)) { this。dos。writeUTF(jsonObject。toString()); this。dos。flush(); } LOGGER。info(“======== 開始向服務端傳送原始檔” + srcRealPath + “ ========”); byte[] bytes = new byte[1024]; long progress = 0L; int length; while((length = this。fis。read(bytes, 0, bytes。length)) != -1) { this。dos。write(bytes, 0, length); this。dos。flush(); progress += (long)length; LOGGER。info(“| ” + 100L * progress / file。length() + “% |”); } LOGGER。info(“======== 檔案傳輸成功 (” + file。length() / 1048576L + “)M========”); this。client。shutdownOutput(); LOGGER。info(“======== 開始轉換” + ext + “ ========”); InputStream inputStream = this。client。getInputStream(); this。dis = new DataInputStream(inputStream); String result = this。dis。readUTF(); if (“error”。equals(result)) { String reason = this。dis。readUTF(); LOGGER。info(reason); code = “500”; message = reason; } else if (“info”。equals(result)) { long l = this。dis。readLong(); LOGGER。info(“======== 轉換” + ext + “完成,檔案大小(” + l / 1048576L + “)M ========”); LOGGER。info(“======== 開始接受” + ext + “ ========”); File newFile = new File(descRealPath); if (newFile。exists()) { newFile。delete(); } this。fos = new FileOutputStream(newFile); progress = 0L; bytes = new byte[1048576]; while((length = this。dis。read(bytes, 0, bytes。length)) != -1) { this。fos。write(bytes, 0, length); this。fos。flush(); } LOGGER。info(“======== 接受” + ext + “檔案成功========”); this。dis。close(); } else { code = “500”; message = “連結被強制關閉。。。。”; } } else { code = “404”; message = “檔案不存在,或已被佔用:” + srcRealPath; } } catch (Exception e) { code = “500”; message = “客戶端報錯:” + e。toString(); LOGGER。error(“異常:”,e); } finally { if (this。fis != null) { try { this。fis。close(); } catch (Exception var38) { ; } } if (this。fos != null) { try { this。fos。close(); } catch (Exception var37) { ; } } try { this。client。close(); } catch (Exception var36) { ; } } rtnObject。element(“code”, code); rtnObject。element(“message”, message); return rtnObject; } public static void main(String[] args) { try { SocketClient socketClient = new SocketClient(); // 將文件轉換成pdf檔案 socketClient。processOffice(“D:/2。doc”,“D:/2。pdf”,YOZOOfficeUtil。PROCESS_TYPE_CONVERTFILE,null); // 將文件轉換成pdf檔案 JSONObject dataObject = new JSONObject(); dataObject。element(“bookmarkname”,“這個是測試呢日哦那個”); socketClient。processOffice(“D:/2。doc”,“D:/2。pdf”,YOZOOfficeUtil。PROCESS_TYPE_REPLACEBOOKMARK,dataObject); } catch (Exception e) { LOGGER。error(“異常:”,e); } }}

5、啟動word檔案處理元件服務端

服務端WORD檔案模板書籤替換、轉換檔案型別的另類實現(原始碼)

元件啟動指令碼

nohup 。/ofdServer。sh &

6、呼叫服務端對word檔案處理

public static void main(String[] args) { try { SocketClient socketClient = new SocketClient(); // 將文件轉換成pdf檔案 socketClient。processOffice(“D:/2。doc”,“D:/2。pdf”,YOZOOfficeUtil。PROCESS_TYPE_CONVERTFILE,null); // 替換模板中的書籤值,word中插入書籤自行百度 JSONObject dataObject = new JSONObject(); dataObject。element(“bookmarkname”,“這個是測試呢日哦那個”); socketClient。processOffice(“D:/2。doc”,“D:/3。doc”,YOZOOfficeUtil。PROCESS_TYPE_REPLACEBOOKMARK,dataObject); } catch (Exception e) { LOGGER。error(“異常:”,e); } }

7、資源下載

word檔案處理元件服務端(開箱即用):

連結: https://pan。baidu。com/s/1_ZgjoX_nuv3a7_SKkJ_D7w 提取碼: hn2r

服務端WORD檔案模板書籤替換、轉換檔案型別的另類實現(原始碼)

服務端資源內容

將檔案複製到linux伺服器,並解壓,執行 。/ofdServer。sh ,輸出:服務端啟動,監聽埠為:8899,即執行成功

word檔案處理元件客戶端(開箱即用processOffice):

連結: https://pan。baidu。com/s/1mtabGY87RuAGGkwKrBIvfQ 提取碼: mqxf

服務端WORD檔案模板書籤替換、轉換檔案型別的另類實現(原始碼)

客戶端資原始檔內容

將原始檔複製到專案指定包名,執行SocketClient。java中的main方法,可檢視執行結果。

最重要的一點:伺服器要安裝永中OFFICE客戶端

推薦文章