diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/controller/admin/OnlyOfficeController.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/controller/admin/OnlyOfficeController.java index a645fea9..49dd0a46 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/controller/admin/OnlyOfficeController.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/controller/admin/OnlyOfficeController.java @@ -6,6 +6,7 @@ import com.zt.plat.framework.business.controller.AbstractFileUploadController; import com.zt.plat.framework.business.interceptor.BusinessControllerMarker; import com.zt.plat.framework.common.enums.UserTypeEnum; import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.framework.datapermission.core.annotation.DeptDataPermissionIgnore; import com.zt.plat.framework.security.core.LoginUser; import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils; import com.zt.plat.framework.tenant.core.aop.TenantIgnore; @@ -17,8 +18,8 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.annotation.Resource; import jakarta.annotation.security.PermitAll; import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -32,7 +33,7 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success; @RestController @RequestMapping("/qms/common/only-office") @Validated -//@DeptDataPermissionIgnore(enable = "true") +@DeptDataPermissionIgnore(enable = "true") @FileUploadController(source = "qms.only-office", codeKey = "data.fileUploadBusinessCode") public class OnlyOfficeController extends AbstractFileUploadController implements BusinessControllerMarker { @@ -53,6 +54,15 @@ public class OnlyOfficeController extends AbstractFileUploadController implement return success(onlyOfficeService.getEditorConfig(id)); } + @GetMapping("/file-content") + @Operation(summary = "获取文档文件内容") + @PermitAll + public void getFileContent(@RequestParam("fileId") Long fileId, + @RequestParam("token") String token, + HttpServletResponse response) { + onlyOfficeService.getDocFileContent(fileId, token, response); + } + @PostMapping("/callback") @Operation(summary = "OnlyOffice 回调接口") @PermitAll diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeService.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeService.java index efedabf0..677355b9 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeService.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeService.java @@ -1,8 +1,11 @@ package com.zt.plat.module.qms.resource.record.controller.admin.onlyOffice.service; import com.zt.plat.module.qms.resource.record.controller.admin.onlyOffice.controller.vo.OnlyOfficeEditorConfigRespVO; +import jakarta.servlet.http.HttpServletResponse; public interface OnlyOfficeService { OnlyOfficeEditorConfigRespVO getEditorConfig(Long id); + + void getDocFileContent(Long fileId, String token, HttpServletResponse response); } diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeServiceImpl.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeServiceImpl.java index c30fb72d..71c72efd 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeServiceImpl.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/controller/admin/onlyOffice/service/OnlyOfficeServiceImpl.java @@ -11,11 +11,14 @@ import com.zt.plat.module.qms.resource.record.controller.admin.onlyOffice.contro import com.zt.plat.module.system.api.user.AdminUserApi; import com.zt.plat.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.io.OutputStream; + import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.zt.plat.module.infra.enums.ErrorCodeConstants.DOC_NOT_EXISTS; @@ -90,51 +93,10 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService{ @Override public OnlyOfficeEditorConfigRespVO getEditorConfig(Long id) { -// DocFileDO doc = docFileMapper.selectById(id); -// if (doc == null) { -// throw exception(DOC_NOT_EXISTS); -// } + Long userId = SecurityFrameworkUtils.getLoginUserId(); OnlyOfficeEditorConfigRespVO resp = new OnlyOfficeEditorConfigRespVO(); -// // 根据文件类型动态设置文档类型 -// String documentType = getDocumentType(doc.getFileType()); -// resp.setDocumentType(documentType); -// -// DocEditorConfigRespVO.DocumentConfig document = new DocEditorConfigRespVO.DocumentConfig(); -// document.setFileType(doc.getFileType()); -// -// // 关键修复:使用基于文档版本的稳定key策略 -// // 只有当文档内容真正发生版本变更时,key才会改变 -// String documentKey; -// if (doc.getLatestVersionId() != null) { -// // 使用文档ID + 最新版本ID,确保同一版本在编辑期间key保持不变 -// documentKey = doc.getId() + "_v" + doc.getLatestVersionId(); -// } else { -// // 如果没有版本信息,使用文档ID + 创建时间(不会变化) -// documentKey = doc.getId() + "_init_" + doc.getCreateTime().toEpochSecond(java.time.ZoneOffset.UTC); -// } -// -// document.setKey(documentKey); -// document.setTitle(doc.getTitle()); -// -// log.info("生成文档key: docId={}, key={}, latestVersionId={}, userId={}", -// doc.getId(), documentKey, doc.getLatestVersionId(), userId); -// -// // 使用新的接口生成文件 URL -// String fileUrl = ""; -// if (doc.getFileId() != null) { -// // 生成文件访问的JWT token -// String fileToken = generateFileToken(doc.getFileId()); -// -// // 生成通过新接口访问文件的URL,包含JWT token -// fileUrl = StrUtil.removeSuffix(onlyOfficeCallbackBaseUrl, "/") + "/admin-api/infra/doc-file/file-content?fileId=" + doc.getFileId(); -// if (StrUtil.isNotBlank(fileToken)) { -// fileUrl += "&token=" + fileToken; -// } -// } -// document.setUrl(fileUrl); - CommonResult file = fileApi.getFile(id); log.info("file:{}",file); if (file.getData() == null) throw exception(DOC_NOT_EXISTS); @@ -152,16 +114,7 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService{ // 关键修复:使用基于文档版本的稳定key策略 // 只有当文档内容真正发生版本变更时,key才会改变 - String documentKey; - // TODO -// if (doc.getLatestVersionId() != null) { -// // 使用文档ID + 最新版本ID,确保同一版本在编辑期间key保持不变 -// documentKey = doc.getId() + "_v" + doc.getLatestVersionId(); -// } else { -// // 如果没有版本信息,使用文档ID + 创建时间(不会变化) -// documentKey = doc.getId() + "_init_" + doc.getCreateTime().toEpochSecond(java.time.ZoneOffset.UTC); -// } -// +// String documentKey = id + "_v" + data.getUpdateTime(); // document.setKey(documentKey); document.setTitle(fileName); @@ -244,6 +197,84 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService{ } return resp; } + @Override + public void getDocFileContent(Long fileId, String token, HttpServletResponse response) { + try { + // 验证JWT token + if (StrUtil.isBlank(token)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // 验证JWT签名和有效性 + if (StrUtil.isNotBlank(onlyOfficeJwtSecret)) { + try { + JWT jwt = JWT.of(token).setKey(onlyOfficeJwtSecret.getBytes()); + if (!jwt.verify()) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + + // 验证token中的fileId是否匹配 + Object tokenFileId = jwt.getPayload("fileId"); + if (tokenFileId == null || !fileId.equals(Long.valueOf(tokenFileId.toString()))) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + return; + } + + // 验证token是否过期(可选,如果token中包含过期时间) + Object expTime = jwt.getPayload("exp"); + if (expTime != null) { + long expTimestamp = Long.parseLong(expTime.toString()); + if (System.currentTimeMillis() / 1000 > expTimestamp) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + } + } catch (Exception e) { + log.warn("JWT验证失败: token={}", token, e); + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + return; + } + } + + // 获取文件信息 + CommonResult fileInfo = fileApi.getFileInfo(fileId); + FileRespDTO file = fileInfo.getData(); + if (file == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + + // 获取文件内容 + byte[] content = file.getContent(); + if (content == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + + // 设置响应头 + response.setContentType(file.getType() != null ? file.getType() : "application/octet-stream"); +// response.setContentLength(content.length); + response.setHeader("Content-Disposition", "inline; filename=\"" + file.getName() + "\""); + // 添加跨域头,允许 OnlyOffice 访问 + response.setHeader("Access-Control-Allow-Origin", "*"); + response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With"); + response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "0"); + + // 写入响应 + try (OutputStream os = response.getOutputStream()) { + os.write(content); + os.flush(); + } + } catch (Exception e) { + log.error("获取文档文件内容失败: fileId={}", fileId, e); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + } public String getFileSuffix(String fileName){ //从文件名中最后一个点截取,例:1111.111.222.docx,截取 docx diff --git a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/service/recordapply/RecordApplyServiceImpl.java b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/service/recordapply/RecordApplyServiceImpl.java index 530e3b74..ed5be635 100644 --- a/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/service/recordapply/RecordApplyServiceImpl.java +++ b/zt-module-qms/zt-module-qms-server/src/main/java/com/zt/plat/module/qms/resource/record/service/recordapply/RecordApplyServiceImpl.java @@ -299,6 +299,9 @@ public class RecordApplyServiceImpl implements RecordApplyService, BMPCallbackIn for (RecordApplyDetailSaveReqVO item : detailList) { RecordApplyDetailDO recordApplyDetailDO = new RecordApplyDetailDO(); recordApplyDetailDO.setApplyId(recordApplyDO.getId()); + recordApplyDetailDO.setTargetId(SecurityFrameworkUtils.getLoginUserId()); + recordApplyDetailDO.setTargetType(RecordConstants.TargetType.USER); + recordApplyDetailDO.setTargetName(SecurityFrameworkUtils.getLoginUserNickname()); recordApplyDetailDO.setDocumentId(item.getDocumentId()); recordApplyDetailDO.setIsModify(item.getIsModify()); recordApplyDetailDO.setModifyCause(item.getModifyCause()); @@ -328,6 +331,9 @@ public class RecordApplyServiceImpl implements RecordApplyService, BMPCallbackIn List detailDOList = BeanUtils.toBean(detailList, RecordApplyDetailDO.class); for (RecordApplyDetailDO item : detailDOList) { item.setApplyId(recordApplyDO.getId()); + item.setTargetId(SecurityFrameworkUtils.getLoginUserId()); + item.setTargetType(RecordConstants.TargetType.USER); + item.setTargetName(SecurityFrameworkUtils.getLoginUserNickname()); detailSaveReqVOList.add(item); } return detailSaveReqVOList; @@ -343,6 +349,9 @@ public class RecordApplyServiceImpl implements RecordApplyService, BMPCallbackIn recordApplyDetailDO.setIsModify(item.getIsModify()); recordApplyDetailDO.setModifyCause(item.getModifyCause()); recordApplyDetailDO.setFormData(item.getFormData()); + recordApplyDetailDO.setTargetId(SecurityFrameworkUtils.getLoginUserId()); + recordApplyDetailDO.setTargetType(RecordConstants.TargetType.USER); + recordApplyDetailDO.setTargetName(SecurityFrameworkUtils.getLoginUserNickname()); detailSaveReqVOList.add(recordApplyDetailDO); } return detailSaveReqVOList; @@ -702,12 +711,15 @@ public class RecordApplyServiceImpl implements RecordApplyService, BMPCallbackIn Long documentId = applyDetailDO.getDocumentId(); detailDO.setDocumentId(documentId); detailDO.setIsModify(1); + detailDO.setTargetId(applyDetailDO.getTargetId()); + detailDO.setTargetType(applyDetailDO.getTargetType()); + detailDO.setTargetName(applyDetailDO.getTargetName()); detailDO.setModifyCause(applyDetailDO.getModifyCause()); - detailDO.setApplyStartDate(LocalDateTime.now()); +// detailDO.setApplyStartDate(LocalDateTime.now()); String formData = applyDetailDO.getFormData(); JSONObject formDataJson = JSONObject.parseObject(formData); // 把documentId 存到 formDataJson 中key = id 的里面 - formDataJson.put("id", documentId); + formDataJson.put("id", documentId.toString()); // detailDO.setFormData(formDataJson.toJSONString()); detailDOList.add(detailDO); // 创建更改申请 @@ -717,6 +729,7 @@ public class RecordApplyServiceImpl implements RecordApplyService, BMPCallbackIn recordApplyRespVO.setApplyContent(applyDetailDO.getModifyCause()); // 修改原因 recordApplyRespVO.setFormData(formDataJson.toJSONString()); recordApplyRespVO.setDetailList(detailDOList); + recordApplyRespVO.setApplyStartDate(LocalDateTime.now()); createApplyData(recordApplyRespVO); }