onlyoffice歷史版本功能實現,版本恢復功能,編輯器功能實現 springboot+vue2

文章目錄

  • oonlyoffice歷史版本功能實現 (編輯器功能實現)springboot+vue2
  • 前提 需要注意把這個 (改成自己服務器的ip或者域名) 改成 自己服務器的域名或者地址
  • 1. onloyoffice 服務器部署 搜索其他文章
  • 2. 前段代碼 vue 2
    • 2.1 需要注意把這個 (改成自己服務器的ip或者域名) 改成 自己服務器的域名或者地址
    • 2.2. openedit getHistoryData 這兩個 是調用后端的 接口 改成自己項目的寫法 都是 post 請求
    • 2.3 下面是整個頁面代碼 需要 別的頁面進入下面這個頁面 入參是 文件id
    • 舉例
    • 進入editer.vue 頁面的 頁面代碼 row.id 是文件id 也就是 onloyoffice 文件id
      • 文件名字 editer.vue
  • 3. 后端java 代碼
    • 3.1 controller 代碼
    • 3.2 service 代碼
    • 3.3 serviceImpl 代碼
    • 3.3公共方法代碼
  • 4.效果圖
  • 5.可以參考此文章優化代碼

oonlyoffice歷史版本功能實現 (編輯器功能實現)springboot+vue2

前提 需要注意把這個 (改成自己服務器的ip或者域名) 改成 自己服務器的域名或者地址

1. onloyoffice 服務器部署 搜索其他文章

2. 前段代碼 vue 2

2.1 需要注意把這個 (改成自己服務器的ip或者域名) 改成 自己服務器的域名或者地址

2.2. openedit getHistoryData 這兩個 是調用后端的 接口 改成自己項目的寫法 都是 post 請求

2.3 下面是整個頁面代碼 需要 別的頁面進入下面這個頁面 入參是 文件id

舉例

進入editer.vue 頁面的 頁面代碼 row.id 是文件id 也就是 onloyoffice 文件id

//row.id 是文件id 也就是 onloyoffice 文件id
//  /only/editer/   這是頁面路由的地址需要在路由里面配置
//頁面
openFile(row) {window.open('#/only/editer/' + row.id,'_blank');},

文件名字 editer.vue

