package jnpf.bizcommon.onlyoffice.controller;
|
|
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import jnpf.base.ActionResult;
|
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeCallbackParam;
|
import jnpf.bizcommon.onlyoffice.entity.OnlyOfficeConfigParam;
|
import jnpf.bizcommon.onlyoffice.service.OnlyOfficeService;
|
import jnpf.exception.DataException;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.util.Collections;
|
import java.util.Map;
|
|
/**
|
* OnlyOffice 文档编辑。经网关 /api/biz/onlyoffice/**(StripPrefix=2)落到本类。
|
*
|
* <p>⚠️ 本类下的端点鉴权形态不统一,新增端点前先想清楚属于哪一类:
|
* <ul>
|
* <li>{@code /config} —— 需登录态。它会下发 securityKey,**不可放进网关白名单**;</li>
|
* <li>{@code /callback} —— 在网关白名单内(平台补丁 #9),匿名可达,
|
* 安全边界是 OnlyOffice 回调 JWT 的验签,见里程碑 2。</li>
|
* </ul>
|
*/
|
@Slf4j
|
@Tag(name = "OnlyOffice 文档编辑", description = "编辑器配置签发与保存回调")
|
@RestController
|
@RequestMapping("/onlyoffice")
|
@RequiredArgsConstructor
|
public class OnlyOfficeController {
|
|
private final OnlyOfficeService onlyOfficeService;
|
|
/**
|
* 签发编辑器配置。前端拿返回值直接喂 {@code new DocsAPI.DocEditor(id, config)}。
|
*
|
* <p>入参里的 mode 只是期望值:格式不可编辑、他人正持锁、上次保存失败三种情况下,
|
* 后端会降级为只读,以实际返回的 editorConfig.mode 为准。
|
*/
|
@Operation(summary = "签发编辑器配置")
|
@GetMapping("/config")
|
public ActionResult<Map<String, Object>> config(OnlyOfficeConfigParam param) {
|
try {
|
return ActionResult.success(onlyOfficeService.buildEditorConfig(param));
|
} catch (DataException e) {
|
log.warn("签发 OnlyOffice 配置失败:{}", e.getMessage());
|
return ActionResult.fail(e.getMessage());
|
}
|
}
|
|
@Operation(summary = "查询文档保存状态")
|
@GetMapping("/save-status")
|
public ActionResult<Map<String, Object>> saveStatus(@RequestParam String fileId) {
|
try {
|
return ActionResult.success(onlyOfficeService.getSaveStatus(fileId));
|
} catch (DataException e) {
|
return ActionResult.fail(e.getMessage());
|
}
|
}
|
|
/**
|
* DS 保存回调。**匿名可达**(路径在网关白名单内,平台补丁 #9),
|
* 安全边界是 Service 内对回调 JWT 的验签。
|
*
|
* <p>返回值格式是 OnlyOffice 定死的 {@code {"error":0}},不能套 ActionResult。
|
* 且**无论处理成功与否都返回 0**——返回非 0 会让 DS 认为保存失败并无限重试,
|
* 而多数失败(会话不存在、验签不过)重试多少次都不会变好。真正的问题靠日志暴露。
|
*/
|
@Operation(summary = "DS 保存回调")
|
@PostMapping("/callback")
|
public Map<String, Object> callback(@RequestBody OnlyOfficeCallbackParam param,
|
@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authorization) {
|
try {
|
onlyOfficeService.handleCallback(param, authorization);
|
} catch (DataException e) {
|
log.warn("OnlyOffice 回调处理失败,key={} status={}:{}", param.getKey(), param.getStatus(), e.getMessage());
|
} catch (Exception e) {
|
log.error("OnlyOffice 回调处理异常,key={} status={}", param.getKey(), param.getStatus(), e);
|
}
|
return Collections.singletonMap("error", 0);
|
}
|
}
|