diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsFilesController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsFilesController.java index 8a97f6a..be3e05c 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsFilesController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsFilesController.java @@ -375,6 +375,26 @@ public class TsFilesController { } + /********************************** + * 用途说明: 查询本地和备份空间结构树 + * 参数说明 taskId 节点ID + * 参数说明 nodeId 任务ID + * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据 + ***********************************/ + @Log(module = "实验数据管理", value = "查询本地和备份空间结构树!") + @PostMapping("/listLocalAndBackup") + @ApiOperation("查询本地和备份空间结构树") + public ResponseResult listLocalAndBackup(String taskId, String nodeId) { + + + if (StrUtil.isBlank(taskId) && StrUtil.isBlank(nodeId)) { + return ResponseResult.error("参数为空"); + } + //查询本地树和minio树 + DualTreeResponse response = tsFilesService.listLocalAndBackup(taskId, nodeId); + return ResponseResult.successData(response); + } + /********************************** * 用途说明: 查询本地结构树 diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java index e40b216..9d826ad 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsFilesService.java @@ -207,4 +207,12 @@ public interface ITsFilesService extends IService { * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据 ***********************************/ DualTreeResponse listBackupTree(String taskId, String nodeId, String id); + + /********************************** + * 用途说明: 查询本地和备份空间结构树 + * 参数说明 taskId 节点ID + * 参数说明 nodeId 任务ID + * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据 + ***********************************/ + DualTreeResponse listLocalAndBackup(String taskId, String nodeId); } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java index ae76023..31067e7 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsFilesServiceImpl.java @@ -2234,24 +2234,43 @@ public class TsFilesServiceImpl extends ServiceImpl impl } } - // 保留Unix权限 + // 保留Unix权限(仅在非Windows系统生效) if (!System.getProperty("os.name").toLowerCase().contains("win")) { - Files.setPosixFilePermissions(targetPath, - PosixFilePermissions.fromString(getPosixMode(entry.getMode()))); + try { + Files.setPosixFilePermissions( + targetPath, + PosixFilePermissions.fromString(getPosixMode(entry.getMode())) + ); + } catch (IllegalArgumentException e) { + // 捕获非法权限格式异常,避免进程终止 + System.err.println("警告: 无法设置权限 [" + entry.getMode() + "] 文件: " + targetPath); + } } } } return destRoot.toFile(); } - // 转换Unix权限位 + /** + * 将TAR文件条目的权限位转换为POSIX格式字符串 + * (修正1:移除空格,修正2:屏蔽高位) + */ private String getPosixMode(int mode) { - return String.format("%s%s%s %s%s%s %s%s%s", - (mode & 0400) != 0 ? "r" : "-", (mode & 0200) != 0 ? "w" : "-", (mode & 0100) != 0 ? "x" : "-", - (mode & 0040) != 0 ? "r" : "-", (mode & 0020) != 0 ? "w" : "-", (mode & 0010) != 0 ? "x" : "-", - (mode & 0004) != 0 ? "r" : "-", (mode & 0002) != 0 ? "w" : "-", (mode & 0001) != 0 ? "x" : "-"); + // 仅保留低9位权限信息(用户/组/其他) + mode &= 0777; + return String.format("%s%s%s%s%s%s%s%s%s", + (mode & 0400) != 0 ? "r" : "-", // 用户读 + (mode & 0200) != 0 ? "w" : "-", // 用户写 + (mode & 0100) != 0 ? "x" : "-", // 用户执行 + (mode & 0040) != 0 ? "r" : "-", // 组读 + (mode & 0020) != 0 ? "w" : "-", // 组写 + (mode & 0010) != 0 ? "x" : "-", // 组执行 + (mode & 0004) != 0 ? "r" : "-", // 其他读 + (mode & 0002) != 0 ? "w" : "-", // 其他写 + (mode & 0001) != 0 ? "x" : "-"); // 其他执行 } + /** * 验证目标路径安全性(防止路径穿越攻击) */ @@ -4284,6 +4303,59 @@ public class TsFilesServiceImpl extends ServiceImpl impl // return new DualTreeResponse(localTrees, minioTrees); // } + /********************************** + * 用途说明: 查询本地和备份空间结构树 + * 参数说明 taskId 节点ID + * 参数说明 nodeId 任务ID + * 返回值说明: com.yfd.platform.config.ResponseResult 返回双树数据 + ***********************************/ + @Override + public DualTreeResponse listLocalAndBackup(String taskId, String nodeId) { + // 记录方法入参 + LOGGER.info("Starting to build dual trees for taskId={}, nodeId={}", taskId, nodeId); + // 1. 批量查询所有相关节点 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("task_id", taskId) + .eq("node_id", nodeId); + List allNodes = tsFilesMapper.selectList(queryWrapper); + + // 2. 构建内存索引提升查询效率 + Map> parentChildrenMap = allNodes.stream() + .collect(Collectors.groupingBy(TsFiles::getParentId)); + LOGGER.debug("使用{}个条目构建父子映射", parentChildrenMap.size()); + + // 3. 双树构建容器 + List localTrees = new ArrayList<>(); + List minioTrees = new ArrayList<>(); + + // 4. 从顶级节点(parentId为00)开始构建树 + List rootNodes = parentChildrenMap.get("00"); + if (rootNodes == null || rootNodes.isEmpty()) { + LOGGER.warn("找不到的根节点 taskId={}, nodeId={}", taskId, nodeId); + return new DualTreeResponse(localTrees, minioTrees); + } + + if (rootNodes != null) { + for (TsFiles rootNode : rootNodes) { + // 构建本地树 + TreeDTO localTree = buildTree(rootNode, parentChildrenMap, true); + if (localTree != null) { + localTrees.add(localTree); + LOGGER.debug("添加了本地树节点: {}", localTree.getId()); + } + + // 构建Minio树 + TreeDTO minioTree = buildTree(rootNode, parentChildrenMap, false); + if (minioTree != null) { + minioTrees.add(minioTree); + LOGGER.debug("添加了MINIO树节点: {}", minioTree.getId()); + } + } + } + LOGGER.info("Tree construction completed. Local nodes: {}, MinIO nodes: {}", localTrees.size(), minioTrees.size()); + return new DualTreeResponse(localTrees, minioTrees); + } + /** * 递归构建树形结构(内存操作,不再查询数据库) *