From 7f940ff25733613113dcc7d71c2676aaec8cb419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BD=98=E8=8D=A3=E6=99=9F?= <9691125+pan-rongsheng@user.noreply.gitee.com> Date: Thu, 25 Sep 2025 18:08:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=AE=A1=E7=90=86=E7=9A=84?= =?UTF-8?q?=E5=8F=91=E5=B8=83=E6=97=B6=E9=97=B4=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../templtp/TemplateInstanceController.java | 9 +- .../onlyoffice/config/OnlyOfficeConfig.java | 14 ++ .../OnlyOfficeCallbackController.java | 42 ++++ .../admin/templtp/onlyoffice/pojo/Action.java | 23 +++ .../templtp/onlyoffice/pojo/History.java | 20 ++ .../onlyoffice/pojo/OnlyOfficeCallback.java | 83 ++++++++ .../service/OnlyOfficeCallbackService.java | 12 ++ .../OnlyOfficeCallbackServiceImpl.java | 190 ++++++++++++++++++ .../onlyoffice/util/UrlFileDownloader.java | 167 +++++++++++++++ .../dataobject/tmpltp/TemplateInstanceDO.java | 2 + .../tmpltp/TemplateInstanceService.java | 3 + .../tmpltp/TemplateInstanceServiceImpl.java | 11 +- 12 files changed, 574 insertions(+), 2 deletions(-) create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/config/OnlyOfficeConfig.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/controller/OnlyOfficeCallbackController.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/Action.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/History.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/OnlyOfficeCallback.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackService.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackServiceImpl.java create mode 100644 zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/util/UrlFileDownloader.java diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/TemplateInstanceController.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/TemplateInstanceController.java index f0c765d..e3cd0f9 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/TemplateInstanceController.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/TemplateInstanceController.java @@ -5,6 +5,7 @@ import com.zt.plat.module.base.controller.admin.templtp.vo.*; import com.zt.plat.module.base.dal.dataobject.tmpltp.TemplateInstanceDO; import com.zt.plat.module.base.service.tmpltp.TemplateInstanceService; import com.zt.plat.module.infra.api.file.FileApi; +import com.zt.plat.module.infra.api.file.dto.FileCreateReqDTO; import jakarta.validation.constraints.NotEmpty; import org.springframework.web.bind.annotation.*; import jakarta.annotation.Resource; @@ -35,6 +36,7 @@ import static com.zt.plat.framework.common.pojo.CommonResult.success; import com.zt.plat.framework.excel.core.util.ExcelUtils; import com.zt.plat.framework.apilog.core.annotation.ApiAccessLog; +import org.springframework.web.multipart.MultipartFile; import static com.zt.plat.framework.apilog.core.enums.OperateTypeEnum.*; @@ -53,10 +55,15 @@ public class TemplateInstanceController extends AbstractFileUploadController { setFileUploadInfo(annotation); } } - @Resource private TemplateInstanceService templateInstanceService; + //上传文件 + @PostMapping("/save-file") + @Operation(summary = "上传文件", description = "上传文件,传入文件对象和模版实例id") + public CommonResult> uploadFile(@NotEmpty(message = "文件不能为空") @RequestParam("file") MultipartFile file,@RequestParam("id") String id) { + return success(templateInstanceService.saveFile(file,id)); + } @PostMapping("/create") @Operation(summary = "创建模板实例") diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/config/OnlyOfficeConfig.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/config/OnlyOfficeConfig.java new file mode 100644 index 0000000..0091ff4 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/config/OnlyOfficeConfig.java @@ -0,0 +1,14 @@ +//package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.web.client.RestTemplate; +// +//@Configuration +//public class OnlyOfficeConfig { +// +// @Bean +// public RestTemplate restTemplate() { +// return new RestTemplate(); +// } +//} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/controller/OnlyOfficeCallbackController.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/controller/OnlyOfficeCallbackController.java new file mode 100644 index 0000000..4847677 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/controller/OnlyOfficeCallbackController.java @@ -0,0 +1,42 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.controller; + + +import com.zt.plat.framework.tenant.core.aop.TenantIgnore; +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo.OnlyOfficeCallback; +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.service.OnlyOfficeCallbackService; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.security.PermitAll; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/base/onlyoffice") +@Tag(name = "管理后台 - onlyOffice回调") +public class OnlyOfficeCallbackController { + + private final OnlyOfficeCallbackService callbackService; + + public OnlyOfficeCallbackController(OnlyOfficeCallbackService callbackService) { + this.callbackService = callbackService; + } + + /** + * 处理OnlyOffice文档编辑服务发送的回调 + */ + @PostMapping("/callback/{id}") + @PermitAll + @TenantIgnore + public ResponseEntity> handleCallback(@RequestBody OnlyOfficeCallback callback, @PathVariable String id) { + // 处理回调逻辑 + callbackService.processCallback(callback,id); + + // 返回必须的响应,否则OnlyOffice会显示错误 + Map response = new HashMap<>(); + response.put("error", 0); + return new ResponseEntity<>(response, HttpStatus.OK); + } +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/Action.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/Action.java new file mode 100644 index 0000000..1ba6e1a --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/Action.java @@ -0,0 +1,23 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class Action { + + /** + * 操作类型: + * 0 - 用户断开与文档共同编辑的连接 + * 1 - 新用户连接到文档共同编辑 + * 2 - 用户单击强制保存按钮 + */ + @JsonProperty("type") + private int type; + + /** + * 用户标识符 + */ + @JsonProperty("userid") + private String userId; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/History.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/History.java new file mode 100644 index 0000000..c8cdc63 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/History.java @@ -0,0 +1,20 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class History { + + /** + * 更改内容 + */ + @JsonProperty("changes") + private Object changes; + + /** + * 服务器版本 + */ + @JsonProperty("serverVersion") + private String serverVersion; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/OnlyOfficeCallback.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/OnlyOfficeCallback.java new file mode 100644 index 0000000..964ef7b --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/pojo/OnlyOfficeCallback.java @@ -0,0 +1,83 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class OnlyOfficeCallback { + + /** + * 编辑的文档标识符(必需) + */ + @JsonProperty("key") + private String key; + + /** + * 文档的状态(必需) + */ + @JsonProperty("status") + private int status; + + /** + * 用户对文档执行的操作数组 + */ + @JsonProperty("actions") + private List actions; + + /** + * 文档更改历史的对象数组(已删除,使用history替代) + */ + @JsonProperty("changeshistory") + @Deprecated + private List changesHistory; + + /** + * 文档更改历史记录的文件链接 + */ + @JsonProperty("changesurl") + private String changesUrl; + + /** + * 文档的扩展名 + */ + @JsonProperty("filetype") + private String fileType; + + /** + * 强制保存请求的启动器类型 + */ + @JsonProperty("forcesavetype") + private Integer forceSaveType; + + /** + * 提交的表单数据的JSON文件URL + */ + @JsonProperty("formsdataurl") + private String formsDataUrl; + + /** + * 文档更改历史的对象 + */ + @JsonProperty("history") + private History history; + + /** + * 已编辑的要保存的文档的链接 + */ + @JsonProperty("url") + private String url; + + /** + * 发送到命令服务的自定义信息 + */ + @JsonProperty("userdata") + private String userData; + + /** + * 打开文档进行编辑的用户标识符列表 + */ + @JsonProperty("users") + private List users; +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackService.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackService.java new file mode 100644 index 0000000..41e7afa --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackService.java @@ -0,0 +1,12 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.service; + + +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo.OnlyOfficeCallback; + +public interface OnlyOfficeCallbackService { + /** + * 处理OnlyOffice回调 + * @param callback 回调数据 + */ + void processCallback(OnlyOfficeCallback callback,String id); +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackServiceImpl.java new file mode 100644 index 0000000..7395de3 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/service/OnlyOfficeCallbackServiceImpl.java @@ -0,0 +1,190 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.service; + +import com.zt.plat.framework.common.pojo.CommonResult; +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo.Action; +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo.History; +import com.zt.plat.module.base.controller.admin.templtp.onlyoffice.pojo.OnlyOfficeCallback; +import com.zt.plat.module.infra.api.file.FileApi; +import com.zt.plat.module.infra.api.file.dto.FileCreateReqDTO; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +import static com.zt.plat.module.base.controller.admin.templtp.onlyoffice.util.UrlFileDownloader.downloadFileAsMultipart; + + +@Service +@RequiredArgsConstructor +@Slf4j +public class OnlyOfficeCallbackServiceImpl implements OnlyOfficeCallbackService { + + private final FileApi fileApi; + @Override + public void processCallback(OnlyOfficeCallback callback,String id) { + log.info("Received OnlyOffice callback for document: {}", callback.getKey()); + log.info("Callback status: {}", callback.getStatus()); + + // 根据不同的状态处理回调 + switch (callback.getStatus()) { + case 1: + handleEditingStatus(callback,id); + break; + case 2: + handleDocumentSaved(callback,id); + break; + case 3: + handleSaveError(callback,id); + break; + case 4: + handleDocumentClosedWithoutChanges(callback,id); + break; + case 6: + handleForcedSave(callback,id); + break; + case 7: + handleForcedSaveError(callback,id); + break; + default: + log.warn("Received unknown callback status: {}", callback.getStatus()); + } + } + + /** + * 处理文档正在编辑的状态 + */ + private void handleEditingStatus(OnlyOfficeCallback callback,String id) { + log.info("Document {} is being edited by users: {}", + callback.getKey(), callback.getUsers()); + + // 处理用户操作(连接或断开连接) + if (callback.getActions() != null) { + for (Action action : callback.getActions()) { + String actionType = switch (action.getType()) { + case 0 -> "disconnected from"; + case 1 -> "connected to"; + case 2 -> "clicked force save in"; + default -> "performed unknown action in"; + }; + log.info("User {} {}", action.getUserId(), actionType); + } + } + } + + /** + * 处理文档已保存的状态 + */ + private void handleDocumentSaved(OnlyOfficeCallback callback,String id) { + log.info("Document {} is ready to be saved", callback.getKey()); + saveDocument(callback,id); + + // 处理历史记录 + // handleHistoryChanges(callback,id); + } + + /** + * 处理保存错误的状态 + */ + private void handleSaveError(OnlyOfficeCallback callback,String id) { + log.error("Error saving document {}", callback.getKey()); + // 可以在这里添加错误处理逻辑,如发送通知等 + } + + /** + * 处理文档关闭且无更改的状态 + */ + private void handleDocumentClosedWithoutChanges(OnlyOfficeCallback callback,String id) { + log.info("Document {} closed without changes", callback.getKey()); + // 可以在这里添加清理资源等逻辑 + } + + /** + * 处理强制保存的状态 + */ + private void handleForcedSave(OnlyOfficeCallback callback,String id) { + log.info("Document {} forced save. Type: {}", + callback.getKey(), callback.getForceSaveType()); + saveDocument(callback,id); + + // 处理历史记录 + handleHistoryChanges(callback,id); + + // 如果是表单提交,处理表单数据 + if (callback.getForceSaveType() == 3 && callback.getFormsDataUrl() != null) { + handleFormSubmission(callback,id); + } + } + + /** + * 处理强制保存错误的状态 + */ + private void handleForcedSaveError(OnlyOfficeCallback callback,String id) { + log.error("Error during forced save of document {}", callback.getKey()); + // 可以在这里添加错误处理逻辑 + } + + /** + * 保存文档到存储 + */ + private void saveDocument(OnlyOfficeCallback callback,String id) { + if (callback.getUrl() == null) { + log.error("文件路径为空"); + return; + } + + try { + MultipartFile file = downloadFileAsMultipart(callback.getUrl()); + // 1. 验证文件是否为空 + + + // 2. 获取并验证文件名 + String fileName = file.getOriginalFilename(); + + String directory = "template-instance"; + FileCreateReqDTO fileCreateReqDTO = new FileCreateReqDTO(); + fileCreateReqDTO.setName(fileName); + fileCreateReqDTO.setContent(file.getBytes()); + fileCreateReqDTO.setType(file.getContentType()); // 使用真实的MIME类型 + fileCreateReqDTO.setDirectory(directory); // 设置文件存储目录 + + // 7. 调用文件服务创建文件 + CommonResult result = fileApi.createFile(fileCreateReqDTO); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + /** + * 处理文档历史记录变更 + */ + private void handleHistoryChanges(OnlyOfficeCallback callback,String id) { + History history = callback.getHistory(); + if (history != null) { + log.info("Processing document history changes for {}", callback.getKey()); + // 这里可以实现处理历史记录的逻辑 + // 例如:调用refreshHistory方法更新历史记录 + } + + // 处理变更历史URL + if (callback.getChangesUrl() != null) { + log.info("Changes URL for document {}: {}", callback.getKey(), callback.getChangesUrl()); + // 这里可以实现保存变更历史的逻辑 + // 例如:下载变更历史并使用setHistoryData方法存储 + } + } + + /** + * 处理表单提交数据 + */ + private void handleFormSubmission(OnlyOfficeCallback callback,String id) { + log.info("Processing form submission for document {}", callback.getKey()); + // 这里可以实现处理表单数据的逻辑 + // 例如:从formsDataUrl下载并解析表单数据 + } + + +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/util/UrlFileDownloader.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/util/UrlFileDownloader.java new file mode 100644 index 0000000..50fba30 --- /dev/null +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/controller/admin/templtp/onlyoffice/util/UrlFileDownloader.java @@ -0,0 +1,167 @@ +package com.zt.plat.module.base.controller.admin.templtp.onlyoffice.util; + +import org.jetbrains.annotations.NotNull; +import org.springframework.web.multipart.MultipartFile; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLConnection; + +/** + * 网络文件下载工具类,用于从URL下载文件并转换为MultipartFile + */ +public class UrlFileDownloader { + + // 连接超时时间(毫秒) + private static final int CONNECT_TIMEOUT = 5000; + // 读取超时时间(毫秒) + private static final int READ_TIMEOUT = 10000; + // 缓冲区大小 + private static final int BUFFER_SIZE = 4096; + + /** + * 从URL下载文件并转换为MultipartFile + * + * @param fileUrl 文件的网络地址 + * @return 转换后的MultipartFile对象 + * @throws IOException 下载过程中发生IO异常时抛出 + */ + public static MultipartFile downloadFileAsMultipart(String fileUrl) throws IOException { + if (fileUrl == null || fileUrl.trim().isEmpty()) { + throw new IllegalArgumentException("文件URL不能为空"); + } + + URL url = new URL(fileUrl); + URLConnection connection = url.openConnection(); + + // 设置连接和读取超时 + connection.setConnectTimeout(CONNECT_TIMEOUT); + connection.setReadTimeout(READ_TIMEOUT); + + // 设置请求头,模拟浏览器行为(避免部分服务器拒绝非浏览器请求) + connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"); + + // 1. 获取文件名(从响应头或URL提取) + String fileName = getFileNameFromUrl(fileUrl, connection); + // 2. 获取文件MIME类型(响应头中获取,默认二进制流) + String contentType = connection.getContentType() == null ? "application/octet-stream" : connection.getContentType(); + // 3. 读取文件字节内容 + byte[] fileBytes = readFileBytes(connection.getInputStream()); + + // 4. 使用自定义MultipartFile实现类封装(不依赖Spring Test) + return new CustomMultipartFile( + "file", // 表单字段名(与上传接口的@RequestParam("file")对应) + fileName, // 文件名 + contentType, // 文件MIME类型 + fileBytes // 文件字节内容 + ); + } + + /** + * 从输入流读取文件字节数组 + */ + private static byte[] readFileBytes(InputStream inputStream) throws IOException { + try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { + byte[] buffer = new byte[BUFFER_SIZE]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + return outputStream.toByteArray(); + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } + + /** + * 从URL和响应头中提取文件名 + */ + private static String getFileNameFromUrl(String fileUrl, URLConnection connection) { + // 优先从响应头的Content-Disposition获取(如:attachment;filename="test.pdf") + String disposition = connection.getHeaderField("Content-Disposition"); + if (disposition != null && disposition.contains("filename=")) { + String fileName = disposition.substring(disposition.indexOf("filename=") + 9); + // 处理文件名中的引号(如去掉"test.pdf"的双引号) + return fileName.replaceAll("^[\"']|[\"']$", ""); + } + + // 从URL路径提取(如:https://xxx.com/abc/test.pdf → test.pdf) + String urlPath = fileUrl.split("\\?")[0]; // 去掉URL参数部分 + if (urlPath.contains("/")) { + String fileName = urlPath.substring(urlPath.lastIndexOf("/") + 1); + if (!fileName.isEmpty()) { + return fileName; + } + } + + // 兜底:生成默认文件名(避免空文件名) + return "downloaded_file_" + System.currentTimeMillis(); + } + + /** + * 自定义MultipartFile实现类(不依赖Spring Test,适用于生产环境) + * 覆盖核心方法,满足文件上传场景需求 + */ + private static class CustomMultipartFile implements MultipartFile { + private final String fieldName; // 表单字段名 + private final String originalFilename; // 原始文件名 + private final String contentType; // MIME类型 + private final byte[] content; // 文件字节内容 + + public CustomMultipartFile(String fieldName, String originalFilename, String contentType, byte[] content) { + this.fieldName = fieldName; + this.originalFilename = originalFilename; + this.contentType = contentType; + this.content = content != null ? content : new byte[0]; + } + + @NotNull + @Override + public String getName() { + return fieldName; // 表单字段名(如"file") + } + + @Override + public String getOriginalFilename() { + return originalFilename; // 原始文件名(如"test.pdf") + } + + @Override + public String getContentType() { + return contentType; // MIME类型(如"application/pdf") + } + + @Override + public boolean isEmpty() { + return content.length == 0; // 判断文件是否为空 + } + + @Override + public long getSize() { + return content.length; // 文件大小(字节数) + } + + @NotNull + @Override + public byte[] getBytes() throws IOException { + return content.clone(); // 返回文件字节数组(克隆避免外部修改) + } + + @NotNull + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(content); // 字节流(用于读取文件内容) + } + + // 以下方法在文件上传场景中极少用到,默认实现即可 + @Override + public void transferTo(@NotNull java.io.File dest) throws IOException, IllegalStateException { + throw new UnsupportedOperationException("暂不支持transferTo方法"); + } + } +} diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/tmpltp/TemplateInstanceDO.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/tmpltp/TemplateInstanceDO.java index b2eb6bc..59dae5b 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/tmpltp/TemplateInstanceDO.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/dal/dataobject/tmpltp/TemplateInstanceDO.java @@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; import com.zt.plat.framework.mybatis.core.dataobject.BusinessBaseDO; import lombok.*; @@ -75,6 +76,7 @@ public class TemplateInstanceDO extends BusinessBaseDO { /** * 发布时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private LocalDateTime publishTime; // /** // * 公司编号 diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceService.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceService.java index 493ea66..2cd658c 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceService.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceService.java @@ -9,6 +9,7 @@ import jakarta.validation.*; import com.zt.plat.framework.common.pojo.PageResult; import com.zt.plat.framework.common.pojo.PageParam; import jakarta.validation.constraints.NotEmpty; +import org.springframework.web.multipart.MultipartFile; /** * 模板实例 Service 接口 @@ -82,4 +83,6 @@ public interface TemplateInstanceService { Map getVersion(String id); List listByCdg(String cdg); + + Map saveFile(MultipartFile file, String id); } diff --git a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceServiceImpl.java b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceServiceImpl.java index 9f4223b..ac9b337 100644 --- a/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceServiceImpl.java +++ b/zt-module-base/zt-module-base-server/src/main/java/com/zt/plat/module/base/service/tmpltp/TemplateInstanceServiceImpl.java @@ -13,6 +13,7 @@ import com.zt.plat.framework.tenant.core.context.CompanyContextHolder; import com.zt.plat.module.base.controller.admin.templtp.vo.*; import com.zt.plat.module.base.dal.dataobject.tmpltp.*; import com.zt.plat.module.base.dal.mysql.tmpltp.*; +import com.zt.plat.module.infra.api.file.FileApi; import com.zt.plat.module.tmpltp.enums.DeleteStatusEnum; import com.zt.plat.module.tmpltp.enums.PublishStatusEnum; import com.zt.plat.module.tmpltp.enums.TmplStsEnum; @@ -22,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import org.springframework.web.multipart.MultipartFile; import java.time.LocalDateTime; import java.util.*; @@ -42,7 +44,8 @@ import static com.zt.plat.module.tmpltp.enums.ErrorCodeConstants.*; @Service @Validated public class TemplateInstanceServiceImpl implements TemplateInstanceService { - + @Resource + private FileApi fileApi; @Resource private TemplateInstanceMapper templateInstanceMapper; @Resource @@ -373,6 +376,12 @@ private String incrementVersion(String currentVersion) { return templateInstanceRespVOS; } + @Override + public Map saveFile(MultipartFile file, String id) { + + return Map.of(); + } + @Override public void getDetailedInfo(TemplateInstanceRespVO templateInstanceRespVO) {