<template><div><div id="onlyoffice-container" ref="editorContainer"></div></div>
</template><script>export default {name: 'OnlyOfficeEditor',props: {isEdit: {type: Boolean,default: true}},data() {return {docEditor: null,currentVersion: null,fileToken: null,historyData: null,historys: [],historyList: []};},mounted() {this.loadScript().then(() => {this.initEditor();});},methods: {async loadScript() {return new Promise((resolve, reject) => {const scriptId = "onlyoffice-api-script";if (!document.getElementById(scriptId)) {const script = document.createElement('script');script.id = scriptId;script.src = "https://(改成自己服務器的ip或者域名)/ds-vpath/web-apps/apps/api/documents/api.js"; // 替換為你的 ONLYOFFICE 服務器地址script.type = "text/javascript";script.onload = resolve;script.onerror = reject;document.head.appendChild(script);} else {resolve();}});},initEditor() {if (this.docEditor) {this.docEditor.destroyEditor();this.docEditor = null;}openedit({"fileId": this.$route.params.id}).then(res  => {if (res.code  === 200) {//這是主編輯器獲取的數據  config let config = res.data.openedit;//處理后端返回的歷史版本數據const historyList = res.data.historyList;const fileToken = res.data.fileToken;const currentVersion  = historyList[0].version; // 假設最新版本為第一個元素// 添加版本歷史事件處理config.events  = {//這里拿到的是 左側版本的 數據 比如 版本1 版本2onRequestHistory: () => {this.docEditor.refreshHistory({currentVersion: currentVersion,token: fileToken,history: historyList});},//這里是 左側關閉歷史記錄 按鈕調用這個方法onRequestHistoryClose: () => {document.location.reload();},//這是左側 點擊版本  對應的版本內容onRequestHistoryData: (event) => {const version = event.datagetHistoryData({"fileId": this.$route.params.id,"version": version}).then(res  => {const historyData = res.data.historyData;this.docEditor.setHistoryData(historyData);}).catch(err => {console.log(err);});},//版本恢復功能onRequestRestore: (event) => {//待實現}};this.docEditor  = new window.DocsAPI.DocEditor(this.$refs.editorContainer.id,  config);}}).catch(err => {console.log(err);});}},beforeDestroy() {if (this.docEditor)  {this.docEditor.destroyEditor();this.docEditor  = null;}if (this.DocsAPIInterval) {clearInterval(this.DocsAPIInterval);}},beforeRouteLeave(to, from, next) {if (this.docEditor)  {this.docEditor.destroyEditor();this.docEditor  = null;}if (this.DocsAPIInterval) {clearInterval(this.DocsAPIInterval);}next();}
};
</script><style>
iframe {border: none;width: 100%;height: 100vh;
}
</style>

3. 后端java 代碼

3.1 controller 代碼

    @PostMapping("/openedit")public RestResultDTO openedit(HttpServletRequest request, @RequestBody OnlyofficeRequestDTO params) {try {if (CommonFunctions.isEmpty(params.getFileId())) {throw new BusinessServiceException("非空校驗失敗");}Map<String, Object> resultMap  = onlyofficeService.openedit(params);return RestResultDTO.success(resultMap);} catch (Exception e) {LOGGER.error("openedit 方法發生異常: ", e);return RestResultDTO.error(ResponseCodeDTO.INTERNAL_SERVER_ERROR, e.getMessage());}}
@PostMapping("/getHistoryData")public RestResultDTO getHistoryData(HttpServletRequest request, @RequestBody OnlyofficeRequestDTO params) {try {if (CommonFunctions.isEmpty(params.getFileId()) || CommonFunctions.isEmpty(params.getVersion())) {throw new BusinessServiceException("非空校驗失敗");}Map<String, Object> resultMap  = onlyofficeService.getHistoryData(params);return RestResultDTO.success(resultMap);} catch (Exception e) {LOGGER.error("openedit 方法發生異常: ", e);return RestResultDTO.error(ResponseCodeDTO.INTERNAL_SERVER_ERROR, e.getMessage());}}

3.2 service 代碼

    Map<String, Object> openedit(OnlyofficeRequestDTO params);
 //獲取文件的初始化配置Map<String, Object> getHistoryData(OnlyofficeRequestDTO params);

3.3 serviceImpl 代碼

       @Overridepublic Map<String, Object> openedit(OnlyofficeRequestDTO params) {String fileId = params.getFileId();String permissionType = "";JSONObject onlyOfficeConfig = null;try {String result = HttpUtils.executeRequestOnlyoffice(HttpUtils.O_SHAREFILE_URL + fileId + "/openedit", null, null, "UTF-8", "get");JSONObject resJsonObject = JSONObject.parseObject(result);if (CollectionUtils.isEmpty(resJsonObject)) {throw new BusinessServiceException("獲取配置文件異常");} else if (resJsonObject.getInteger("statusCode") == 200) {onlyOfficeConfig = resJsonObject.getJSONObject("response");} else if (resJsonObject.getInteger("statusCode") == 500) {throw new BusinessServiceException(resJsonObject.getJSONObject("error").getString("message"));} else {throw new BusinessServiceException("獲取配置文件異常");}//只讀if ("4".equals(permissionType)) {onlyOfficeConfig.getJSONObject("editorConfig").put("mode", "view");}} catch (Exception e) {LOGGER.error("解析JSON響應失敗", e);throw new BusinessServiceException("", e);}JSONArray responseArray = null;try {String result = HttpUtils.executeRequestOnlyoffice(HttpUtils.O_FILES_URL  + "/edit-history?fileId=" + fileId, null, null, "UTF-8", "get");// 嘗試解析為 JSONArrayJSONArray resJsonArray = JSONArray.parseArray(result);if (CollectionUtils.isEmpty(resJsonArray))  {throw new BusinessServiceException("獲取配置文件異常");}responseArray = resJsonArray;} catch (Exception e) {LOGGER.error(" 解析JSON響應失敗", e);throw new BusinessServiceException("", e);}// 使用 Map 封裝多個 JSON 對象Map<String, Object> resultMap = new HashMap<>();resultMap.put("openedit", onlyOfficeConfig);resultMap.put("historyList", responseArray);try {resultMap.put("fileToken",HttpUtils.renovateAuthorizationToken());} catch (Exception e) {LOGGER.error(" 獲取token失敗", e);throw new BusinessServiceException("", e);}return resultMap;}
    @Overridepublic Map<String, Object> getHistoryData(OnlyofficeRequestDTO params) {String fileId = params.getFileId();String version = params.getVersion();JSONObject responseArray = null;try {String result = HttpUtils.executeRequestOnlyoffice(HttpUtils.O_FILES_URL + "/edit-diff-url?fileId=" + fileId + "&version=" + version, null, null, "UTF-8", "get");responseArray = JSONObject.parseObject(result);if (CollectionUtils.isEmpty(responseArray))  {throw new BusinessServiceException("獲取配置文件異常");}} catch (Exception e) {LOGGER.error("解析JSON響應失敗", e);throw new BusinessServiceException("", e);}// 使用 Map 封裝多個 JSON 對象Map<String, Object> resultMap = new HashMap<>();resultMap.put("historyData", responseArray);return resultMap;}

3.3公共方法代碼

  /*** 根據請求類型執行POST或PUT請求*/public static String executeRequestOnlyoffice(String url, Map<String, Object> params, Map<String, String> headers, String encoding, String requestType) throws Exception {Map<String, String> headersCover = new HashMap<>();String authorizationToken = getAuthorizationToken();//覆蓋默認請求頭headersCover.put("Authorization", authorizationToken);headersCover.put("Accept", "application/json");headersCover.put("Content-Type", "application/json");if (headers != null) {for (Map.Entry<String, String> entry : headers.entrySet()) {headersCover.put(entry.getKey(), entry.getValue());}}switch (requestType.toLowerCase()) {case "get":return executeGetRequestCommon(url, params, headersCover, encoding);case "post":return executePostRequestCommon(url, params, headersCover, encoding);case "put":return executePutRequestCommon(url, params, headersCover, encoding);case "delete":return executeDeleteRequestCommon(url, params, headersCover, encoding);default:throw new IllegalArgumentException("Unsupported request type: " + requestType);}}
 /*** 獲取授權Token*/public static synchronized void refreshAuthorizationToken() throws Exception {Map<String, Object> params = new HashMap<>();params.put("userName", "");//輸入onloyoffice 登錄用戶名params.put("password", "");//輸入onloyoffice登錄密碼Map<String, String> headers = new HashMap<>();headers.put("Accept", "application/json");headers.put("Content-Type", "application/json");String result = executePostRequestCommon(HttpUtils.O_AUTH_URL, params, headers, "UTF-8");JSONObject jsonObject = JSONObject.parseObject(result);HttpUtils.authorizationToken = "Bearer " + jsonObject.getJSONObject("response").getString("token");}// 獲取Token的方法@PostConstructpublic static String getAuthorizationToken() throws Exception {if (CommonFunctions.isEmpty(HttpUtils.authorizationToken)) {refreshAuthorizationToken();}return HttpUtils.authorizationToken;}
    /*** 執行GET通用請求*/public static String executeGetRequestCommon(String url, Map<String, Object> params, Map<String, String> headers, String encoding) throws Exception {// 創建一個帶有默認配置的HttpClient,并設置超時時間RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000) // 連接超時時間.setSocketTimeout(10000) // 讀取超時時間.build();try (CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build()) {// 構建帶有查詢參數的URLif (params != null && !params.isEmpty()) {StringBuilder queryString = new StringBuilder(url);if (!url.contains("?")) {queryString.append("?");} else {queryString.append("&");}for (String key : params.keySet()) {queryString.append(key).append("=").append(params.get(key)).append("&");}// 去掉最后一個多余的&if (queryString.toString().endsWith("&")) {queryString.setLength(queryString.length() - 1);}url = queryString.toString();}HttpGet httpGet = new HttpGet(url);// 添加自定義頭信息if (headers != null) {for (Map.Entry<String, String> entry : headers.entrySet()) {httpGet.addHeader(entry.getKey(), entry.getValue());}}// 執行請求并獲取響應try (CloseableHttpResponse response = httpClient.execute(httpGet)) {HttpEntity entity = response.getEntity();return entity != null ? EntityUtils.toString(entity, encoding != null ? encoding : "UTF-8") : null;}} catch (IOException e) {logger.error("Error executing GET request to URL: {}. Exception: {}", url, e.getMessage(), e);throw e;}}
public static String O_FILES_URL = "https://(自己服務器ip或者域名)/Products/Files/Services/WCFService/service.svc"public static String O_SHAREFILE_URL = "https://(自己服務器ip或者域名)/api/2.0/files/file/"
/*** 獲取授權Token* @return 授權Token字符串* @throws Exception 如果請求或解析失敗*/public static String renovateAuthorizationToken() throws Exception {// 構造請求參數Map<String, Object> params = new HashMap<>();params.put("userName", "");//輸入onloyoffice 登錄用戶名params.put("password", "");//輸入onloyoffice登錄密碼// 構造請求頭Map<String, String> headers = new HashMap<>();headers.put("Accept", "application/json");headers.put("Content-Type", "application/json");// 執行POST請求并獲取結果String result = executePostRequestCommon(HttpUtils.O_AUTH_URL, params, headers, "UTF-8");// 解析JSON結果JSONObject jsonObject = JSONObject.parseObject(result);return jsonObject.getJSONObject("response").getString("token");}

4.效果圖

在這里插入圖片描述
在這里插入圖片描述

5.可以參考此文章優化代碼

https://www.cnblogs.com/gamepen/p/17849005.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/78025.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78025.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78025.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決ubuntu server修改為中文后亂碼問題(改回英文)

操作步驟 1.安裝英文語言包 sudo apt-get install language-pack-en2.編輯/etc/default/locale文件 sudo vim /etc/default/locale修改為以下內容&#xff1a; LANG"en_US.UTF-8" LANGUAGE"en_US:en" LC_ALL"en_US.UTF-8"3.應用配置 sudo l…

安卓的Launcher 在哪個環節進行啟動

安卓Launcher在系統啟動過程中的關鍵環節啟動&#xff0c;具體如下&#xff1a; 內核啟動&#xff1a;安卓設備開機后&#xff0c;首先由引導加載程序啟動Linux內核。內核負責初始化硬件設備、建立內存管理機制、啟動系統進程等基礎工作&#xff0c;為整個系統的運行提供底層支…

數據通信學習筆記之OSPF其他內容2

OSPF 與 BFD 聯動 網絡上的鏈路故障或拓撲變化都會導致設備重新進行路由計算&#xff0c;所以縮短路由協議的收斂時間對于提高網絡的性能是非常重要的。 OSPF 與 BFD 聯動就是將 BFD 和 OSPF 關聯起來&#xff0c;一旦與鄰居之間的鏈路出現故障&#xff0c;BFD 對完品以&…

數據庫原理及應用mysql版陳業斌實驗四

&#x1f3dd;?專欄&#xff1a;Mysql_貓咪-9527的博客-CSDN博客 &#x1f305;主頁&#xff1a;貓咪-9527-CSDN博客 “欲窮千里目&#xff0c;更上一層樓。會當凌絕頂&#xff0c;一覽眾山小。” 目錄 實驗四索引與視圖 1.實驗數據如下 student 表&#xff08;學生表&…

[密碼學實戰]密評考試訓練系統v1.0程序及密評參考題庫(獲取路徑在文末)

[密碼學實戰]密評考試訓練系統v1.0程序及密評參考題庫 引言:密評考試的重要性與挑戰 商用密碼應用安全性評估(簡稱"密評") 作為我國密碼領域的重要認證體系,已成為信息安全從業者的必備技能。根據國家密碼管理局最新數據,截至2024年6月,全國僅有3000余人持有…

藍橋杯練習題2

動態規劃 動態規劃三大題型&#xff1a;計數問題、最值問題、存在性問題&#xff1b; 【最小權值】-- 最值問題 【題目分析】 import java.util.Arrays; Arrays類中的一個方法&#xff1a;Arrays.fill(int[] m,int n) //給 int 類型(或者char類型/Long類型...)的數組全部空間…

【集群IP管理分配技術_DHCP】二、DHCP核心功能與技術實現

一、智能 IP 地址分配功能與技術實現? 1.1 功能概述? 智能 IP 地址分配是 DHCP 中間件的核心功能之一&#xff0c;它打破了傳統 DHCP 固定的分配模式&#xff0c;能夠根據網絡的實時狀態、客戶端類型、接入位置等多種因素&#xff0c;動態且合理地分配 IP 地址。例如&#…

實現AWS Lambda函數安全地請求企業內部API返回數據

需要編寫一個Lambda函數在AWS云上運行,它需要訪問企業內部的API獲取JSON格式的數據,企業有網關和防火墻,API有公司的okta身份認證,通過公司的域賬號來授權訪問,現在需要創建一個專用的域賬號,讓Lambda函數訪問Secret Manager,來獲取賬號密碼,然后通過配置訪問公司內部A…

子網劃分的學習

定長子網劃分&#xff08;Fixed-length Subnetting&#xff09; 也叫做固定長度子網劃分&#xff0c;是指在一個IP網絡中&#xff0c;把網絡劃分成若干個大小相等的子網&#xff0c;每個子網的子網掩碼長度是一樣的。 一、定長子網劃分的背景 在早期的IP地址分配中&#xff0…

3.QT-信號和槽|自定義槽函數|自定義信號}自定義的語法}帶參數的信號和槽(C++)

信號和槽 Linux信號 Signal 系統內部的通知機制. 進程間通信的方式. 信號源&#xff1a;誰發的信號.信號的類型&#xff1a;哪種類別的信號信號的處理方式&#xff1a;注冊信號處理函數&#xff0c;在信號被觸發的時候自動調用執行. Qt中的信號和Linux中的信號&#xff0c;雖…

如何在 Element UI 中優雅地使用 `this.$loading` 顯示和隱藏加載動畫

如何在 Element UI 中優雅地使用 this.$loading 顯示和隱藏加載動畫 在現代 Web 應用開發中&#xff0c;用戶體驗至關重要。當執行耗時操作&#xff08;如網絡請求或數據處理&#xff09;時&#xff0c;顯示一個友好的加載動畫可以讓用戶知道系統正在工作&#xff0c;而不是卡…

動態加載內容時selenium如何操作?

當處理動態加載的內容時&#xff0c;Selenium 是一個非常強大的工具&#xff0c;因為它可以模擬真實用戶的瀏覽器行為&#xff0c;等待頁面元素加載完成后再進行操作。以下是使用 Selenium 獲取動態加載內容的詳細步驟和代碼示例。 一、安裝 Selenium 和 ChromeDriver &#…

力扣第446場周賽

有事沒趕上, 賽后模擬了一下, 分享一下我的解題思路和做題感受 1.執行指令后的得分 題目鏈接如下&#xff1a;力扣 給你兩個數組&#xff1a;instructions 和 values&#xff0c;數組的長度均為 n。 你需要根據以下規則模擬一個過程&#xff1a; 從下標 i 0 的第一個指令開…

三維點擬合平面ransac c++

理論 平面的一般定義 在三維空間中&#xff0c;一個平面可以由兩個要素唯一確定&#xff1a; 法向量 n(a,b,c)&#xff1a;垂直于平面的方向 平面上一點 平面上任意一點 p(x,y,z) 滿足&#xff1a; ( p ? p 0 ) ? n 0 (p - p0) * n 0 (p?p0)?n0 即 a ( x ? x 0 ) …

基于LSTM-AutoEncoder的心電信號時間序列數據異常檢測(PyTorch版)

心電信號&#xff08;ECG&#xff09;的異常檢測對心血管疾病早期預警至關重要&#xff0c;但傳統方法面臨時序依賴建模不足與噪聲敏感等問題。本文使用一種基于LSTM-AutoEncoder的深度時序異常檢測框架&#xff0c;通過編碼器-解碼器結構捕捉心電信號的長期時空依賴特征&#…

Docker 部署 PostgreSQL 數據庫

Docker 部署 PostgreSQL 數據庫 基于 Docker 部署 PostgreSQL 數據庫一、拉取 PostgreSQL 鏡像二、運行 PostgreSQL 容器三、運行命令參數詳解四、查看容器運行狀態 基于 Docker 部署 PostgreSQL 數據庫 一、拉取 PostgreSQL 鏡像 首先&#xff0c;確保你的 Docker 環境已正確…

MySQL性能調優(四):MySQL的執行原理(MYSQL的查詢成本)

文章目錄 MySQL性能調優數據庫設計優化查詢優化配置參數調整硬件優化 1.MySQL的執行原理-21.1.MySQL的查詢成本1.1.1.什么是成本1.1.2.單表查詢的成本1.1.2.1.基于成本的優化步驟實戰1. 根據搜索條件&#xff0c;找出所有可能使用的索引2. 計算全表掃描的代價3. 計算使用不同索…

用 Go 優雅地清理 HTML 并抵御 XSS——Bluemonday

1、背景與動機 只要你的服務接收并回顯用戶生成內容&#xff08;UGC&#xff09;——論壇帖子、評論、富文本郵件正文、Markdown 等——就必須考慮 XSS&#xff08;Cross?Site Scripting&#xff09;攻擊風險。瀏覽器在解析 HTML 時會執行腳本&#xff1b;如果不做清理&#…

Redis SCAN 命令的詳細介紹

Redis SCAN 命令的詳細介紹 以下是 Redis SCAN? 命令的詳細介紹&#xff0c;結合其核心特性、使用場景及底層原理進行綜合說明&#xff1a; 工作原理圖 &#xff1a; ? 一、核心特性 非阻塞式迭代 通過游標&#xff08;Cursor&#xff09; 分批次遍歷鍵&#xff0c;避免一次…

SpringBoot3集成MyBatis-Plus(解決Boot2升級Boot3)

總結&#xff1a;目前升級僅發現依賴有變更&#xff0c;其他目前未發現&#xff0c;如有發現&#xff0c;后續會繼續更新 由于項目架構提升&#xff0c;以前開發的很多公共的組件&#xff0c;以及配置都需要升級&#xff0c;因此記錄需要更改的配置&#xff08;記錄時間&#…