试验任务扫描

This commit is contained in:
lilin 2025-05-27 09:48:19 +08:00
parent e598ff9cae
commit 0ce8d92a5a
3 changed files with 306 additions and 82 deletions

View File

@ -2,6 +2,9 @@ package com.yfd.platform.modules.experimentalData.mapper;
import com.yfd.platform.modules.experimentalData.domain.TsFiles;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
@ -13,4 +16,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface TsFilesMapper extends BaseMapper<TsFiles> {
int batchInsertTsFiles(List<TsFiles> tsFilesToCreate);
int updateParentIdByPathHierarchy(@Param("taskId") String taskId, @Param("nodeId") String nodeId);
}

View File

@ -1,6 +1,7 @@
package com.yfd.platform.modules.experimentalData.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@ -21,6 +22,8 @@ import com.yfd.platform.modules.specialDocument.domain.Files;
import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.yfd.platform.modules.specialDocument.domain.Project;
import com.yfd.platform.modules.storage.context.StorageSourceContext;
import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper;
import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig;
import com.yfd.platform.modules.storage.model.enums.FileTypeEnum;
import com.yfd.platform.modules.storage.model.request.BatchDeleteRequest;
import com.yfd.platform.modules.storage.model.request.NewFolderRequest;
@ -30,6 +33,7 @@ import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.utils.StringUtils;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.val;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -86,6 +90,10 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
@Resource
private StorageSourceService storageSourceService;
@Resource
private StorageSourceConfigMapper storageSourceConfigMapper;
//顶级父节点 Top level parent node
public static final String TOP_LEVEL_PARENT_NODE = "00";
@ -647,6 +655,21 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
TsTask tsTask = tsTaskMapper.selectById(id);
//文件的第一层是节点 下面的层级是文件夹
//获取文件列表
String absolutePath = "/" + tsTask.getTaskName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath);
@ -664,15 +687,6 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
if (fileItemList.size() == 0) {
throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。");
}
// //获取数据库父节点为0的数据 任务ID 上级节点时00
// List<TsNodes> tsNodes = tsNodesMapper.selectList(new LambdaQueryWrapper<TsNodes>().eq(TsNodes::getParentId, "00").eq(TsNodes::getTaskId, id));
//
// // 步骤 1提取现有的 nodeName
// Set<String> existingNodeNames = tsNodes.stream().map(TsNodes::getNodeName).collect(Collectors.toSet());
//
// // 步骤 2筛选新增数据 找到需要新增到数据库的文件夹 这个属于第一层架
// List<FileItemResult> fileItemNewList = fileItemList.stream().filter(fileItem -> !existingNodeNames.contains(fileItem.getName())).collect(Collectors.toList());
firstLayerData(fileItemList, id);
return "扫描完成";
@ -705,27 +719,6 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
}
}
// else {
// //获取节点名称
// String nodeName = getLastPathSegment(item.getPath());
// //获取节点信息 主要用到ID
// QueryWrapper<Nodes> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("node_name", nodeName);
// queryWrapper.eq("parent_id", TOP_LEVEL_PARENT_NODE);
// Nodes node = nodesMapper.selectOne(queryWrapper);
//
// //新增之前先查询
// LambdaQueryWrapper<Files> queryWrapper1 = new LambdaQueryWrapper<>();
// queryWrapper1.eq(Files::getProjectId, projectId);
// queryWrapper1.eq(Files::getNodeId, node.getId());
// queryWrapper1.eq(Files::getFilePath, item.getPath());
// queryWrapper1.eq(Files::getFileName, item.getName());
// Files files = filesMapper.selectOne(queryWrapper1);
// if (files == null) {
// //保存文件信息
// saveFiles(projectId, node.getId(), item.getPath(), item.getName(), String.valueOf(item.getSize()));
// }
// }
}
}
@ -739,62 +732,264 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
*/
private void otherLevelsData(String taskId, String nodeId, String nodeName, String path, String parentId) throws Exception {
//通过节点的路径加名称 查询下面的文件及文件夹
String absolutePath = path + nodeName + "/";
//获取文件列表
FileListRequest fileListRequest = buildFileRequest(absolutePath);
String storageKey = fileListRequest.getStorageKey();
Integer storageId = storageSourceService.findIdByKey(storageKey);
if (storageId == null) {
throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey);
}
// 处理请求参数默认值
fileListRequest.handleDefaultValue();
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
for (FileItemResult item : fileItemList) {
//思路就是 如果是文件夹 就查询一下 没有就新增 新的的时候递归往下走
if (item.getType() == FileTypeEnum.FOLDER) {
//先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称
LambdaQueryWrapper<TsFiles> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsFiles::getTaskId, taskId);
queryWrapper.eq(TsFiles::getNodeId, nodeId);
queryWrapper.eq(TsFiles::getParentId, parentId);
queryWrapper.eq(TsFiles::getFileName, item.getName());
queryWrapper.eq(TsFiles::getWorkPath, item.getPath());
TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper);
//如果没有 新增 并且递归
if (tsFiles == null) {
//保存文件
TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FOLDER", String.valueOf(item.getSize()));
otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFilesData.getId());
// 存储所有目录和文件的列表
List<TsFiles> tsFilesToCreate = new ArrayList<>();
} else {
otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFiles.getId());
}
} else {
//todo 如果是文件 直接新增就可以了 不需要其他的操作
//先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称
LambdaQueryWrapper<TsFiles> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsFiles::getTaskId, taskId);
queryWrapper.eq(TsFiles::getNodeId, nodeId);
queryWrapper.eq(TsFiles::getParentId, parentId);
queryWrapper.eq(TsFiles::getFileName, item.getName());
queryWrapper.eq(TsFiles::getWorkPath, item.getPath());
TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper);
if (tsFiles == null) {
// 设置当前时间
LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp
Timestamp currentTime = Timestamp.valueOf(now);
// 获取文件大小字节
long fileSizeInBytes = item.getSize();
// 转换为 MB 并保留两位小数
double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
// 查询本地文件路径根目录 E:\yun
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "filePath");
queryWrapper.eq("type", "local");
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//获取文件列表 这个地方path+name
File projectDir = new File(storageSourceConfig.getValue()+path+nodeName);
// 获取所有子目录
List<File> allSubDirs = new ArrayList<>();
getAllSubDirectories(projectDir, allSubDirs);
String storageSourceConfigPath = storageSourceConfig.getValue().replace("\\", "/");
// 批量处理子目录
long startBuildNodes = System.currentTimeMillis();
for (File subDir : allSubDirs) {
String normalizedSubDirPath = subDir.getAbsolutePath().replace("\\", "/");
// 获取上一级目录
String parentPath = normalizedSubDirPath.substring(0, normalizedSubDirPath.lastIndexOf("/"));
// 去掉 D:/yun 部分
String finalPath = parentPath.replace(storageSourceConfigPath, "");
//保存文件信息
TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FILE", fileSizeFormatted);
LOGGER.info("保存文件信息:{}", item.getPath() + item.getName());
TsFiles tsFiles1 = new TsFiles();
//任务
tsFiles1.setTaskId(taskId);
//节点
tsFiles1.setNodeId(nodeId);
//文件 文件夹 区分
tsFiles1.setIsFile("FOLDER");
//上级ID
tsFiles1.setParentId("00");
//文件名称
tsFiles1.setFileName(subDir.getName());
//工作空间路径
tsFiles1.setWorkPath(ensurePathFormat(finalPath));
tsFiles1.setUploadTime(currentTime);
if ("null".equals(String.valueOf(subDir.length()))) {
tsFiles1.setFileSize("0.001");
} else {
//文件大小
if ("0.000".equals(String.valueOf(subDir.length()))) {
tsFiles1.setFileSize("0.001");
} else {
tsFiles1.setFileSize(String.valueOf(subDir.length()));
}
}
tsFilesToCreate.add(tsFiles1);
}
LOGGER.info("[构建文件表中的文件夹列表] 耗时 {} ms | 待处理数量: {} 条",
System.currentTimeMillis() - startBuildNodes,
tsFilesToCreate.size());
// 获取所有文件
List<File> allFiles = new ArrayList<>();
getAllFiles(projectDir, allFiles);
System.out.println("allFiles=" + allFiles.size());
long startBuildFiles = System.currentTimeMillis();
// 批量处理文件
for (File file : allFiles) {
String normalizedFilesPath = file.getAbsolutePath().replace("\\", "/");
// 获取上一级目录
String parentPath = normalizedFilesPath.substring(0, normalizedFilesPath.lastIndexOf("/"));
// 去掉 D:/yun 部分
String finalPath = parentPath.replace(storageSourceConfigPath, "");
//保存文件信息
TsFiles tsFiles1 = new TsFiles();
tsFiles1.setId(IdUtil.fastSimpleUUID());
//任务
tsFiles1.setTaskId(taskId);
//节点
tsFiles1.setNodeId(nodeId);
//文件 文件夹 区分
tsFiles1.setIsFile("FILE");
//上级ID
tsFiles1.setParentId("00");
//文件名称
tsFiles1.setFileName(file.getName());
//工作空间路径
tsFiles1.setWorkPath(ensurePathFormat(finalPath));
tsFiles1.setUploadTime(currentTime);
if ("null".equals(String.valueOf(file.length()))) {
tsFiles1.setFileSize("0.001");
} else {
//文件大小
if ("0.000".equals(String.valueOf(file.length()))) {
tsFiles1.setFileSize("0.001");
} else {
tsFiles1.setFileSize(String.valueOf(file.length()));
}
}
tsFilesToCreate.add(tsFiles1);
}
LOGGER.info("[构建文件表中的文件列表] 耗时 {} ms | 待处理数量: {} 条",
System.currentTimeMillis() - startBuildFiles,
tsFilesToCreate.size());
// 批量插入文件表忽略重复
if (!tsFilesToCreate.isEmpty()) {
long startBatchInsertFiles = System.currentTimeMillis();
int affectedRowsFiles = tsFilesMapper.batchInsertTsFiles(tsFilesToCreate);
LOGGER.info("[批量插入试验任务文件表] 耗时 {} ms | 实际新增数量: {} 条",
System.currentTimeMillis() - startBatchInsertFiles,
affectedRowsFiles);
}
// 记录开始时间
long startTimeFiles = System.currentTimeMillis();
// 执行更新操作 taskId, String nodeId
int affectedLevelFilesRows = tsFilesMapper.updateParentIdByPathHierarchy(taskId,nodeId);
// 记录结束时间
long endTimeFiles = System.currentTimeMillis();
// 计算耗时
long costTimeFiles = endTimeFiles - startTimeFiles;
// 打印日志
LOGGER.info("文件表中的节点ID更新完成影响 {} 行,总耗时 {} 毫秒", affectedLevelFilesRows, costTimeFiles);
// //获取文件列表
// String absolutePath =path + "/" + nodeName + "/";
// //获取当前登录用户 上传人是当前登录人
// UsernamePasswordAuthenticationToken authentication =
// (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
// LoginUser loginuser = null;
// if (authentication != null) {
// loginuser = (LoginUser) authentication.getPrincipal();
// }
// //登录人
// String uploader = null;
// if (loginuser != null) {
// uploader = loginuser.getUsername();
// }
// // 设置当前时间
// LocalDateTime now = LocalDateTime.now();
// // 转换为 Timestamp
// Timestamp currentTime = Timestamp.valueOf(now);
//
//
//
//
//
// //获取文件列表
// FileListRequest fileListRequest = buildFileRequest(absolutePath);
// String storageKey = fileListRequest.getStorageKey();
// Integer storageId = storageSourceService.findIdByKey(storageKey);
// if (storageId == null) {
// throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey);
// }
// // 处理请求参数默认值
// fileListRequest.handleDefaultValue();
// AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
// //todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
// List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
//
// for (FileItemResult item : fileItemList) {
// //思路就是 如果是文件夹 就查询一下 没有就新增 新的的时候递归往下走
// if (item.getType() == FileTypeEnum.FOLDER) {
// //先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称
// LambdaQueryWrapper<TsFiles> queryWrapper1 = new LambdaQueryWrapper<>();
// queryWrapper1.eq(TsFiles::getTaskId, taskId);
// queryWrapper1.eq(TsFiles::getNodeId, nodeId);
// queryWrapper1.eq(TsFiles::getParentId, parentId);
// queryWrapper1.eq(TsFiles::getFileName, item.getName());
// queryWrapper1.eq(TsFiles::getWorkPath, item.getPath());
// TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper1);
// //如果没有 新增 并且递归
// if (tsFiles == null) {
// //保存文件
// TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FOLDER", String.valueOf(item.getSize()));
// otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFilesData.getId());
//
// } else {
// otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFiles.getId());
// }
// } else {
// //todo 如果是文件 直接新增就可以了 不需要其他的操作
// //先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称
// LambdaQueryWrapper<TsFiles> queryWrapper2 = new LambdaQueryWrapper<>();
// queryWrapper2.eq(TsFiles::getTaskId, taskId);
// queryWrapper2.eq(TsFiles::getNodeId, nodeId);
// queryWrapper2.eq(TsFiles::getParentId, parentId);
// queryWrapper2.eq(TsFiles::getFileName, item.getName());
// queryWrapper2.eq(TsFiles::getWorkPath, item.getPath());
// TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper2);
// if (tsFiles == null) {
//
// // 获取文件大小字节
// long fileSizeInBytes = item.getSize();
// // 转换为 MB 并保留两位小数
// double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
// String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
//
// //保存文件信息
// TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FILE", fileSizeFormatted);
// LOGGER.info("保存文件信息:{}", item.getPath() + item.getName());
// }
// }
// }
}
/**
* 确保路径格式为以 "/" 开头和结尾例如 "/data/test/"
* 若路径为空或非法返回根路径 "/"
*/
private String ensurePathFormat(String path) {
if (StringUtils.isBlank(path)) {
return "/";
}
// 统一替换反斜杠为斜杠兼容 Windows 路径
String normalized = path.replaceAll("\\\\", "/");
// 去掉多余的斜杠
normalized = normalized.replaceAll("/{2,}", "/");
// 确保以 "/" 开头
if (!normalized.startsWith("/")) {
normalized = "/" + normalized;
}
// 确保以 "/" 结尾
if (!normalized.endsWith("/")) {
normalized += "/";
}
return normalized;
}
private void getAllSubDirectories(File dir, List<File> subDirs) {
File[] files = dir.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
subDirs.add(file);
getAllSubDirectories(file, subDirs);
}
}
}
}
private void getAllFiles(File dir, List<File> files) {
File[] fileList = dir.listFiles();
if (fileList != null) {
for (File file : fileList) {
if (file.isFile()) {
files.add(file);
} else if (file.isDirectory()) {
getAllFiles(file, files);
}
}
}

View File

@ -2,4 +2,27 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yfd.platform.modules.experimentalData.mapper.TsFilesMapper">
<!-- 批量插入试验任务文件表(存在唯一键冲突时忽略) -->
<insert id="batchInsertTsFiles">
INSERT INTO ts_files
(id,node_id, task_id, is_file, parent_id, file_name, file_size, work_path,upload_time)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.id},#{item.nodeId}, #{item.taskId}, #{item.isFile}, #{item.parentId},
#{item.fileName}, #{item.fileSize}, #{item.workPath}, #{item.uploadTime})
</foreach>
</insert>
<update id="updateParentIdByPathHierarchy">
UPDATE ts_files a
LEFT JOIN ts_files b
ON b.task_id = a.task_id
AND b.node_id = a.node_id
AND a.work_path = CONCAT( b.work_path, b.file_name, '/' )
SET a.parent_id = b.id
WHERE
b.task_id = #{taskId}
AND b.node_id = #{nodeId}
</update>
</mapper>