From 43aab58c9ecb1203770ba382efbdbae299ca87ec Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期一, 26 十月 2026 15:12:31 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/dev_business' into dev_business
---
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemAgentImportBridgeService.java | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 169 insertions(+), 0 deletions(-)
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemAgentImportBridgeService.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemAgentImportBridgeService.java
new file mode 100644
index 0000000..3d7629d
--- /dev/null
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/storage/SystemAgentImportBridgeService.java
@@ -0,0 +1,169 @@
+package cn.iocoder.yudao.module.system.service.storage;
+
+import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.module.system.controller.admin.storage.vo.SystemStorageAttachmentSaveReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemAgentImportSessionDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageAttachmentDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageBlobDO;
+import cn.iocoder.yudao.module.system.dal.mysql.storage.SystemAgentImportSessionMapper;
+import cn.iocoder.yudao.module.system.dal.mysql.storage.SystemStorageAttachmentMapper;
+import cn.iocoder.yudao.module.system.framework.agent.AgentBridgeException;
+import cn.iocoder.yudao.module.system.framework.storage.config.StorageProperties;
+import jakarta.annotation.Resource;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HexFormat;
+import java.util.List;
+import java.util.Objects;
+
+@Service
+public class SystemAgentImportBridgeService {
+
+ public static final long MAX_FILE_BYTES = 8L * 1024 * 1024;
+ public static final String RECORD_TYPE = "agent_import_session";
+
+ @Resource
+ private SystemAgentImportSessionMapper sessionMapper;
+ @Resource
+ private SystemStorageAttachmentMapper attachmentMapper;
+ @Resource
+ private SystemStorageBlobService blobService;
+ @Resource
+ private SystemStorageAttachmentService attachmentService;
+ @Resource
+ private StorageProperties storageProperties;
+
+ @Transactional(rollbackFor = Exception.class)
+ public Long createSession() {
+ Long userId = SecurityFrameworkUtils.getLoginUserId();
+ if (userId == null) {
+ throw new AgentBridgeException(HttpStatus.UNAUTHORIZED, "UNAUTHORIZED", "鏈櫥褰曟垨鐧诲綍宸茶繃鏈�");
+ }
+ SystemAgentImportSessionDO session = new SystemAgentImportSessionDO();
+ session.setOwnerUserId(userId);
+ session.setStatus("active");
+ sessionMapper.insert(session);
+ return session.getId();
+ }
+
+ @Transactional(rollbackFor = Exception.class)
+ public Long bindAttachment(Long sessionId, Long blobId) {
+ requireOwnedSession(sessionId);
+ SystemStorageBlobDO blob = blobService.getStorageBlob(blobId);
+ requireOwnedBlob(blob);
+ SystemStorageAttachmentSaveReqVO req = new SystemStorageAttachmentSaveReqVO();
+ req.setApplication("file");
+ req.setRecordType(RECORD_TYPE);
+ req.setRecordId(sessionId);
+ SystemStorageAttachmentSaveReqVO.BlobItem item = new SystemStorageAttachmentSaveReqVO.BlobItem();
+ item.setBlobId(blobId);
+ req.setBlobItems(List.of(item));
+ attachmentService.bindAttachments(req);
+ // 閫氱敤 bind 瀵瑰悓涓�浼氳瘽鏄浛鎹㈣涔夛細閲嶅缁戝畾鏃舵棫闄勪欢琛屼細琚垹闄ゃ��
+ return attachmentMapper.selectListByApplicationAndRecordTypeAndRecordId("file", RECORD_TYPE, sessionId)
+ .stream().filter(row -> blobId.equals(row.getStorageBlobId()))
+ .map(SystemStorageAttachmentDO::getId).findFirst()
+ .orElseThrow(() -> new AgentBridgeException(HttpStatus.CONFLICT, "ATTACHMENT_BIND_FAILED",
+ "闄勪欢缁戝畾澶辫触锛岃閲嶆柊涓婁紶鍚庡啀璇�", true, null));
+ }
+
+ /** 鍒犻櫎琛ュ綍闄勪欢鎵�灞炰細璇濓細闄勪欢鍏崇郴銆乥lob 璁板綍涓庣鐩樻枃浠朵竴骞舵竻鐞嗭紝闄勪欢涓嶅瓨鍦ㄦ椂骞傜瓑杩斿洖銆� */
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteImportAttachment(Long attachmentId) {
+ SystemStorageAttachmentDO attachment = attachmentMapper.selectById(attachmentId);
+ if (attachment == null) {
+ return;
+ }
+ if (!RECORD_TYPE.equals(attachment.getRecordType())) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_FORBIDDEN", "闄勪欢涓嶅彲璁块棶");
+ }
+ Long sessionId = attachment.getRecordId();
+ requireOwnedSession(sessionId);
+ // 鎸変細璇濇暣鎵瑰垹闄わ紝鍚屼竴浼氳瘽鍐呰鏇挎崲鐨勬棫闄勪欢琛屼笌 blob 鏂囦欢閮戒笉浼氭畫鐣�
+ attachmentService.deleteAttachmentsByRecordTypeAndRecordId(RECORD_TYPE, sessionId);
+ sessionMapper.deleteById(sessionId);
+ }
+
+ public SystemAgentAttachmentRef requireOwnedAttachmentRef(Long attachmentId) {
+ SystemStorageAttachmentDO attachment = attachmentMapper.selectById(attachmentId);
+ if (attachment == null) {
+ throw new AgentBridgeException(HttpStatus.CONFLICT, "ATTACHMENT_REPLACED",
+ "闄勪欢宸插け鏁堬紙鍙兘琚噸鏂颁笂浼犳浛鎹級锛岃閲嶆柊涓婁紶鍚庡啀璇�", true, null);
+ }
+ if (!RECORD_TYPE.equals(attachment.getRecordType())) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_FORBIDDEN", "闄勪欢涓嶅彲璁块棶");
+ }
+ requireOwnedSession(attachment.getRecordId());
+ SystemStorageBlobDO blob = blobService.getStorageBlob(attachment.getStorageBlobId());
+ requireOwnedBlob(blob);
+ Path file = resolveBlobFile(blob);
+ String filename = blob.getOriginalFilename();
+ if (filename == null || filename.isBlank()) {
+ filename = "attachment";
+ }
+ return new SystemAgentAttachmentRef(attachmentId, attachment.getRecordId(), filename,
+ blob.getByteSize(), file);
+ }
+
+ public String sha256OfAttachment(Long attachmentId) {
+ SystemAgentAttachmentRef ref = requireOwnedAttachmentRef(attachmentId);
+ try (InputStream in = Files.newInputStream(ref.path())) {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ byte[] buffer = new byte[8192];
+ long total = 0;
+ int read;
+ while ((read = in.read(buffer)) != -1) {
+ total += read;
+ if (total > MAX_FILE_BYTES) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "FILE_TOO_LARGE", "闄勪欢瓒呰繃 8 MiB");
+ }
+ digest.update(buffer, 0, read);
+ }
+ return HexFormat.of().formatHex(digest.digest());
+ } catch (IOException ex) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_UNREADABLE", "闄勪欢涓嶅彲璁块棶");
+ } catch (NoSuchAlgorithmException ex) {
+ throw new IllegalStateException("SHA-256 涓嶅彲鐢�", ex);
+ }
+ }
+
+ private Path resolveBlobFile(SystemStorageBlobDO blob) {
+ try {
+ Path root = Path.of(storageProperties.getPath()).toRealPath();
+ Path file = root.resolve(blob.getPath() == null ? "" : blob.getPath())
+ .resolve(blob.getUidFilename()).toRealPath();
+ if (!file.startsWith(root) || !Files.isRegularFile(file)
+ || Files.size(file) > MAX_FILE_BYTES) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_UNREADABLE", "闄勪欢涓嶅彲璁块棶");
+ }
+ return file;
+ } catch (IOException ex) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "ATTACHMENT_UNREADABLE", "闄勪欢涓嶅彲璁块棶");
+ }
+ }
+
+ private void requireOwnedSession(Long sessionId) {
+ SystemAgentImportSessionDO session = sessionMapper.selectById(sessionId);
+ Long userId = SecurityFrameworkUtils.getLoginUserId();
+ if (session == null || userId == null || !Objects.equals(session.getOwnerUserId(), userId)
+ || !"active".equals(session.getStatus())) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "SESSION_FORBIDDEN", "琛ュ綍浼氳瘽涓嶅彲璁块棶");
+ }
+ }
+
+ private void requireOwnedBlob(SystemStorageBlobDO blob) {
+ Long userId = SecurityFrameworkUtils.getLoginUserId();
+ if (blob == null || userId == null || !String.valueOf(userId).equals(blob.getCreator())
+ || blob.getByteSize() == null || blob.getByteSize() > MAX_FILE_BYTES) {
+ throw new AgentBridgeException(HttpStatus.FORBIDDEN, "BLOB_FORBIDDEN", "鏂囦欢涓嶅彲璁块棶鎴栬秴杩� 8 MiB");
+ }
+ }
+}
--
Gitblit v1.9.3