onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2

文章目录

  • onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
  • 前提 需要注意把这个 (改成自己服务器的ip或者域名) 改成 自己服务器的域名或者地址
  • 我使用的onloyoffice版本 8.1.3.4
  • 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.可以参考此文章优化代码

onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2

前提 需要注意把这个 (改成自己服务器的ip或者域名) 改成 自己服务器的域名或者地址

我使用的onloyoffice版本 8.1.3.4

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>
import {openedit, getHistoryData, restoreVersion, editHistory} from '@/http/http';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: {// 加载脚本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";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) {const config = res.data.openedit;config.events = this.getEditorEvents();this.docEditor = new window.DocsAPI.DocEditor(this.$refs.editorContainer.id, config);}}).catch(this.handleError);},// 获取编辑器事件配置getEditorEvents() {return {onRequestHistory: this.handleRequestHistory,onRequestHistoryClose: this.handleRequestHistoryClose,onRequestHistoryData: this.handleRequestHistoryData,onRequestRestore: this.handleRequestRestore};},// 处理请求历史记录事件handleRequestHistory() {editHistory({"fileId": this.$route.params.id}).then((res) => {if (res.code === 200) {const historyList = res.data.editHistory;const fileToken = res.data.fileToken;const currentVersion = historyList[historyList.length - 1].version;this.docEditor.refreshHistory({currentVersion,token: fileToken,history: historyList});}}).catch(this.handleError);},// 处理关闭历史记录事件handleRequestHistoryClose() {document.location.reload();},// 处理请求历史记录数据事件handleRequestHistoryData(event) {const version = event.data;getHistoryData({"fileId": this.$route.params.id, "version": version}).then((res) => {if (res.code === 200) {const historyData = res.data.historyData;this.docEditor.setHistoryData(historyData);}}).catch(this.handleError);},// 处理版本恢复事件handleRequestRestore(event) {const version = event.data.version;restoreVersion({"fileId": this.$route.params.id, "version": version}).then((res) => {if (res.code === 200) {const historyList = res.data.editHistory;const currentVersion = historyList[historyList.length - 1].version;this.docEditor.refreshHistory({currentVersion,history: historyList});}}).catch(this.handleError);},// 统一错误处理handleError(err) {console.log(err);},// 销毁编辑器destroyEditor() {if (this.docEditor) {this.docEditor.destroyEditor();this.docEditor = null;}if (this.DocsAPIInterval) {clearInterval(this.DocsAPIInterval);}}},beforeDestroy() {this.destroyEditor();},beforeRouteLeave(to, from, next) {this.destroyEditor();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());}}
    /*** 还原版本** @return* @request: fileId   personId*/@PostMapping("/restoreVersion")public RestResultDTO restoreVersion(HttpServletRequest request, @RequestBody OnlyofficeRequestDTO params) {try {if (CommonFunctions.isEmpty(params.getFileId()) || CommonFunctions.isEmpty(params.getVersion())) {throw new BusinessServiceException("非空校验失败");}Map<String, Object> resultMap  = onlyofficeService.restoreVersion(params);return RestResultDTO.success(resultMap);} catch (Exception e) {LOGGER.error("restoreVersion 方法发生异常: ", e);return RestResultDTO.error(ResponseCodeDTO.INTERNAL_SERVER_ERROR, e.getMessage());}}
    /*** 修改历史** @return* @request: fileId   personId*/@PostMapping("/editHistory")public RestResultDTO editHistory(HttpServletRequest request, @RequestBody OnlyofficeRequestDTO params) {try {if (CommonFunctions.isEmpty(params.getFileId())) {throw new BusinessServiceException("非空校验失败");}Map<String, Object> resultMap  = onlyofficeService.editHistory(params);return RestResultDTO.success(resultMap);} catch (Exception e) {LOGGER.error("editHistory 方法发生异常: ", 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);
    Map<String, Object> restoreVersion(OnlyofficeRequestDTO params);
    Map<String, Object> editHistory(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);}// 使用 Map 封装多个 JSON 对象Map<String, Object> resultMap = new HashMap<>();resultMap.put("openedit", onlyOfficeConfig);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;}
    @Overridepublic Map<String, Object> restoreVersion(OnlyofficeRequestDTO params) {String fileId = params.getFileId();String version = params.getVersion();JSONArray responseArray = null;try {String result = HttpUtils.executeRequestOnlyoffice(HttpUtils.O_FILES_URL + "/restore-version?fileId=" + fileId + "&version=" + version, null, null, "UTF-8", "put");// 尝试解析为 JSONArrayJSONArray resJsonArray = JSONArray.parseArray(result);if (CollectionUtils.isEmpty(resJsonArray))  {throw new BusinessServiceException("获取配置文件异常");}} catch (Exception e) {LOGGER.error(" 解析JSON响应失败", e);throw new BusinessServiceException("", e);}Map<String, Object> stringObjectMap = this.editHistory(params);return stringObjectMap;}
 @Overridepublic Map<String, Object> editHistory(OnlyofficeRequestDTO params) {String fileId = params.getFileId();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<>();try {resultMap.put("fileToken",HttpUtils.renovateAuthorizationToken());} catch (Exception e) {LOGGER.error(" 获取token失败", e);throw new BusinessServiceException("", e);}resultMap.put("editHistory", 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.mzph.cn/bicheng/78732.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

概率论与统计(不确定性分析)主要应用在什么方面?涉及到具体知识是什么?

用户问的是概率论与统计&#xff08;不确定性分析&#xff09;的主要应用方面&#xff0c;涉及的具体知识以及具体公式。首先&#xff0c;我需要确定概率论与统计在哪些领域有应用&#xff0c;比如工程、金融、医学、数据科学等等。然后&#xff0c;具体知识部分应该包括概率论…

如何利用快照与备份快速恢复服务器的数据

在服务器上利用**快照&#xff08;Snapshot&#xff09;**和**备份&#xff08;Backup&#xff09;**快速恢复数据&#xff0c;可显著减少停机时间并确保业务连续性。以下是具体操作步骤和最佳实践&#xff1a; --- ### **1. 快照&#xff08;Snapshot&#xff09;恢复** **适…

安卓APP开发项目源码

在移动互联网蓬勃发展的今天&#xff0c;安卓应用几乎覆盖了人们生活的方方面面。从社交、购物&#xff0c;到医疗、教育&#xff0c;APP 的需求呈指数级增长。然而&#xff0c;如何高效、低成本地开发一款质量可靠的安卓应用&#xff0c;仍是很多开发者和团队关注的核心问题。…

遨游三防|30200mAh、双露营灯三防平板,见证堆料天花板

在工业4.0与智能化转型的浪潮中&#xff0c;专业设备对性能、防护及场景适应性的要求日益严苛。遨游通讯作为国家级高新技术企业&#xff0c;依托“危、急、特”场景的深耕经验&#xff0c;推出的旗舰级产品AORO-P300三防平板&#xff0c;以30200mAh超大容量电池、双露营灯设计…

【Python】Matplotlib:立体永生花绘制

本文代码部分实现参考自CSDN博客&#xff1a;https://blog.csdn.net/ak_bingbing/article/details/135852038 一、引言 Matplotlib作为Python生态中最著名的可视化库&#xff0c;其三维绘图功能可以创造出令人惊叹的数学艺术。本文将通过一个独特的参数方程&#xff0c;结合极…

OpenCV 图形API(57)颜色空间转换-----将图像从 RGB 色彩空间转换为 YUV 色彩空间函数RGB2YUV()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为 YUV 色彩空间。 该函数将输入图像从 RGB 色彩空间转换为 YUV。R、G 和 B 通道值的常规范围是 0 到 255。 在进行线…

Kubernetes(K8S)入门阶段详细指南

Kubernetes(K8S)入门阶段详细指南 一、容器技术基础:Docker核心操作与理解 1.1 Docker核心操作 镜像管理: 拉取镜像:docker pull ubuntu(以Ubuntu为例)查看本地镜像:docker images删除镜像:docker rmi <image_id>容器生命周期管理: 启动容器:docker run -d -…

AI大模型学习十一:‌尝鲜ubuntu 25.04 桌面版私有化sealos cloud + devbox+minio,实战运行成功

一、说明 没意思&#xff0c;devbox私有化不支持&#xff0c;看来这个开源意义不大&#xff0c;和宣传差距很大啊&#xff0c;那devbox就不用玩 用了ubuntu 25.04&#xff0c;内核为GNU/Linux 6.14.0-15-generic x86_64&#xff0c;升级了部分image&#xff0c;过程曲折啊 se…

[GXYCTF2019]Ping Ping Ping

解题步骤 1、先使用 内敛执行 查看当前的php文件 执行 命令执行 发现空格被过滤 ?ip127.0.0.1$IFS|$IFSwhomi 还有一个点就是这个 执行的命令是不能进行拼接的 可能就是被过滤了 | 所以我们使用 ; 进行绕过一下 空格过滤代替 $IFS ${IFS} ${IFS}$9 //这里$1到$9都可以 $IFS$1…

重温TCP通信过程

文章目录 1. 慢启动2. 拥塞避免 3. 快速重传和快速恢复 初识tcp报文 我们先来简单认识一下报文的格式,具体理解需要后面详细介绍 源端口和目的端口:顾名思义就是标识传输双方的信息首部长度:指的是TCP报头的长度,换句话来说,我们需要用一个属性来描述报头的长度,就说明TCP的报…

力扣HOT100之链表:23. 合并 K 个升序链表

这道题我是用最淳朴最简单的思路去做的&#xff0c;用一个while循环持续地将当前遍历到的最小值加入到合并链表中&#xff0c;while循环中使用一个for循环遍历整个指针数组&#xff0c;将其中的最小值和对应下标记录下来&#xff0c;并将其值加入到合并链表中&#xff0c;同时对…

Spring Boot 支持政策

&#x1f9d1;&#x1f4bb; Spring Boot 支持政策 ✒️ Andy Wilkinson 于2023年12月7日编辑本页 32次修订 &#x1f4cc; 核心政策 &#x1f6e1;️ VMware Tanzu 开源支持政策 Spring Boot 针对关键错误和安全问题提供支持 &#x1f4c6; 版本支持周期 1️⃣ 主要版本&a…

WeakAuras Lua Script TOC BOSS2 <Lord Jaraxxus>

WeakAuras Lua脚本&#xff08;WA 字符串&#xff09; 十字军试炼老2 加拉克苏斯 血肉成灰 !WA:2!TIv7VnYrz8UXuDudiDN7PqFfCdTHKYLOeN7sBpXvKDIZf36Kyw7KRT3DYE2Dh7DAwV7CZSoXUOIewf4GdAfgbu13LPasv8MS4diavKoH4RSkIp0phXDT8je5FGYZmZU2oVCqrGLJZUpZZoZZB)EEz1wkr9ewjSU6MD5u…

Spring security详细上手教学(二)用户管理

Spring security详细上手教学&#xff08;二&#xff09;用户管理 这章节主要学习&#xff1a; 如何使用UserDetails接口描述用户在鉴权流中使用UserDetailsService自定义的UserDetailsService实现自定义的UserDetailsManager实现在鉴权中使用JdbcUserDetialsManager 在Spri…

网络安全厂商F5荣登2025 CRN AI 100榜单,释放AI潜力

近期&#xff0c;网络安全厂商F5凭借其应用交付和安全技术与前沿的人工智能洞察&#xff0c;成功入选“2025 CRN AI 100 榜单”&#xff0c;并跻身“领导者”之列。这一荣誉的获得&#xff0c;彰显了F5在助力企业拥抱人工智能创新的过程中&#xff0c;无需牺牲性能、灵活性或安…

4.RabbitMQ - 延迟消息

RabbitMQ延迟消息 文章目录 RabbitMQ延迟消息一、延迟消息介绍二、实现2.1 死信交换机2.2 延迟消息插件2.3 取消超时订单 一、延迟消息介绍 延迟消息&#xff1a;生产者发送消息时指定一个时间&#xff0c;消费者不会立刻收到消息&#xff0c;而是在指定时间后才收到消息 用户…

5.学习笔记-SpringMVC(P53-P60)

1.响应 &#xff08;1&#xff09;响应页面 &#xff08;2&#xff09;响应数据&#xff08;异步提交&#xff09;&#xff1a;文本数据、json数据 2.REST风格 (1)REST:表现形式状态转换。 (2)传统风格资源描述形式 3.Restful入门案例 5.基于RESTful页面数据…

Golang | 搜索表达式

// (( A | B | C ) & D ) | E & (( F | G ) & H )import "strings"// 实例化一个搜索表达式 func NewTermQuery(field, keyword string) *TermQuery {return &TermQuery{Keyword: &Keyword{Field: field, Word: keyword},} }func (tq *TermQuery…

LangChain构建大模型应用之RAG

RAG(Retrieval-augmented Generation 检索增强生成)是一种结合信息检索与生成模型的技术,通过动态整合外部知识库提升大模型输出的准确性和时效性。其核心思想是在生成答案前,先检索外部知识库中的相关信息作为上下文依据,从而突破传统生成模型的静态知识边界。 为什么我们…

Ubuntu 下 Nginx 1.28.0 源码编译安装与 systemd 管理全流程指南

一、环境与依赖准备 为确保编译顺利&#xff0c;我们首先更新系统并安装必要的编译工具和库&#xff1a; sudo apt update sudo apt install -y build-essential \libpcre3 libpcre3-dev \zlib1g zlib1g-dev \libssl-dev \wgetbuild-essential&#xff1a;提供 gcc、make 等基…