From eba1252f9ac1e7ae86f70e2b2722dc93046496ee Mon Sep 17 00:00:00 2001
From: linwei <872216696@qq.com>
Date: Fri, 10 Jul 2026 17:12:23 +0800
Subject: [PATCH] feat(resource): 集成OnlyOffice文档编辑功能
---
drone-ops/drone-resource/src/main/java/org/sxkj/resource/endpoint/OfficeCallbackEndpoint.java | 90 ++++++++++++++++++++++++++++++--------------
1 files changed, 61 insertions(+), 29 deletions(-)
diff --git a/drone-ops/drone-resource/src/main/java/org/sxkj/resource/endpoint/OfficeCallbackEndpoint.java b/drone-ops/drone-resource/src/main/java/org/sxkj/resource/endpoint/OfficeCallbackEndpoint.java
index ca9c313..3451b39 100644
--- a/drone-ops/drone-resource/src/main/java/org/sxkj/resource/endpoint/OfficeCallbackEndpoint.java
+++ b/drone-ops/drone-resource/src/main/java/org/sxkj/resource/endpoint/OfficeCallbackEndpoint.java
@@ -6,7 +6,6 @@
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
-import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
@@ -15,17 +14,18 @@
import org.springblade.core.oss.model.BladeFile;
import org.springblade.core.tenant.annotation.NonDS;
import org.springblade.core.tool.utils.FileUtil;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
import org.sxkj.common.utils.file.FileNameHarsher;
import org.sxkj.resource.builder.OssBuilder;
-import org.sxkj.resource.dto.OfficeCallbackDTO;
import org.sxkj.resource.entity.Attach;
import org.sxkj.resource.service.IAttachService;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
/**
* ONLYOFFICE 回调端点
@@ -56,6 +56,7 @@
* <p>
* 处理ONLYOFFICE文档编辑保存回调,支持以下状态:
* status=2: 文档编辑完成,关闭编辑器时触发
+ * status=3: 文档保存出错时触发
* status=6: 文档强制保存(forcesave)时触发
* </p>
* <p>
@@ -64,43 +65,72 @@
*
* @param payload 回调数据对象,包含status、url、key、filetype等字段
* @param response HTTP响应对象
- * @return 回调响应结果,{"error":0}表示成功
+ * @throws Exception 回调处理异常
*/
- @SneakyThrows
@PostMapping("/callback")
@ApiOperation(value = "ONLYOFFICE保存回调", notes = "ONLYOFFICE文档编辑保存回调接口")
- public Map<String, Object> officeCallback(@RequestBody JSONObject payload, HttpServletResponse response) {
+ public void officeCallback(@RequestBody JSONObject payload, HttpServletResponse response) throws Exception {
log.info("ONLYOFFICE回调开始,回调数据: {}", JSON.toJSONString(payload));
- // 1. 获取回调状态码
- Integer status = payload.getInteger("status");
+ // 步骤1:获取回调状态码(核心逻辑判断依据:2/3/6 表示需要保存文档)
+ int status = payload.getIntValue("status");
log.info("回调状态status={}", status);
- // 2. 获取编辑后文件下载地址
- String downloadUrl = payload.getString("url");
- if (downloadUrl != null) {
- log.info("编辑后新版文件下载地址: {}", downloadUrl);
- }
-
- // 3. 获取文档唯一标识key
- String key = payload.getString("key");
- log.info("回调key={}", key);
-
try {
- // 4. 处理不同状态码
+ // 步骤2:判断是否需要保存文档
// status=2: 文档被关闭,所有用户都退出编辑,需要保存
+ // status=3: 文档保存出错时触发
// status=6: 文档强制保存(forcesave),编辑过程中定时或手动触发
- if ((status == 2 || status == 6) && downloadUrl != null) {
+ if (status == 2 || status == 3 || status == 6) {
+ String downloadUrl = payload.getString("url");
+ String key = payload.getString("key");
+ log.info("回调key={}, 下载地址: {}", key, downloadUrl);
+
+ // 步骤3:检查文件URL是否为空
+ if (downloadUrl == null || downloadUrl.isEmpty()) {
+ log.warn("缺少文件URL,status={}, key={}", status, key);
+ sendErrorResponse(response, "缺少文件URL");
+ return;
+ }
+
+ // 步骤4:处理保存回调
handleSaveCallback(payload, key, downloadUrl);
}
- // 5. 成功必须返回 {"error":0}
- return Map.of("error", 0);
+ // 步骤5:返回OnlyOffice要求的规范响应(error:0 表示处理成功)
+ sendSuccessResponse(response);
} catch (Exception e) {
- log.error("ONLYOFFICE回调处理失败,status={}, key={}, 错误: {}", status, key, e.getMessage(), e);
- // 异常返回非0,文档服务判定保存失败
- return Map.of("error", 1);
+ log.error("ONLYOFFICE回调处理失败,status={}, 错误: {}", status, e.getMessage(), e);
+ // 步骤6:异常时返回 error:1
+ sendErrorResponse(response, e.getMessage());
}
+ }
+
+ /**
+ * 发送成功响应给OnlyOffice
+ *
+ * @param response HTTP响应对象
+ * @throws Exception IO异常
+ */
+ private void sendSuccessResponse(HttpServletResponse response) throws Exception {
+ JSONObject responseJson = new JSONObject();
+ responseJson.put("error", 0);
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+ response.getWriter().write(responseJson.toString());
+ }
+
+ /**
+ * 发送错误响应给OnlyOffice
+ *
+ * @param response HTTP响应对象
+ * @param message 错误消息
+ * @throws Exception IO异常
+ */
+ private void sendErrorResponse(HttpServletResponse response, String message) throws Exception {
+ JSONObject responseJson = new JSONObject();
+ responseJson.put("error", 1);
+ response.setContentType(MediaType.APPLICATION_JSON_VALUE);
+ response.getWriter().write(responseJson.toString());
}
/**
@@ -127,8 +157,10 @@
log.info("找到附件记录,attachId={}, name={}", attach.getId(), attach.getName());
// 2. 从ONLYOFFICE服务器下载编辑后的文件
- log.info("开始从ONLYOFFICE下载编辑后文件: {}", downloadUrl);
- byte[] fileContent = downloadFile(downloadUrl);
+ // 对URL进行HTML实体解码(将&转换为&)
+ String decodedUrl = downloadUrl.replace("&", "&");
+ log.info("开始从ONLYOFFICE下载编辑后文件,解码后URL: {}", decodedUrl);
+ byte[] fileContent = downloadFile(decodedUrl);
log.info("文件下载完成,大小: {} bytes", fileContent.length);
// 3. 上传文件到OSS
--
Gitblit v1.9.3