diff --git a/java/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java b/java/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java index 20b9718..9ecede2 100644 --- a/java/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java +++ b/java/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java @@ -2,10 +2,16 @@ package com.yfd.platform.config; import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; +import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler; +import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; +import com.yfd.platform.utils.TableNameContextHolder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import java.util.HashMap; +import java.util.Map; + /****************************** * 用途说明: * 作者姓名: pcj @@ -16,11 +22,36 @@ public class MybitsPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { - MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); - mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); - return mybatisPlusInterceptor; + MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); + + // 创建动态表名拦截器 + DynamicTableNameInnerInterceptor dynamicInterceptor = new DynamicTableNameInnerInterceptor(); + + // 创建表名处理器映射 + Map handlerMap = new HashMap<>(); + + // 为 ts_files 表添加处理器 + handlerMap.put("ts_files", new TableNameHandler() { + @Override + public String dynamicTableName(String sql, String tableName) { + String taskCode = TableNameContextHolder.getTaskCode(); + if (taskCode == null || taskCode.isEmpty()) { + throw new IllegalArgumentException("任务编码不能为空"); + } + return "ts_files_" + taskCode; + } + }); + + // 设置处理器映射 + dynamicInterceptor.setTableNameHandlerMap(handlerMap); + // 添加动态表名拦截器 + interceptor.addInnerInterceptor(dynamicInterceptor); + // 添加分页拦截器 + interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); + return interceptor; } - - - } + + + + 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 adc85cc..1f2b5c6 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 @@ -167,12 +167,12 @@ public class TsFilesController { @PostMapping("/deleteTsFilesById") @ApiOperation("根据ID删除试验数据管理文档内容") @PreAuthorize("@el.check('del:tsFiles')") - public ResponseResult deleteTsFilesById(@RequestParam String id, @RequestParam String type) { - if (StrUtil.isBlank(id)) { + public ResponseResult deleteTsFilesById(@RequestParam String id, @RequestParam String type,@RequestParam String taskId) { + if (StrUtil.isBlank(id) || StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } List dataset = Arrays.asList(id); - return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type)); + return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type,taskId)); } /********************************** @@ -185,14 +185,14 @@ public class TsFilesController { @PostMapping("/deleteTsFilesByIds") @ApiOperation("批量删除试验数据管理文档内容") @PreAuthorize("@el.check('del:tsFiles')") - public ResponseResult deleteTsFilesByIds(@RequestParam String ids, @RequestParam String type) { - if (StrUtil.isBlank(ids)) { + public ResponseResult deleteTsFilesByIds(@RequestParam String ids, @RequestParam String type,@RequestParam String taskId) { + if (StrUtil.isBlank(ids) || StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } String[] splitIds = ids.split(","); // 数组转集合 List dataset = Arrays.asList(splitIds); - return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type)); + return ResponseResult.success(tsFilesService.deleteTsFilesByIds(dataset, type,taskId)); } /**************************压缩 解压缩********************************/ @@ -211,13 +211,13 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "压缩文件夹接口!") @PostMapping("/compress") @ApiOperation("压缩文件夹接口") - public ResponseResult compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path) { + public ResponseResult compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path,String taskId) { try { - if (StrUtil.isBlank(ids) && StrUtil.isBlank(compressedFormat) && StrUtil.isBlank(compressedName) && StrUtil.isBlank(compressedPath) && StrUtil.isBlank(path)) { + if (StrUtil.isBlank(ids) && StrUtil.isBlank(compressedFormat) && StrUtil.isBlank(compressedName) && StrUtil.isBlank(compressedPath) && StrUtil.isBlank(path) && StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } - return ResponseResult.success(tsFilesService.compressFolder(ids, compressedFormat, compressedName, compressedPath, covered, parentId, path)); + return ResponseResult.success(tsFilesService.compressFolder(ids, compressedFormat, compressedName, compressedPath, covered, parentId, path,taskId)); } catch (Exception e) { System.out.print("压缩异常原因" + e); return ResponseResult.error("压缩失败"); @@ -235,12 +235,12 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "解压缩接口!") @PostMapping("/decompression") @ApiOperation("解压缩接口") - public ResponseResult decompressionFolder(String id, String decompressionPath, String parentId, String path) { + public ResponseResult decompressionFolder(String id, String decompressionPath, String parentId, String path,String taskId) { try { - if (StrUtil.isBlank(id)) { + if (StrUtil.isBlank(id)|| StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } - return ResponseResult.success(tsFilesService.decompressionFolder(id, decompressionPath, parentId, path)); + return ResponseResult.success(tsFilesService.decompressionFolder(id, decompressionPath, parentId, path,taskId)); } catch (Exception e) { System.out.print("解压缩异常原因" + e); return ResponseResult.error("解压缩失败"); @@ -654,12 +654,12 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "实时获取轨迹数据!") @PostMapping("/startSimpleNavi") @ApiOperation("实时获取轨迹数据") - public ResponseResult startSimpleNavi(String id, int samTimes, String token) { + public ResponseResult startSimpleNavi(String id, int samTimes, String token,String taskId) { try { // 使用线程池异步执行任务 CompletableFuture.runAsync(() -> { try { - tsFilesService.batchSendNaviOutDataJob(id, samTimes, token); + tsFilesService.batchSendNaviOutDataJob(id, samTimes, token,taskId); } catch (Exception e) { e.printStackTrace(); } @@ -694,12 +694,12 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "查询文件内容!") @GetMapping("/api/files/content") @ApiOperation("查询文件内容") - public ResponseResult getFileContent(@RequestParam String id) { + public ResponseResult getFileContent(@RequestParam String id,String taskId) { try { - if (StrUtil.isBlank(id)) { + if (StrUtil.isBlank(id) && StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } - String content = tsFilesService.readFileContent(id); + String content = tsFilesService.readFileContent(id, taskId); return ResponseResult.successData(content); } catch (SecurityException | IOException e) { return ResponseResult.error("非法操作: " + e.getMessage()); @@ -715,12 +715,12 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "保存文件内容!") @PostMapping("/save/files/content") @ApiOperation("保存文件内容") - public ResponseResult saveFileContent(String id, String content) { + public ResponseResult saveFileContent(String id, String content,String taskId) { try { - if (StrUtil.isBlank(id) && StrUtil.isBlank(content)) { + if (StrUtil.isBlank(id) && StrUtil.isBlank(content) && StrUtil.isBlank(taskId)) { return ResponseResult.error("参数为空"); } - tsFilesService.saveFileContent(id, content); + tsFilesService.saveFileContent(id, content, taskId); return ResponseResult.success("文件保存成功"); } catch (SecurityException | IOException e) { return ResponseResult.error("非法操作: " + e.getMessage()); @@ -737,7 +737,7 @@ public class TsFilesController { @PostMapping("/batchModify") @ApiOperation("批量修改文件中多行多列的内容") public ResponseResult batchModifyFile(@RequestBody BatchModifyRequest request) throws IOException { - tsFilesService.batchUpdateFile(request.getId(), request.getModifications()); + tsFilesService.batchUpdateFile(request.getId(), request.getModifications(),request.getTaskId()); return ResponseResult.success("文件保存成功"); } @@ -749,12 +749,12 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "获取文件url!") @PostMapping("/obtainUrl") @ApiOperation("获取文件url") - public ResponseResult obtainUrl(String id, String type) { - if (StrUtil.isBlank(id) && StrUtil.isBlank(type)) { + public ResponseResult obtainUrl(String id, String type,String taskId) { + if (StrUtil.isBlank(id) && StrUtil.isBlank(type) && StrUtil.isBlank(type)) { return ResponseResult.error("参数为空"); } //查询本地树和minio树 - FileItemResult fileItemResult = tsFilesService.obtainUrl(id, type); + FileItemResult fileItemResult = tsFilesService.obtainUrl(id, type,taskId); return ResponseResult.successData(fileItemResult); } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java index 46aad55..35f67a4 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsTaskController.java @@ -184,9 +184,7 @@ public class TsTaskController { @ResponseBody //@PreAuthorize("@el.check('select:devicesignal')") public ResponseResult listTsTask() { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.orderByDesc(TsTask::getTaskStartdate); - List tsTasks = tsTaskService.list(queryWrapper); + List tsTasks = tsTaskService.listTsTask(); return ResponseResult.successData(tsTasks); } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/BatchModifyRequest.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/BatchModifyRequest.java index cd74727..62e5b79 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/BatchModifyRequest.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/BatchModifyRequest.java @@ -13,6 +13,9 @@ public class BatchModifyRequest { @NotBlank private String id; // 文件ID + @NotBlank + private String taskId; // 任务ID + @NotEmpty private List modifications; } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java index b4e73fd..d3c68c7 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/MoveCopyFileFolderRequest.java @@ -12,5 +12,6 @@ public class MoveCopyFileFolderRequest { private String newFileName; private String rename; private String type; + private String taskId; } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/Parameter.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/Parameter.java index 39a42a0..7e4f085 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/Parameter.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/Parameter.java @@ -7,5 +7,6 @@ import java.util.List; @Data public class Parameter { public List parameterLists; + public String taskId; // public String parameterLists; } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/TsTask.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/TsTask.java index 6a6c3c2..397c255 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/TsTask.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/domain/TsTask.java @@ -1,6 +1,7 @@ package com.yfd.platform.modules.experimentalData.domain; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -138,7 +139,21 @@ public class TsTask implements Serializable { @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private LocalDate taskEnddate; + /** + * 本地存储空间id + */ + private Integer localStorageId; + /** + * 备份存储空间id + */ + private Integer backupStorageId; + + /** + * 上传用到KEY:TODO 增加用于前端展示 + */ + @TableField(exist = false) + private String key; } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsFilesMapper.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsFilesMapper.java index 5f98fed..faceabb 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsFilesMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/mapper/TsFilesMapper.java @@ -21,4 +21,7 @@ public interface TsFilesMapper extends BaseMapper { int updateParentIdByPathHierarchy(@Param("taskId") String taskId, @Param("nodeId") String nodeId); int countFiles(@Param("id") String id); + + + void updateTsFileByPath(@Param("taskId") String taskId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath); } 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 3eed989..15807da 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 @@ -60,7 +60,7 @@ public interface ITsFilesService extends IService { * 参数说明 type local还是minio * 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败 ***********************************/ - String deleteTsFilesByIds(List dataset, String type); + String deleteTsFilesByIds(List dataset, String type, String taskId); /********************************** * 用途说明: 压缩文件夹接口 @@ -73,7 +73,7 @@ public interface ITsFilesService extends IService { * 参数说明 path 根目录 /项目名/节点名称/ * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ - String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId,String path) throws FileNotFoundException; + String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId,String path,String taskId) throws FileNotFoundException; /********************************** * 用途说明: 解压缩接口 @@ -83,7 +83,7 @@ public interface ITsFilesService extends IService { * 参数说明 path 根目录 /项目名/节点名称/ * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ - String decompressionFolder(String id, String decompressionPath, String parentId, String path); + String decompressionFolder(String id, String decompressionPath, String parentId, String path,String taskId); /********************************** * 用途说明: 将文件上传到备份空间 @@ -144,7 +144,7 @@ public interface ITsFilesService extends IService { * 参数说明 token SSE连接的token * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ - void batchSendNaviOutDataJob(String id, int samTimes, String token); + void batchSendNaviOutDataJob(String id, int samTimes, String token,String taskId); /** * 查询文件内容接口 @@ -152,7 +152,7 @@ public interface ITsFilesService extends IService { * @param id 文件的id * @return 文件内容的纯文本(UTF-8 编码) */ - String readFileContent(String id) throws IOException; + String readFileContent(String id,String taskId) throws IOException; /********************************** * 用途说明: 保存文件内容接口 @@ -160,14 +160,14 @@ public interface ITsFilesService extends IService { * 参数说明 content 新的文件内容(HTML/文本) * 返回值说明: com.yfd.platform.config.ResponseResult操作结果 ***********************************/ - void saveFileContent(String id, String content) throws IOException; + void saveFileContent(String id, String content,String taskId) throws IOException; /********************************** * 用途说明: 批量修改文件中多行多列的内容 * 参数说明 request 要修改的文件信息 * 返回值说明: com.yfd.platform.config.ResponseResult操作结果 ***********************************/ - void batchUpdateFile(String id, List modifications) throws IOException; + void batchUpdateFile(String id, List modifications,String taskId) throws IOException; /********************************** * 用途说明: 文件自动备份 @@ -198,7 +198,7 @@ public interface ITsFilesService extends IService { * 参数说明 id 文件夹ID * 返回值说明: com.yfd.platform.config.ResponseResult 返回文件信息 ***********************************/ - FileItemResult obtainUrl(String id, String type); + FileItemResult obtainUrl(String id, String type,String taskId); /********************************** * 用途说明: 对比本地有minio没有的文件差异 diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java index 5f4e3f5..492ee06 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/ITsTaskService.java @@ -64,4 +64,6 @@ public interface ITsTaskService extends IService { * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败 ***********************************/ Object confirmDeleteTask(List dataset); + + List listTsTask(); } 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 2535ba3..d939f7a 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 @@ -26,6 +26,7 @@ import com.amazonaws.util.IOUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -58,6 +59,7 @@ import com.yfd.platform.system.domain.SysDictionaryItems; import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; import com.yfd.platform.task.TaskMessage; import com.yfd.platform.utils.StringUtils; +import com.yfd.platform.utils.TableNameContextHolder; import io.netty.channel.ChannelInboundHandlerAdapter; import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZFile; @@ -156,122 +158,137 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public Page getTsFilesPage(String id, String fileName, String startDate, String endDate, String keywords, String nodeId, String taskId, String fileName1, String childNode, Page page) throws Exception { - //查询字典表获取压缩文件后缀 - QueryWrapper queryWrapperSysDictionary = new QueryWrapper<>(); - queryWrapperSysDictionary.eq("parentcode", "compressType"); - queryWrapperSysDictionary.orderByAsc("orderno"); - List sysDictionaryItems = sysDictionaryItemsMapper.selectList(queryWrapperSysDictionary); + // 初始化分页结果(防止NPE) + Page tsFilesPage = new Page<>(); + tsFilesPage.setRecords(new ArrayList<>()); + try { + //查询字典表获取压缩文件后缀 + QueryWrapper queryWrapperSysDictionary = new QueryWrapper<>(); + queryWrapperSysDictionary.eq("parentcode", "compressType"); + queryWrapperSysDictionary.orderByAsc("orderno"); + List sysDictionaryItems = sysDictionaryItemsMapper.selectList(queryWrapperSysDictionary); - QueryWrapper queryWrapper = new QueryWrapper<>(); - // 固定条件过滤 - if (StringUtils.isNotBlank(nodeId)) { - queryWrapper.eq("node_id", nodeId); - } - if (StringUtils.isNotBlank(taskId)) { - queryWrapper.eq("task_id", taskId); - } + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); - - // 模糊搜索 - if (StringUtils.isNotBlank(fileName)) { - queryWrapper.like("file_name", fileName); - } - if (StringUtils.isNotBlank(keywords)) { - queryWrapper.like("keywords", keywords); - } - - // 时间范围过滤 - if (StringUtils.isNotBlank(startDate)) { - queryWrapper.ge("upload_time", startDate); - } - if (StringUtils.isNotBlank(endDate)) { - queryWrapper.le("upload_time", endDate); - } - boolean hasSearchCondition = StringUtils.isNotBlank(fileName) || StringUtils.isNotBlank(keywords) || StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate); - - // 处理层级关系条件 - if (StringUtils.isNotBlank(id)) { - // 有ID时:根据childNode决定是否递归子节点 如果filename - if (childNode != null && childNode.equals("0") && hasSearchCondition) { - List childIds = getAllChildIds(id); - queryWrapper.in("parent_id", childIds); - } else { - // 其他情况:childNode=1 或 无搜索条件时 按当前层级查询 - queryWrapper.eq("parent_id", id); + QueryWrapper queryWrapper = new QueryWrapper<>(); + // 固定条件过滤 + if (StringUtils.isNotBlank(nodeId)) { + queryWrapper.eq("node_id", nodeId); } - } else { - //如果说ID是空 说明是顶级节点 - if (childNode != null) { - if (childNode.equals("0")) { - if (hasSearchCondition) { - // 递归获取根目录下所有子节点ID(包含多级) - List allChildIds = getAllChildIds("00"); // 注意这里传入字符串"00" - allChildIds.add("00"); // 包含根目录的直接子节点 - queryWrapper.in("parent_id", allChildIds); - } else { - // 无搜索条件时,仅查询根目录的直接子节点 + if (StringUtils.isNotBlank(taskId)) { + queryWrapper.eq("task_id", taskId); + } + + + // 模糊搜索 + if (StringUtils.isNotBlank(fileName)) { + queryWrapper.like("file_name", fileName); + } + if (StringUtils.isNotBlank(keywords)) { + queryWrapper.like("keywords", keywords); + } + + // 时间范围过滤 + if (StringUtils.isNotBlank(startDate)) { + queryWrapper.ge("upload_time", startDate); + } + if (StringUtils.isNotBlank(endDate)) { + queryWrapper.le("upload_time", endDate); + } + boolean hasSearchCondition = StringUtils.isNotBlank(fileName) || StringUtils.isNotBlank(keywords) || StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate); + + // 处理层级关系条件 + if (StringUtils.isNotBlank(id)) { + // 有ID时:根据childNode决定是否递归子节点 如果filename + if (childNode != null && childNode.equals("0") && hasSearchCondition) { + List childIds = getAllChildIds(id); + queryWrapper.in("parent_id", childIds); + } else { + // 其他情况:childNode=1 或 无搜索条件时 按当前层级查询 + queryWrapper.eq("parent_id", id); + } + } else { + //如果说ID是空 说明是顶级节点 + if (childNode != null) { + if (childNode.equals("0")) { + if (hasSearchCondition) { + // 递归获取根目录下所有子节点ID(包含多级) + List allChildIds = getAllChildIds("00"); // 注意这里传入字符串"00" + allChildIds.add("00"); // 包含根目录的直接子节点 + queryWrapper.in("parent_id", allChildIds); + } else { + // 无搜索条件时,仅查询根目录的直接子节点 + queryWrapper.eq("parent_id", "00"); + } + } else if (childNode.equals("1")) { + // 始终只查根目录的直接子节点 queryWrapper.eq("parent_id", "00"); } - } else if (childNode.equals("1")) { - // 始终只查根目录的直接子节点 - queryWrapper.eq("parent_id", "00"); } } - } - // - queryWrapper.isNotNull("work_path"); - queryWrapper.ne("work_path", ""); - //文件还是文件夹 - queryWrapper.orderByDesc("is_file"); - //文件名称 - queryWrapper.orderByDesc("file_name"); - //分页查询 - Page tsFilesPage = tsFilesMapper.selectPage(page, queryWrapper); - if (tsFilesPage == null) { - tsFilesPage = new Page<>(); - tsFilesPage.setRecords(new ArrayList<>()); // 确保 records 被初始化 - } - List records = tsFilesPage.getRecords(); - for (TsFiles tsFiles : records) { + // + queryWrapper.isNotNull("work_path"); + queryWrapper.ne("work_path", ""); + //文件还是文件夹 + queryWrapper.orderByDesc("is_file"); + //文件名称 + queryWrapper.orderByAsc("file_name"); + //分页查询 + tsFilesPage = tsFilesMapper.selectPage(page, queryWrapper); + if (tsFilesPage == null) { + tsFilesPage = new Page<>(); + tsFilesPage.setRecords(new ArrayList<>()); // 确保 records 被初始化 + } + List records = tsFilesPage.getRecords(); + for (TsFiles tsFiles : records) { + + String fileNameData = tsFiles.getFileName(); + //主要是用于文件路径加名称 + String path = tsFiles.getWorkPath() + fileNameData; + //准备获取文件的信息 + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("local"); + FileItemResult fileItemResult = fileService.getFileItem(path); + if (fileItemResult == null || fileItemResult.getName() == null) { + LOGGER.error("{}文件没有上传到工作空间,请重新选择上传", fileNameData); + } + tsFiles.setUrl(fileItemResult.getUrl()); + //如果是压缩文件 类型就给zip + boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems); + if (isValid) { + tsFiles.setType("ZIP"); + } else { + tsFiles.setType(fileItemResult.getType().getValue()); + } + if (tsFiles.getUpdateTime() == null) { + tsFiles.setUpdateTime(tsFiles.getUploadTime()); + } - String fileNameData = tsFiles.getFileName(); - //主要是用于文件路径加名称 - String path = tsFiles.getWorkPath() + fileNameData; - //准备获取文件的信息 - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("local"); - FileItemResult fileItemResult = fileService.getFileItem(path); - if (fileItemResult == null || fileItemResult.getName() == null) { - LOGGER.error("{}文件没有上传到工作空间,请重新选择上传", fileNameData); - } - tsFiles.setUrl(fileItemResult.getUrl()); - //如果是压缩文件 类型就给zip - boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems); - if (isValid) { - tsFiles.setType("ZIP"); - } else { - tsFiles.setType(fileItemResult.getType().getValue()); - } - if (tsFiles.getUpdateTime() == null) { - tsFiles.setUpdateTime(tsFiles.getUploadTime()); } - } - - tsFilesPage.setRecords(records); // 同步到 tsFilesPage - int currentPage = (int) page.getCurrent(); - // 如果是前五页,将结果存入Redis(有效期建议30分钟)如果搜索条件为空 从Redis获取 - if (StrUtil.isBlank(fileName) && StrUtil.isBlank(keywords) && StrUtil.isBlank(startDate) && StrUtil.isBlank(endDate) && !"00".equals(id)) { - if (!StrUtil.isEmpty(id)) { - if (currentPage >= 1 && currentPage <= 5) { - String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_parentId" + id + "_page_" + currentPage + ""; - redisTemplate.opsForValue().set(redisKey, tsFilesPage, 2, TimeUnit.HOURS); + tsFilesPage.setRecords(records); // 同步到 tsFilesPage + int currentPage = (int) page.getCurrent(); + // 如果是前五页,将结果存入Redis(有效期建议30分钟)如果搜索条件为空 从Redis获取 + if (StrUtil.isBlank(fileName) && StrUtil.isBlank(keywords) && StrUtil.isBlank(startDate) && StrUtil.isBlank(endDate) && !"00".equals(id)) { + if (!StrUtil.isEmpty(id)) { + if (currentPage >= 1 && currentPage <= 5) { + String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_parentId" + id + "_page_" + currentPage + ""; + redisTemplate.opsForValue().set(redisKey, tsFilesPage, 2, TimeUnit.HOURS); + } } } - } - return tsFilesPage; + return tsFilesPage; + } catch (Exception e) { + // 必须处理异常(至少记录日志) + LOGGER.error("查询文件分页失败: {}", e.getMessage(), e); + // 可选:抛出业务异常 + throw new BrokenBarrierException("文件查询失败"); + } finally { + TableNameContextHolder.clear(); + } } /** @@ -388,23 +405,33 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public List getsListTsFiles(String id, String path, String nodeId, String taskId) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getIsFile, "FOLDER"); - if (StringUtils.isNotBlank(id)) { - queryWrapper.eq(TsFiles::getParentId, id); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getIsFile, "FOLDER"); + if (StringUtils.isNotBlank(id)) { + queryWrapper.eq(TsFiles::getParentId, id); + } + if (StringUtils.isNotBlank(path)) { + queryWrapper.eq(TsFiles::getWorkPath, path); + } + if (StringUtils.isNotBlank(nodeId)) { + queryWrapper.eq(TsFiles::getNodeId, nodeId); + } + if (StringUtils.isNotBlank(taskId)) { + queryWrapper.eq(TsFiles::getTaskId, taskId); + } + queryWrapper.isNotNull(TsFiles::getWorkPath); + List tsFiles = tsFilesMapper.selectList(queryWrapper); + return tsFiles; + } catch (Exception e) { + // 可选:记录异常日志 + LOGGER.error("查询失败:{}", e.getMessage(), e); + return Collections.emptyList(); + } finally { + TableNameContextHolder.clear(); } - if (StringUtils.isNotBlank(path)) { - queryWrapper.eq(TsFiles::getWorkPath, path); - } - if (StringUtils.isNotBlank(nodeId)) { - queryWrapper.eq(TsFiles::getNodeId, nodeId); - } - if (StringUtils.isNotBlank(taskId)) { - queryWrapper.eq(TsFiles::getTaskId, taskId); - } - queryWrapper.isNotNull(TsFiles::getWorkPath); - List tsFiles = tsFilesMapper.selectList(queryWrapper); - return tsFiles; } @@ -417,66 +444,65 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public ResponseResult addTsFiles(TsFiles tsFiles) { - //todo 新增成功以后 删除redis - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; - redisTemplate.delete(redisKey); - } - LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); + try { + TsTask tsTask = tsTaskMapper.selectById(tsFiles.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 清理 Redis 缓存 + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; + redisTemplate.delete(redisKey); + } + LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); - // 参数校验 - if (tsFiles.getFileName() == null || tsFiles.getFileSize() == null) { - return ResponseResult.error("文件名或文件大小不能为空!"); - } - - Boolean value = true; - //文件名称和大小 因为支持多个上传所以用,分隔 - List names = Arrays.asList(tsFiles.getFileName().split(",")); - List sizes = Arrays.asList(tsFiles.getFileSize().split(",")); - //上传人是当前登录人 - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - - // 数据校验 - if (names.size() != sizes.size()) { - LOGGER.error("文件名称和文件大小的列表长度不一致"); - return ResponseResult.error("文件名称和文件大小的列表长度不一致!"); - } - - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - tsFiles.setUploadTime(currentTime); - - List filesToSave = new ArrayList<>(); - for (int i = 0; i < names.size(); i++) { - String name = names.get(i).trim(); - String sizeStr = sizes.get(i).trim(); - - String pathAndName = tsFiles.getWorkPath() + name; - //准备获取文件的信息 - AbstractBaseFileService fileServicefile = storageSourceContext.getByStorageKey("local"); - FileItemResult fileItemResult = fileServicefile.getFileItem(pathAndName); - if (fileItemResult == null || fileItemResult.getName() == null) { - return ResponseResult.error(name + "文件没有上传到工作空间,请重新选择上传!"); + // 参数校验 + if (tsFiles.getFileName() == null || tsFiles.getFileSize() == null) { + return ResponseResult.error("文件名或文件大小不能为空!"); } - //通过节点ID 任务ID 路径 上级ID 文件名称 查询是否重复 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); - queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); - queryWrapper.eq(TsFiles::getWorkPath, tsFiles.getWorkPath()); - queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); - queryWrapper.eq(TsFiles::getFileName, name); - int count = tsFilesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("文件已存在!"); + Boolean value = true; + + // 文件名称和大小,支持多个上传用逗号分隔 + List names = Arrays.asList(tsFiles.getFileName().split(",")); + List sizes = Arrays.asList(tsFiles.getFileSize().split(",")); + // 获取当前登录用户 + UsernamePasswordAuthenticationToken authentication = + (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + + // 数据校验 + if (names.size() != sizes.size()) { + LOGGER.error("文件名称和文件大小的列表长度不一致"); + return ResponseResult.error("文件名称和文件大小的列表长度不一致!"); } - // 校验文件大小是否可以转换成数值 - try { + + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + Timestamp currentTime = Timestamp.valueOf(now); + tsFiles.setUploadTime(currentTime); + + List filesToSave = new ArrayList<>(); + for (int i = 0; i < names.size(); i++) { + String name = names.get(i).trim(); + String sizeStr = sizes.get(i).trim(); + + String pathAndName = tsFiles.getWorkPath() + name; + AbstractBaseFileService fileServicefile = storageSourceContext.getByStorageKey("local"); + FileItemResult fileItemResult = fileServicefile.getFileItem(pathAndName); + if (fileItemResult == null || fileItemResult.getName() == null) { + return ResponseResult.error(name + "文件没有上传到工作空间,请重新选择上传!"); + } + + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()) + .eq(TsFiles::getTaskId, tsFiles.getTaskId()) + .eq(TsFiles::getWorkPath, tsFiles.getWorkPath()) + .eq(TsFiles::getParentId, tsFiles.getParentId()) + .eq(TsFiles::getFileName, name); + int count = tsFilesMapper.selectCount(queryWrapper); + if (count > 0) { + return ResponseResult.error("文件已存在!"); + } + TsFiles files1 = new TsFiles(); files1.setTaskId(tsFiles.getTaskId()); files1.setIsFile(tsFiles.getIsFile()); @@ -489,32 +515,31 @@ public class TsFilesServiceImpl extends ServiceImpl impl files1.setUploadTime(tsFiles.getUploadTime()); files1.setUploader(loginuser.getUsername()); files1.setFileName(name); - if ("0.000".equals(sizeStr)) { - files1.setFileSize("0.001"); - - } else { - files1.setFileSize(sizeStr); - } + files1.setFileSize("0.000".equals(sizeStr) ? "0.001" : sizeStr); filesToSave.add(files1); - } catch (NumberFormatException e) { - LOGGER.error("文件大小必须是有效的数字"); } - } - if (filesToSave.size() > 0) { - //循环新增 - for (TsFiles filess : filesToSave) { - int valueAdded = tsFilesMapper.insert(filess); - if (valueAdded == 1) { - LOGGER.info("表结构和本地都创建文件夹成功"); - value = true; - } else { - LOGGER.error("本地创建文件夹成功,表结构新增失败"); - value = false; + + if (!filesToSave.isEmpty()) { + for (TsFiles filess : filesToSave) { + int valueAdded = tsFilesMapper.insert(filess); + if (valueAdded == 1) { + LOGGER.info("表结构和本地都创建文件夹成功"); + value = true; + } else { + LOGGER.error("本地创建文件夹成功,表结构新增失败"); + value = false; + } } } + + return value ? ResponseResult.success("新增文件成功!") : ResponseResult.error("新增文件失败!"); + } catch (Exception e) { + LOGGER.error("新增试验数据管理文档内容时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误,请稍后重试"); + } finally { + TableNameContextHolder.clear(); } - return value ? ResponseResult.success("新增文件成功!") : ResponseResult.error("新增文件失败!"); } @@ -527,84 +552,93 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class)// 添加事务注解,遇到异常时回滚 public ResponseResult addTsFile(TsFiles tsFiles) throws IOException { + try { + TsTask tsTask = tsTaskMapper.selectById(tsFiles.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + //todo 新增成功以后 删除redis + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; + redisTemplate.delete(redisKey); + } + LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); + //上传人是当前登录人 + UsernamePasswordAuthenticationToken authentication = + (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); - //todo 新增成功以后 删除redis - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; - redisTemplate.delete(redisKey); - } - LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); - //上传人是当前登录人 - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - - if (tsFiles.getIsFile().equals("FILE")) { - StorageSourceConfig config = getStorageConfig("filePath", "local"); - String basePath = config.getValue() + tsFiles.getWorkPath(); - // 拼接完整的文件路径 - Path filePath = Paths.get(basePath, tsFiles.getFileName() + ".txt"); - // 确保目录存在,如果不存在则创建目录 - Files.createDirectories(filePath.getParent()); - // 使用 Files.write() 写入字符串内容 - Files.write(filePath, "默认内容".getBytes(StandardCharsets.UTF_8)); - tsFiles.setFileName(tsFiles.getFileName() + ".txt"); - tsFiles.setUploadTime(currentTime); - tsFiles.setUploader(loginuser.getUsername()); - tsFiles.setFileSize("0.001"); - int valueAdded = tsFilesMapper.insert(tsFiles); - if (valueAdded == 1) { - LOGGER.info("文件创建成功"); - return ResponseResult.success(); - } else { - LOGGER.error("文件创建失败"); - return ResponseResult.error(); - } - } else { - // 校验文件名是否包含非法字符 - String fileName = tsFiles.getFileName(); - if (containsInvalidCharacters(fileName)) { - return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); - } - tsFiles.setUploadTime(currentTime); - tsFiles.setUploader(loginuser.getUsername()); - tsFiles.setFileSize("0"); - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); - queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); - queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); - queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); - int count = tsFilesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("文件夹名称已存在!"); - } - //本地创建文件夹 - NewFolderRequest newFolderRequest = new NewFolderRequest(); - newFolderRequest.setStorageKey("local"); - newFolderRequest.setPath(tsFiles.getWorkPath()); - newFolderRequest.setPassword(null); - newFolderRequest.setName(tsFiles.getFileName()); - AbstractBaseFileService fileServicefolder = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); - boolean flagfolder = fileServicefolder.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); - //创建成功以后新增表结构 - if (flagfolder) { + if (tsFiles.getIsFile().equals("FILE")) { + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + String basePath = config.getValue() + tsFiles.getWorkPath(); + // 拼接完整的文件路径 + Path filePath = Paths.get(basePath, tsFiles.getFileName() + ".txt"); + // 确保目录存在,如果不存在则创建目录 + Files.createDirectories(filePath.getParent()); + // 使用 Files.write() 写入字符串内容 + Files.write(filePath, "默认内容".getBytes(StandardCharsets.UTF_8)); + tsFiles.setFileName(tsFiles.getFileName() + ".txt"); + tsFiles.setUploadTime(currentTime); + tsFiles.setUploader(loginuser.getUsername()); + tsFiles.setFileSize("0.001"); int valueAdded = tsFilesMapper.insert(tsFiles); if (valueAdded == 1) { - LOGGER.info("表结构和本地都创建文件夹成功"); + LOGGER.info("文件创建成功"); return ResponseResult.success(); } else { - LOGGER.error("本地创建文件夹成功,表结构新增失败"); + LOGGER.error("文件创建失败"); return ResponseResult.error(); } } else { - LOGGER.error("本地创建文件夹失败"); - return ResponseResult.error(); + // 校验文件名是否包含非法字符 + String fileName = tsFiles.getFileName(); + if (containsInvalidCharacters(fileName)) { + return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); + } + tsFiles.setUploadTime(currentTime); + tsFiles.setUploader(loginuser.getUsername()); + tsFiles.setFileSize("0"); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); + queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); + queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); + queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); + int count = tsFilesMapper.selectCount(queryWrapper); + // 大于0说明 区域名称重复 + if (count > 0) { + return ResponseResult.error("文件夹名称已存在!"); + } + //本地创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setStorageKey(storageSource.getKey()); + newFolderRequest.setPath(tsFiles.getWorkPath()); + newFolderRequest.setPassword(null); + newFolderRequest.setName(tsFiles.getFileName()); + AbstractBaseFileService fileServicefolder = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flagfolder = fileServicefolder.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + //创建成功以后新增表结构 + if (flagfolder) { + int valueAdded = tsFilesMapper.insert(tsFiles); + if (valueAdded == 1) { + LOGGER.info("表结构和本地都创建文件夹成功"); + return ResponseResult.success(); + } else { + LOGGER.error("本地创建文件夹成功,表结构新增失败"); + return ResponseResult.error(); + } + } else { + LOGGER.error("本地创建文件夹失败"); + return ResponseResult.error(); + } } + } catch (Exception e) { + LOGGER.error("新增试验数据管理文档内容时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误,请稍后重试"); + } finally { + TableNameContextHolder.clear(); } } @@ -626,84 +660,107 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class)// 添加事务注解,遇到异常时回滚 public ResponseResult updateTsFiles(TsFiles tsFiles) { + try { + TsTask tsTask = tsTaskMapper.selectById(tsFiles.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + //todo 修改成功以后 删除redis + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; + redisTemplate.delete(redisKey); + } + LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); + // 校验文件名是否包含非法字符 + String fileName = tsFiles.getFileName(); + if (containsInvalidCharacters(fileName)) { + return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); + } - //todo 修改成功以后 删除redis - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page; - redisTemplate.delete(redisKey); - } - LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); - // 校验文件名是否包含非法字符 - String fileName = tsFiles.getFileName(); - if (containsInvalidCharacters(fileName)) { - return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); - } + // 修改之前查询表中的文件名是否修改,如果发生变动先修改 minio 然后再修改表结构 + TsFiles filesData = tsFilesMapper.selectById(tsFiles.getId()); - // 修改之前查询表中的文件名是否修改,如果发生变动先修改 minio 然后再修改表结构 - TsFiles filesData = tsFilesMapper.selectById(tsFiles.getId()); + // 判断文件名是否修改 不一致需要修改 + if (!tsFiles.getFileName().equals(filesData.getFileName())) { - // 判断文件名是否修改 不一致需要修改 - if (!tsFiles.getFileName().equals(filesData.getFileName())) { + //校验文件夹会不会重命名 + if ("FOLDER".equals(tsFiles.getIsFile())) { + //如果是文件夹 递归修改它下面的所有文件的路径 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); + queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); + queryWrapper.eq(TsFiles::getWorkPath, tsFiles.getWorkPath()); + queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); + queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); + int count = tsFilesMapper.selectCount(queryWrapper); + // 大于0说明 区域名称重复 + if (count > 0) { + return ResponseResult.error("文件夹名称已存在!"); + } - //校验文件夹会不会重命名 - if ("FOLDER".equals(tsFiles.getIsFile())) { - //如果是文件夹 递归修改它下面的所有文件的路径 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); - queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); - queryWrapper.eq(TsFiles::getWorkPath, tsFiles.getWorkPath()); - queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); - queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); - int count = tsFilesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("文件夹名称已存在!"); - } + //查询数据源 + RenameFileRequest renameFileRequest = new RenameFileRequest(); + renameFileRequest.setName(filesData.getFileName()); + renameFileRequest.setNewName(tsFiles.getFileName()); + renameFileRequest.setPassword(""); + renameFileRequest.setPath(filesData.getWorkPath()); + renameFileRequest.setStorageKey(storageSource.getKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); + Boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); + //如果是true 说明至少有一个修改了文件夹 + if (flag) { + //递归下面所有的文件文件夹 路径都需要修改 + List resultList = new ArrayList<>(); - //查询数据源 - RenameFileRequest renameFileRequest = new RenameFileRequest(); - renameFileRequest.setName(filesData.getFileName()); - renameFileRequest.setNewName(tsFiles.getFileName()); - renameFileRequest.setPassword(""); - renameFileRequest.setPath(filesData.getWorkPath()); - renameFileRequest.setStorageKey("local"); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); - Boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); - //如果是true 说明至少有一个修改了文件夹 - if (flag) { - //递归下面所有的文件文件夹 路径都需要修改 - List resultList = new ArrayList<>(); + if (tsFiles.getBackupPath() != null && tsFiles.getBackupPath() != "") { + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); + //新通过id找到表中现有的 修改也是修改表中现有的数据 新增的一条就是重命名以后的 所有备份空间路径为空 原来的哪条数据把工作空间路径改成空 + TsFiles tsFiles2 = tsFilesMapper.selectById(tsFiles.getId());//查询原来的数据 把原来的数据 + tsFiles2.setWorkPath(""); - if (tsFiles.getBackupPath() != null && tsFiles.getBackupPath() != "") { - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - //新通过id找到表中现有的 修改也是修改表中现有的数据 新增的一条就是重命名以后的 所有备份空间路径为空 原来的哪条数据把工作空间路径改成空 - TsFiles tsFiles2 = tsFilesMapper.selectById(tsFiles.getId());//查询原来的数据 把原来的数据 - tsFiles2.setWorkPath(""); + TsFiles tsFiles1 = new TsFiles(); + tsFiles1.setNodeId(tsFiles.getNodeId()); + tsFiles1.setTaskId(tsFiles.getTaskId()); + tsFiles1.setIsFile(tsFiles.getIsFile()); + tsFiles1.setParentId(tsFiles.getParentId()); + tsFiles1.setFileName(tsFiles.getFileName()); + tsFiles1.setFileSize(tsFiles.getFileSize()); + tsFiles1.setWorkPath(tsFiles.getWorkPath()); + tsFiles1.setBackupPath(""); + tsFiles1.setKeywords(tsFiles.getKeywords()); + tsFiles1.setDescription(tsFiles.getDescription()); + tsFiles1.setUploadTime(currentTime); + tsFiles1.setUploader(tsFiles.getUploader()); + tsFiles1.setUpdateTime(currentTime); + int valueInsert = tsFilesMapper.insert(tsFiles1); + if (valueInsert == 1) { + int valueUpdate = tsFilesMapper.updateById(tsFiles2); + // 获取当前文件夹的完整路径(如 "/147/222/") + String oldFullPath = filesData.getWorkPath() + filesData.getFileName() + "/"; + String newFullPath = filesData.getWorkPath() + tsFiles.getFileName() + "/"; + querySubFilesAndUpdatePaths(resultList, tsFiles2.getId(), oldFullPath, newFullPath, tsFiles1.getId()); + if (valueUpdate == 1) { + LOGGER.info("local和minio修改成功,表结构修改成功"); + return ResponseResult.success(); + } else { + LOGGER.error("local和minio修改成功,表结构修改失败"); + return ResponseResult.error(); + } + } else { + LOGGER.error("local和minio修改成功,表结构修改失败"); + return ResponseResult.error(); + } - TsFiles tsFiles1 = new TsFiles(); - tsFiles1.setNodeId(tsFiles.getNodeId()); - tsFiles1.setTaskId(tsFiles.getTaskId()); - tsFiles1.setIsFile(tsFiles.getIsFile()); - tsFiles1.setParentId(tsFiles.getParentId()); - tsFiles1.setFileName(tsFiles.getFileName()); - tsFiles1.setFileSize(tsFiles.getFileSize()); - tsFiles1.setWorkPath(tsFiles.getWorkPath()); - tsFiles1.setBackupPath(""); - tsFiles1.setKeywords(tsFiles.getKeywords()); - tsFiles1.setDescription(tsFiles.getDescription()); - tsFiles1.setUploadTime(currentTime); - tsFiles1.setUploader(tsFiles.getUploader()); - tsFiles1.setUpdateTime(currentTime); - int valueInsert = tsFilesMapper.insert(tsFiles1); - if (valueInsert == 1) { - int valueUpdate = tsFilesMapper.updateById(tsFiles2); - // 获取当前文件夹的完整路径(如 "/147/222/") + + } else { + // 如果备份空间为空 直接修改数据库 String oldFullPath = filesData.getWorkPath() + filesData.getFileName() + "/"; String newFullPath = filesData.getWorkPath() + tsFiles.getFileName() + "/"; - querySubFilesAndUpdatePaths(resultList, tsFiles2.getId(), oldFullPath, newFullPath, tsFiles1.getId()); + querySubFilesAndUpdatePaths(resultList, tsFiles.getId(), oldFullPath, newFullPath, tsFiles.getId()); + + int valueUpdate = tsFilesMapper.updateById(tsFiles); if (valueUpdate == 1) { LOGGER.info("local和minio修改成功,表结构修改成功"); return ResponseResult.success(); @@ -711,82 +768,78 @@ public class TsFilesServiceImpl extends ServiceImpl impl LOGGER.error("local和minio修改成功,表结构修改失败"); return ResponseResult.error(); } - } else { - LOGGER.error("local和minio修改成功,表结构修改失败"); - return ResponseResult.error(); } - - } else { - // 如果备份空间为空 直接修改数据库 - String oldFullPath = filesData.getWorkPath() + filesData.getFileName() + "/"; - String newFullPath = filesData.getWorkPath() + tsFiles.getFileName() + "/"; - querySubFilesAndUpdatePaths(resultList, tsFiles.getId(), oldFullPath, newFullPath, tsFiles.getId()); - - int valueUpdate = tsFilesMapper.updateById(tsFiles); - if (valueUpdate == 1) { - LOGGER.info("local和minio修改成功,表结构修改成功"); - return ResponseResult.success(); - } else { - LOGGER.error("local和minio修改成功,表结构修改失败"); - return ResponseResult.error(); - } + LOGGER.error("local和minio修改失败"); + return ResponseResult.error(); } } else { - LOGGER.error("local和minio修改失败"); - return ResponseResult.error(); - } - } else { - //如果是文件 直接修改就可以 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); - queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); - queryWrapper.eq(TsFiles::getWorkPath, tsFiles.getWorkPath()); - queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); - queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); - int count = tsFilesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("文件名称已存在!"); - } - //查询数据源 - RenameFileRequest renameFileRequest = new RenameFileRequest(); - renameFileRequest.setName(filesData.getFileName()); - renameFileRequest.setNewName(tsFiles.getFileName()); - renameFileRequest.setPassword(""); - renameFileRequest.setPath(filesData.getWorkPath()); - renameFileRequest.setStorageKey("local"); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); - Boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); - //如果是true 说明至少有一个修改了文件 - if (flag) { - //如果备份路径不为空 那么就先增加一条 然后修改本地的 - if (tsFiles.getBackupPath() != null && tsFiles.getBackupPath() != "") { - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - //新通过id找到表中现有的 修改也是修改表中现有的数据 新增的一条就是重命名以后的 所有备份空间路径为空 原来的哪条数据把工作空间路径改成空 - TsFiles tsFiles2 = tsFilesMapper.selectById(tsFiles.getId());//查询原来的数据 把原来的数据 - tsFiles2.setWorkPath(""); + //如果是文件 直接修改就可以 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getNodeId, tsFiles.getNodeId()); + queryWrapper.eq(TsFiles::getTaskId, tsFiles.getTaskId()); + queryWrapper.eq(TsFiles::getWorkPath, tsFiles.getWorkPath()); + queryWrapper.eq(TsFiles::getParentId, tsFiles.getParentId()); + queryWrapper.eq(TsFiles::getFileName, tsFiles.getFileName()); + int count = tsFilesMapper.selectCount(queryWrapper); + // 大于0说明 区域名称重复 + if (count > 0) { + return ResponseResult.error("文件名称已存在!"); + } + //查询数据源 + RenameFileRequest renameFileRequest = new RenameFileRequest(); + renameFileRequest.setName(filesData.getFileName()); + renameFileRequest.setNewName(tsFiles.getFileName()); + renameFileRequest.setPassword(""); + renameFileRequest.setPath(filesData.getWorkPath()); + renameFileRequest.setStorageKey(storageSource.getKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); + Boolean flag = fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); + //如果是true 说明至少有一个修改了文件 + if (flag) { + //如果备份路径不为空 那么就先增加一条 然后修改本地的 + if (tsFiles.getBackupPath() != null && tsFiles.getBackupPath() != "") { + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); + //新通过id找到表中现有的 修改也是修改表中现有的数据 新增的一条就是重命名以后的 所有备份空间路径为空 原来的哪条数据把工作空间路径改成空 + TsFiles tsFiles2 = tsFilesMapper.selectById(tsFiles.getId());//查询原来的数据 把原来的数据 + tsFiles2.setWorkPath(""); - TsFiles tsFiles1 = new TsFiles(); - tsFiles1.setNodeId(tsFiles.getNodeId()); - tsFiles1.setTaskId(tsFiles.getTaskId()); - tsFiles1.setIsFile(tsFiles.getIsFile()); - tsFiles1.setParentId(tsFiles.getParentId()); - tsFiles1.setFileName(tsFiles.getFileName()); - tsFiles1.setFileSize(tsFiles.getFileSize()); - tsFiles1.setWorkPath(tsFiles.getWorkPath()); - tsFiles1.setBackupPath(""); - tsFiles1.setKeywords(tsFiles.getKeywords()); - tsFiles1.setDescription(tsFiles.getDescription()); - tsFiles1.setUploadTime(currentTime); - tsFiles1.setUploader(tsFiles.getUploader()); - tsFiles1.setUpdateTime(currentTime); - int valueInsert = tsFilesMapper.insert(tsFiles1); - if (valueInsert == 1) { - int valueUpdate = tsFilesMapper.updateById(tsFiles2); + TsFiles tsFiles1 = new TsFiles(); + tsFiles1.setNodeId(tsFiles.getNodeId()); + tsFiles1.setTaskId(tsFiles.getTaskId()); + tsFiles1.setIsFile(tsFiles.getIsFile()); + tsFiles1.setParentId(tsFiles.getParentId()); + tsFiles1.setFileName(tsFiles.getFileName()); + tsFiles1.setFileSize(tsFiles.getFileSize()); + tsFiles1.setWorkPath(tsFiles.getWorkPath()); + tsFiles1.setBackupPath(""); + tsFiles1.setKeywords(tsFiles.getKeywords()); + tsFiles1.setDescription(tsFiles.getDescription()); + tsFiles1.setUploadTime(currentTime); + tsFiles1.setUploader(tsFiles.getUploader()); + tsFiles1.setUpdateTime(currentTime); + int valueInsert = tsFilesMapper.insert(tsFiles1); + if (valueInsert == 1) { + int valueUpdate = tsFilesMapper.updateById(tsFiles2); + if (valueUpdate == 1) { + LOGGER.info("local和minio修改成功,表结构修改成功"); + return ResponseResult.success(); + } else { + LOGGER.error("local和minio修改成功,表结构修改失败"); + return ResponseResult.error(); + } + } else { + LOGGER.error("local和minio修改成功,表结构修改失败"); + return ResponseResult.error(); + } + + + } else { + // 如果备份空间为空 直接修改数据库 + int valueUpdate = tsFilesMapper.updateById(tsFiles); if (valueUpdate == 1) { LOGGER.info("local和minio修改成功,表结构修改成功"); return ResponseResult.success(); @@ -794,38 +847,28 @@ public class TsFilesServiceImpl extends ServiceImpl impl LOGGER.error("local和minio修改成功,表结构修改失败"); return ResponseResult.error(); } - } else { - LOGGER.error("local和minio修改成功,表结构修改失败"); - return ResponseResult.error(); } } else { - // 如果备份空间为空 直接修改数据库 - int valueUpdate = tsFilesMapper.updateById(tsFiles); - if (valueUpdate == 1) { - LOGGER.info("local和minio修改成功,表结构修改成功"); - return ResponseResult.success(); - } else { - LOGGER.error("local和minio修改成功,表结构修改失败"); - return ResponseResult.error(); - } + LOGGER.error("local和minio修改失败"); + return ResponseResult.error(); } - - + } + } else { + // 如果文件名没有修改,仅更新数据库 + int valueUpdate = tsFilesMapper.updateById(tsFiles); + if (valueUpdate == 1) { + return ResponseResult.success(); } else { - LOGGER.error("local和minio修改失败"); return ResponseResult.error(); } } - } else { - // 如果文件名没有修改,仅更新数据库 - int valueUpdate = tsFilesMapper.updateById(tsFiles); - if (valueUpdate == 1) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } + } catch (Exception e) { + LOGGER.error("修改试验数据管理文档内容时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误,请稍后重试"); + } finally { + TableNameContextHolder.clear(); } } @@ -905,153 +948,163 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override @Transactional(rollbackFor = Exception.class)// 添加事务注解,遇到异常时回滚 - public String deleteTsFilesByIds(List dataset, String type) { - List filesList = tsFilesMapper.selectBatchIds(dataset); + public String deleteTsFilesByIds(List dataset, String type, String taskId) { - //新增一个查询 判断下面有没有备份路径 如果有就不能删除 + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + //新增一个查询 判断下面有没有备份路径 如果有就不能删除 + List filesList = tsFilesMapper.selectBatchIds(dataset); - //todo 删除的时候成功以后 删除redis - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + filesList.get(0).getParentId() + "_page_" + page; - redisTemplate.delete(redisKey); - } - LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", filesList.get(0).getTaskId(), filesList.get(0).getNodeId()); + //todo 删除的时候成功以后 删除redis + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + filesList.get(0).getParentId() + "_page_" + page; + redisTemplate.delete(redisKey); + } + LOGGER.info("已清理缓存:taskid={}, node={}, pages=1-5", filesList.get(0).getTaskId(), filesList.get(0).getNodeId()); - int LocalSuccessCount = 0, LocalFailCount = 0, Localtotal = CollUtil.size(dataset); - //Todo 最直接的办法 循环出来 一条一条删除 如果是文件夹 要递归下面所有的文件和文件夹进行删除 - for (TsFiles files : filesList) { + int LocalSuccessCount = 0, LocalFailCount = 0, Localtotal = CollUtil.size(dataset); + //Todo 最直接的办法 循环出来 一条一条删除 如果是文件夹 要递归下面所有的文件和文件夹进行删除 + for (TsFiles files : filesList) { - //判断是文件还是文件夹 - if ("FOLDER".equals(files.getIsFile())) { - //如果是文件夹 - List deleteItemList = new ArrayList<>(); - BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); - deleteItemData.setName(files.getFileName()); - deleteItemData.setPassword(""); - if ("local".equals(type)) { - deleteItemData.setPath(files.getWorkPath()); - } else { - deleteItemData.setPath(files.getBackupPath()); - } - deleteItemData.setType(FileTypeEnum.FOLDER); - deleteItemList.add(deleteItemData); - //首先通过ID集合查询所有的内容 然后放到List deleteItems里面 放好以后删除数据库 然后删除minio - BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); - batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey(type); + //判断是文件还是文件夹 + if ("FOLDER".equals(files.getIsFile())) { + //如果是文件夹 + List deleteItemList = new ArrayList<>(); + BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); + deleteItemData.setName(files.getFileName()); + deleteItemData.setPassword(""); + if (storageSource.getKey().equals(type)) { + deleteItemData.setPath(files.getWorkPath()); + } else { + deleteItemData.setPath(files.getBackupPath()); + } + deleteItemData.setType(FileTypeEnum.FOLDER); + deleteItemList.add(deleteItemData); + //首先通过ID集合查询所有的内容 然后放到List deleteItems里面 放好以后删除数据库 然后删除minio + BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); + batchDeleteRequest.setDeleteItems(deleteItemList); + batchDeleteRequest.setStorageKey(storageSource.getKey()); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); - List deleteItems = batchDeleteRequest.getDeleteItems(); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); + List deleteItems = batchDeleteRequest.getDeleteItems(); - int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems); - for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) { + int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems); + for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) { - boolean flag = false; - try { - if (deleteItem.getType() == FileTypeEnum.FILE) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); - } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { - flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); - } + boolean flag = false; + try { + if (deleteItem.getType() == FileTypeEnum.FILE) { + flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } - if (flag) { - deleteSuccessCount++; - } else { + if (flag) { + deleteSuccessCount++; + } else { + deleteFailCount++; + } + } catch (Exception e) { + LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } - } catch (Exception e) { - LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); - deleteFailCount++; } - } - if (totalCount > 1) { - LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); - } else { - LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); - } - - //如果是1 说明成功删除 - if (deleteSuccessCount >= 1) { - int valueDelete = deleteFolderAndSubFiles(files.getId(), type); - if (valueDelete > 0) { - LocalSuccessCount = valueDelete; - LOGGER.info("表结构成功删除"); + if (totalCount > 1) { + LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); } else { - System.out.println("没有记录被删除"); + LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); + } + + //如果是1 说明成功删除 + if (deleteSuccessCount >= 1) { + int valueDelete = deleteFolderAndSubFiles(files.getId(), type); + if (valueDelete > 0) { + LocalSuccessCount = valueDelete; + LOGGER.info("表结构成功删除"); + } else { + System.out.println("没有记录被删除"); + } + } else { + LocalFailCount++; } } else { - LocalFailCount++; - } - } else { - //如果是文件 + //如果是文件 - List deleteItemList = new ArrayList<>(); - BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); - deleteItemData.setName(files.getFileName()); - deleteItemData.setPassword(""); - if ("local".equals(type)) { - deleteItemData.setPath(files.getWorkPath()); - } else { - deleteItemData.setPath(files.getBackupPath()); - } - deleteItemData.setType(FileTypeEnum.FILE); - deleteItemList.add(deleteItemData); - //首先通过ID集合查询所有的内容 然后放到List deleteItems里面 放好以后删除数据库 然后删除minio - BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); - batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey(type); + List deleteItemList = new ArrayList<>(); + BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); + deleteItemData.setName(files.getFileName()); + deleteItemData.setPassword(""); + if (storageSource.getKey().equals(type)) { + deleteItemData.setPath(files.getWorkPath()); + } else { + deleteItemData.setPath(files.getBackupPath()); + } + deleteItemData.setType(FileTypeEnum.FILE); + deleteItemList.add(deleteItemData); + //首先通过ID集合查询所有的内容 然后放到List deleteItems里面 放好以后删除数据库 然后删除minio + BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); + batchDeleteRequest.setDeleteItems(deleteItemList); + batchDeleteRequest.setStorageKey(storageSource.getKey()); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); - List deleteItems = batchDeleteRequest.getDeleteItems(); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); + List deleteItems = batchDeleteRequest.getDeleteItems(); - int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems); - for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) { + int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItems); + for (BatchDeleteRequest.DeleteItem deleteItem : deleteItems) { - boolean flag = false; - try { - if (deleteItem.getType() == FileTypeEnum.FILE) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); - } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { - flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); - } + boolean flag = false; + try { + if (deleteItem.getType() == FileTypeEnum.FILE) { + flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } - if (flag) { - deleteSuccessCount++; - } else { + if (flag) { + deleteSuccessCount++; + } else { + deleteFailCount++; + } + } catch (Exception e) { + LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } - } catch (Exception e) { - LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); - deleteFailCount++; } - } - if (totalCount > 1) { - //return ResponseResult.success("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); - LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); - } else { - //return totalCount == deleteSuccessCount ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); - LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); - - } - //如果是1 说明成功删除 - if (deleteSuccessCount == 1) { - int valueDelete = deleteFiles(files.getId(), type); - if (valueDelete > 0) { - LocalSuccessCount++; - LOGGER.info("表结构成功删除"); + if (totalCount > 1) { + //return ResponseResult.success("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); + LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); } else { - System.out.println("没有记录被删除"); + //return totalCount == deleteSuccessCount ? ResponseResult.success("删除成功") : ResponseResult.error("删除失败"); + LOGGER.error("批量删除 " + totalCount + " 个, 删除成功 " + deleteSuccessCount + " 个, 失败 " + deleteFailCount + " 个."); + + } + //如果是1 说明成功删除 + if (deleteSuccessCount == 1) { + int valueDelete = deleteFiles(files.getId(), type); + if (valueDelete > 0) { + LocalSuccessCount++; + LOGGER.info("表结构成功删除"); + } else { + System.out.println("没有记录被删除"); + } + } else { + LocalFailCount++; } - } else { - LocalFailCount++; } } + return "Local批量删除 " + Localtotal + " 个, 删除成功 " + LocalSuccessCount + " 个, 失败 " + LocalFailCount + " 个."; + } catch (Exception e) { + LOGGER.error("删除试验数据管理文档内容时发生异常: {}", e.getMessage(), e); + return "删除失败:" + e.getMessage(); + } finally { + TableNameContextHolder.clear(); } - return "Local批量删除 " + Localtotal + " 个, 删除成功 " + LocalSuccessCount + " 个, 失败 " + LocalFailCount + " 个."; } // // 调用删除方法并返回删除数量 @@ -1224,160 +1277,172 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ @Override - public String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path) throws FileNotFoundException { - //获取本地根路径 - StorageSourceConfig storageSourceConfig = getStorageConfig("filePath", "local"); - compressedPath = normalizePath(compressedPath); - - - String returnResult = ""; - // 创建要压缩的文件夹列表 - List sourceDirs = new ArrayList<>(); // 修复:使用 ArrayList - String[] splitIds = ids.split(","); - // 数组转集合 - List dataset = Arrays.asList(splitIds); // 使用 Arrays.asList 创建不可变列表 - List filesList = tsFilesMapper.selectBatchIds(dataset); - // 检查 filesList 是否为空 - if (filesList == null || filesList.isEmpty()) { - throw new RuntimeException("未找到要压缩的文件或文件夹"); - } - for (TsFiles tsFiles : filesList) { - // 检查 tsFiles 的字段是否为空 - if (tsFiles.getWorkPath() == null || tsFiles.getFileName() == null) { - throw new RuntimeException("文件或文件夹信息不完整"); - } - - // 构建完整路径 - String sourceDir = storageSourceConfig.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName(); - Path workpath = Paths.get(sourceDir); - // 检查路径是否存在 - if (!Files.exists(workpath)) { - throw new FileNotFoundException("路径不存在: " + path); - } - // 添加到压缩列表 - sourceDirs.add(workpath); // 修复:使用可变集合 - } + public String compressFolder(String ids, String compressedFormat, String compressedName, String compressedPath, String covered, String parentId, String path, String taskId) throws FileNotFoundException { try { - LOGGER.info("压缩之前的时候删除Redis"); - //todo 压缩的时候删除Redis - if (!parentId.equals("00")) { - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + parentId + "_page_" + page; - redisTemplate.delete(redisKey); - } - } - String finalParentId = ensureFullPathExists(compressedPath, filesList.get(0).getNodeId(), filesList.get(0).getTaskId(), path); - parentId = finalParentId; - LOGGER.info("压缩的时候删除Redis"); - //todo 压缩的时候删除Redis - if (!parentId.equals("00")) { - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + parentId + "_page_" + page; - redisTemplate.delete(redisKey); - } + + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + + //获取本地根路径 + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + compressedPath = normalizePath(compressedPath); + + + String returnResult = ""; + // 创建要压缩的文件夹列表 + List sourceDirs = new ArrayList<>(); // 修复:使用 ArrayList + String[] splitIds = ids.split(","); + // 数组转集合 + List dataset = Arrays.asList(splitIds); // 使用 Arrays.asList 创建不可变列表 + List filesList = tsFilesMapper.selectBatchIds(dataset); + // 检查 filesList 是否为空 + if (filesList == null || filesList.isEmpty()) { + throw new RuntimeException("未找到要压缩的文件或文件夹"); } - LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); - } catch (RuntimeException e) { - LOGGER.error("路径创建失败: {}", e.getMessage()); - returnResult = "路径创建失败!"; - return returnResult; - } + for (TsFiles tsFiles : filesList) { + // 检查 tsFiles 的字段是否为空 + if (tsFiles.getWorkPath() == null || tsFiles.getFileName() == null) { + throw new RuntimeException("文件或文件夹信息不完整"); + } + + // 构建完整路径 + String sourceDir = storageSourceConfig.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName(); + Path workpath = Paths.get(sourceDir); + // 检查路径是否存在 + if (!Files.exists(workpath)) { + throw new FileNotFoundException("路径不存在: " + path); + } + // 添加到压缩列表 + sourceDirs.add(workpath); // 修复:使用可变集合 + } + try { + LOGGER.info("压缩之前的时候删除Redis"); + //todo 压缩的时候删除Redis + if (!parentId.equals("00")) { + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + parentId + "_page_" + page; + redisTemplate.delete(redisKey); + } + } + String finalParentId = ensureFullPathExists(compressedPath, filesList.get(0).getNodeId(), filesList.get(0).getTaskId(), path); + parentId = finalParentId; + LOGGER.info("压缩的时候删除Redis"); + //todo 压缩的时候删除Redis + if (!parentId.equals("00")) { + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + filesList.get(0).getTaskId() + "_" + filesList.get(0).getNodeId() + "_parentId" + parentId + "_page_" + page; + redisTemplate.delete(redisKey); + } + } + + LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); + } catch (RuntimeException e) { + LOGGER.error("路径创建失败: {}", e.getMessage()); + returnResult = "路径创建失败!"; + return returnResult; + } - // 规范化压缩包存放路径 - // 如果 compressedPath 是根目录,使用当前工作目录 - Path zipFilePath = Paths.get(storageSourceConfig.getValue() + path + compressedPath + compressedName + "." + compressedFormat); + // 规范化压缩包存放路径 + // 如果 compressedPath 是根目录,使用当前工作目录 + Path zipFilePath = Paths.get(storageSourceConfig.getValue() + path + compressedPath + compressedName + "." + compressedFormat); - // 检查目标路径是否可写 - if (!Files.isWritable(zipFilePath.getParent())) { - throw new RuntimeException("目标路径不可写: " + zipFilePath.getParent()); - } + // 检查目标路径是否可写 + if (!Files.isWritable(zipFilePath.getParent())) { + throw new RuntimeException("目标路径不可写: " + zipFilePath.getParent()); + } - String zipFileName = compressedName + "." + compressedFormat; + String zipFileName = compressedName + "." + compressedFormat; - // 使用 try-with-resources 确保 zipOut 在使用后关闭 - // 设置压缩级别,可以选择调整 + // 使用 try-with-resources 确保 zipOut 在使用后关闭 + // 设置压缩级别,可以选择调整 // zipOut.setLevel(ZipArchiveOutputStream.STORED); // 或者使用其他的压缩级别 - // 调用压缩方法 - Boolean value = compressToSameDirectory(sourceDirs, compressedFormat, zipFilePath); - if (value) { + // 调用压缩方法 + Boolean value = compressToSameDirectory(sourceDirs, compressedFormat, zipFilePath); + if (value) { - String workPath = normalizePath(path + compressedPath); - //表结构增加 nodeId, String TaskId - TsFiles tsFiles = new TsFiles(); - tsFiles.setTaskId(filesList.get(0).getTaskId()); - tsFiles.setNodeId(filesList.get(0).getNodeId()); - tsFiles.setWorkPath(workPath); - tsFiles.setIsFile("FILE"); + String workPath = normalizePath(path + compressedPath); + //表结构增加 nodeId, String TaskId + TsFiles tsFiles = new TsFiles(); + tsFiles.setTaskId(filesList.get(0).getTaskId()); + tsFiles.setNodeId(filesList.get(0).getNodeId()); + tsFiles.setWorkPath(workPath); + tsFiles.setIsFile("FILE"); - // 获取文件大小(字节) - long fileSizeInBytes = zipFilePath.toFile().length(); - // 转换为 KB 并保留两位小数 - double fileSizeInKB = fileSizeInBytes / (1024.0); - String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 - // 设置文件大小 - tsFiles.setFileSize(fileSizeFormatted); - //tsFiles.setFileSize(String.valueOf(zipFilePath.toFile().length())); - tsFiles.setParentId(parentId); - tsFiles.setBackupPath(""); - tsFiles.setKeywords(""); - tsFiles.setDescription(""); - tsFiles.setFileName(zipFileName); + // 获取文件大小(字节) + long fileSizeInBytes = zipFilePath.toFile().length(); + // 转换为 KB 并保留两位小数 + double fileSizeInKB = fileSizeInBytes / (1024.0); + String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 + // 设置文件大小 + tsFiles.setFileSize(fileSizeFormatted); + //tsFiles.setFileSize(String.valueOf(zipFilePath.toFile().length())); + tsFiles.setParentId(parentId); + tsFiles.setBackupPath(""); + tsFiles.setKeywords(""); + tsFiles.setDescription(""); + tsFiles.setFileName(zipFileName); - //上传人是当前登录人 - UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - tsFiles.setUploadTime(currentTime); - tsFiles.setUploader(loginuser.getUsername()); - // 通过 nodeid taskid 名称查询 如果存在就不 新增 + //上传人是当前登录人 + UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); + tsFiles.setUploadTime(currentTime); + tsFiles.setUploader(loginuser.getUsername()); + // 通过 nodeid taskid 名称查询 如果存在就不 新增 - LambdaQueryWrapper queryWrapperTsFiles = new LambdaQueryWrapper<>(); - queryWrapperTsFiles.eq(TsFiles::getNodeId, filesList.get(0).getNodeId()); - queryWrapperTsFiles.eq(TsFiles::getTaskId, filesList.get(0).getTaskId()); - queryWrapperTsFiles.eq(TsFiles::getWorkPath, workPath); - queryWrapperTsFiles.eq(TsFiles::getFileName, zipFileName); - queryWrapperTsFiles.eq(TsFiles::getParentId, filesList.get(0).getParentId()); - TsFiles tsFilesdata = tsFilesMapper.selectOne(queryWrapperTsFiles); - //covered 是否覆盖 0 覆盖更新updateTime时间 1提示文件存在 - if ("0".equals(covered)) { - //如果不为空 更新updateTime时间 - if (tsFilesdata != null) { - tsFilesdata.setUpdateTime(currentTime); - tsFilesMapper.updateById(tsFilesdata); - } else { - //如果为空就新增 - int valueAdded = tsFilesMapper.insert(tsFiles); - if (valueAdded == 1) { - returnResult = "压缩成功"; + LambdaQueryWrapper queryWrapperTsFiles = new LambdaQueryWrapper<>(); + queryWrapperTsFiles.eq(TsFiles::getNodeId, filesList.get(0).getNodeId()); + queryWrapperTsFiles.eq(TsFiles::getTaskId, filesList.get(0).getTaskId()); + queryWrapperTsFiles.eq(TsFiles::getWorkPath, workPath); + queryWrapperTsFiles.eq(TsFiles::getFileName, zipFileName); + queryWrapperTsFiles.eq(TsFiles::getParentId, filesList.get(0).getParentId()); + TsFiles tsFilesdata = tsFilesMapper.selectOne(queryWrapperTsFiles); + //covered 是否覆盖 0 覆盖更新updateTime时间 1提示文件存在 + if ("0".equals(covered)) { + //如果不为空 更新updateTime时间 + if (tsFilesdata != null) { + tsFilesdata.setUpdateTime(currentTime); + tsFilesMapper.updateById(tsFilesdata); } else { - returnResult = "压缩失败"; + //如果为空就新增 + int valueAdded = tsFilesMapper.insert(tsFiles); + if (valueAdded == 1) { + returnResult = "压缩成功"; + } else { + returnResult = "压缩失败"; + } + } + + } else { + // 1提示文件存在 如果不为空返回提示 + if (tsFilesdata != null) { + returnResult = "文件或文件夹已存在!"; + } else { + //如果为空就新增 + int valueAdded = tsFilesMapper.insert(tsFiles); + if (valueAdded == 1) { + returnResult = "压缩成功"; + } else { + returnResult = "压缩失败"; + } } } - + returnResult = "压缩成功"; } else { - // 1提示文件存在 如果不为空返回提示 - if (tsFilesdata != null) { - returnResult = "文件或文件夹已存在!"; - } else { - //如果为空就新增 - int valueAdded = tsFilesMapper.insert(tsFiles); - if (valueAdded == 1) { - returnResult = "压缩成功"; - } else { - returnResult = "压缩失败"; - } - } + returnResult = "压缩失败"; } - returnResult = "压缩成功"; - } else { - returnResult = "压缩失败"; + return returnResult; + } catch (Exception e) { + LOGGER.error("压缩时发生异常: {}", e.getMessage(), e); + return "压缩失败"; + } finally { + TableNameContextHolder.clear(); } - return returnResult; } @@ -1399,7 +1464,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl //上传人是当前登录人 UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - + TsTask tsTask = tsTaskMapper.selectById(taskId); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); // 1. 解析路径,提取有效层级目录名(跳过nodeId部分) List pathSegments = Arrays.stream(compressedPath.split("/")) @@ -1425,7 +1491,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl // //本地创建文件夹 NewFolderRequest newFolderRequest = new NewFolderRequest(); - newFolderRequest.setStorageKey("local"); + newFolderRequest.setStorageKey(storageSource.getKey()); newFolderRequest.setPath(currentPath); newFolderRequest.setPassword(null); newFolderRequest.setName(dirName); @@ -1840,119 +1906,128 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ @Override - public String decompressionFolder(String id, String decompressionPath, String parentId, String path) { - // 查询本地文件路径根目录(如 E:\yun) - StorageSourceConfig storageSourceConfig = getStorageConfig("filePath", "local"); - decompressionPath = normalizePath(decompressionPath); - // 1. 获取压缩包记录 - TsFiles zipFileRecord = tsFilesMapper.selectById(id); + public String decompressionFolder(String id, String decompressionPath, String parentId, String path, String taskId) { try { - LOGGER.info("解压缩压缩之前的时候删除Redis"); - //todo 解压缩的时候删除Redis - if (!parentId.equals("00")) { - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + zipFileRecord.getTaskId() + "_" + zipFileRecord.getNodeId() + "_parentId" + parentId + "_page_" + page; - redisTemplate.delete(redisKey); + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 查询本地文件路径根目录(如 E:\yun) + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + decompressionPath = normalizePath(decompressionPath); + TsFiles zipFileRecord = tsFilesMapper.selectById(id); + try { + + LOGGER.info("解压缩压缩之前的时候删除Redis"); + //todo 解压缩的时候删除Redis + if (!parentId.equals("00")) { + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + zipFileRecord.getTaskId() + "_" + zipFileRecord.getNodeId() + "_parentId" + parentId + "_page_" + page; + redisTemplate.delete(redisKey); + } } - } - String finalParentId = ensureFullPathExists(decompressionPath, zipFileRecord.getNodeId(), zipFileRecord.getTaskId(), path); - parentId = finalParentId; + String finalParentId = ensureFullPathExists(decompressionPath, zipFileRecord.getNodeId(), zipFileRecord.getTaskId(), path); + parentId = finalParentId; - LOGGER.info("解压缩的时候删除Redis"); - //todo 解压缩的时候删除Redis - if (!parentId.equals("00")) { - for (int page = 1; page <= 5; page++) { - String redisKey = "tsfiles_" + zipFileRecord.getTaskId() + "_" + zipFileRecord.getNodeId() + "_parentId" + parentId + "_page_" + page; - redisTemplate.delete(redisKey); - } - } - - LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); - } catch (RuntimeException e) { - LOGGER.error("路径创建失败: {}", e.getMessage()); - return "路径创建失败!"; - } - //解压以后的路径 - String extractPath = normalizePath(path + decompressionPath); - - String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例:222 - try { - // 2. 判断压缩包类型(单文件还是文件夹) - Path zipFilePath = Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()); - // 3. 判断压缩包内容类型 - boolean hasFolder = hasFolder(zipFilePath); -// // 4. 构建解压目标路径 - Path destRoot; - if (hasFolder) { - // 如果有文件夹,创建子目录(如 E:/yun/333/222/) - destRoot = Paths.get(storageSourceConfig.getValue(), extractPath, zipName); - } else { - // 如果只有文件,直接解压到目标目录(如 E:/yun/333/) - destRoot = Paths.get(storageSourceConfig.getValue(), extractPath); - } - Files.createDirectories(destRoot); - - // 5.执行解压(到子目录) - File unzippedRoot = unzipToTemp( - Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()), - destRoot.toString() - ); - - // 6. 处理解压内容 - if (hasFolder) { - // 如果有文件夹,创建文件夹记录并处理子内容 - TsFiles rootFolder = createFolderRecord( - zipName, // 文件夹名称222 - parentId, // 父ID是333的ID - buildFolderPath(extractPath), // 修正为 /333/222/ - zipFileRecord.getTaskId(), - zipFileRecord.getNodeId(), - zipFileRecord.getUploader() - ); - String rootFolderId = rootFolder.getId(); - - // 7. 处理子内容(路径从/333/222/开始) 关键点 所有的文件夹都是上级路径 文件是上级路径加名称 - processFolderContents( - unzippedRoot, - rootFolderId, - buildFolderPath(extractPath + "/" + zipName + "/"), // 修正为 /333/222/ - zipFileRecord.getTaskId(), - zipFileRecord.getNodeId(), - zipFileRecord.getUploader() - ); - } else { - // 如果只有文件,直接创建文件记录 - File[] files = unzippedRoot.listFiles(); - if (files != null && files.length > 0) { - for (File file : files) { - if (file.isDirectory()) { - continue; - } else { - // 获取文件大小(字节) - long fileSizeInBytes = file.length(); - // 转换为 KB 并保留两位小数 - double fileSizeInKB = fileSizeInBytes / (1024.0); - String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 - - TsFiles fileRecord = createFileRecord( - file.getName(), - parentId, - buildFolderPath(extractPath), - zipFileRecord.getTaskId(), - zipFileRecord.getNodeId(), - zipFileRecord.getUploader(), - fileSizeFormatted - ); - } + LOGGER.info("解压缩的时候删除Redis"); + //todo 解压缩的时候删除Redis + if (!parentId.equals("00")) { + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + zipFileRecord.getTaskId() + "_" + zipFileRecord.getNodeId() + "_parentId" + parentId + "_page_" + page; + redisTemplate.delete(redisKey); } } + LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); + } catch (RuntimeException e) { + LOGGER.error("路径创建失败: {}", e.getMessage()); + return "路径创建失败!"; + } + //解压以后的路径 + String extractPath = normalizePath(path + decompressionPath); + + String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例:222 + try { + // 2. 判断压缩包类型(单文件还是文件夹) + Path zipFilePath = Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()); + // 3. 判断压缩包内容类型 + boolean hasFolder = hasFolder(zipFilePath); +// // 4. 构建解压目标路径 + Path destRoot; + if (hasFolder) { + // 如果有文件夹,创建子目录(如 E:/yun/333/222/) + destRoot = Paths.get(storageSourceConfig.getValue(), extractPath, zipName); + } else { + // 如果只有文件,直接解压到目标目录(如 E:/yun/333/) + destRoot = Paths.get(storageSourceConfig.getValue(), extractPath); + } + Files.createDirectories(destRoot); + + // 5.执行解压(到子目录) + File unzippedRoot = unzipToTemp( + Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()), + destRoot.toString() + ); + + // 6. 处理解压内容 + if (hasFolder) { + // 如果有文件夹,创建文件夹记录并处理子内容 + TsFiles rootFolder = createFolderRecord( + zipName, // 文件夹名称222 + parentId, // 父ID是333的ID + buildFolderPath(extractPath), // 修正为 /333/222/ + zipFileRecord.getTaskId(), + zipFileRecord.getNodeId(), + zipFileRecord.getUploader() + ); + String rootFolderId = rootFolder.getId(); + + // 7. 处理子内容(路径从/333/222/开始) 关键点 所有的文件夹都是上级路径 文件是上级路径加名称 + processFolderContents( + unzippedRoot, + rootFolderId, + buildFolderPath(extractPath + "/" + zipName + "/"), // 修正为 /333/222/ + zipFileRecord.getTaskId(), + zipFileRecord.getNodeId(), + zipFileRecord.getUploader() + ); + } else { + // 如果只有文件,直接创建文件记录 + File[] files = unzippedRoot.listFiles(); + if (files != null && files.length > 0) { + for (File file : files) { + if (file.isDirectory()) { + continue; + } else { + // 获取文件大小(字节) + long fileSizeInBytes = file.length(); + // 转换为 KB 并保留两位小数 + double fileSizeInKB = fileSizeInBytes / (1024.0); + String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 + + TsFiles fileRecord = createFileRecord( + file.getName(), + parentId, + buildFolderPath(extractPath), + zipFileRecord.getTaskId(), + zipFileRecord.getNodeId(), + zipFileRecord.getUploader(), + fileSizeFormatted + ); + } + } + } + + } + return "解压存储成功"; + } catch (Exception e) { + LOGGER.error("解压失败: " + e.getMessage()); + throw new RuntimeException("操作失败: " + e.getMessage()); } - return "解压存储成功"; } catch (Exception e) { - LOGGER.error("解压失败: " + e.getMessage()); - throw new RuntimeException("操作失败: " + e.getMessage()); + LOGGER.error("新增试验数据管理文档内容时发生异常: {}", e.getMessage(), e); + return "解压缩失败"; + } finally { + TableNameContextHolder.clear(); } } @@ -2643,67 +2718,76 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public Page compareLocal(List dataset, String nodeId, String taskId, Page page) { - // ==================== 1. 构建查询条件 ==================== - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", - "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 - if (StringUtils.isNoneEmpty(nodeId, taskId)) { - queryWrapper.eq("node_id", nodeId) - .eq("task_id", taskId) - .isNotNull("work_path") - .ne("work_path", "") - .and(wq -> wq.isNull("backup_path").or().eq("backup_path", "")); - } else { - if (CollectionUtils.isEmpty(dataset)) { - throw new IllegalArgumentException("dataset参数不可为空"); // 优化点9:提前校验参数 + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // ==================== 1. 构建查询条件 ==================== + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 + + if (StringUtils.isNoneEmpty(nodeId, taskId)) { + queryWrapper.eq("node_id", nodeId) + .eq("task_id", taskId) + .isNotNull("work_path") + .ne("work_path", "") + .and(wq -> wq.isNull("backup_path").or().eq("backup_path", "")); + } else { + if (CollectionUtils.isEmpty(dataset)) { + throw new IllegalArgumentException("dataset参数不可为空"); // 优化点9:提前校验参数 + } + queryWrapper.in("id", dataset); } - queryWrapper.in("id", dataset); - } - List parentFiles = tsFilesMapper.selectList(queryWrapper); + List parentFiles = tsFilesMapper.selectList(queryWrapper); - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - if (StringUtils.isNotBlank(nodeId) && StringUtils.isNotBlank(taskId)) { - for (TsFiles tsFiles : parentFiles) { + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + if (StringUtils.isNotBlank(nodeId) && StringUtils.isNotBlank(taskId)) { + for (TsFiles tsFiles : parentFiles) { // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 - // 如果备份路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getBackupPath())) { - allFiles.add(tsFiles); + // 如果备份路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getBackupPath())) { + allFiles.add(tsFiles); + } } - } - } else { - for (TsFiles tsFiles : parentFiles) { + } else { + for (TsFiles tsFiles : parentFiles) { // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 - // 如果备份路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getBackupPath()) && "FILE".equals(tsFiles.getIsFile())) { - allFiles.add(tsFiles); - } - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); + // 如果备份路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getBackupPath()) && "FILE".equals(tsFiles.getIsFile())) { + allFiles.add(tsFiles); + } + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); + } } } + + + // ==================== 3. 内存分页处理 ==================== + int total = allFiles.size(); + int pageSize = (int) page.getSize(); + int currentPage = (int) page.getCurrent(); + int fromIndex = (currentPage - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, total); + + // 构建分页结果 + Page resultPage = new Page<>(currentPage, pageSize, total); + if (fromIndex < total) { + resultPage.setRecords(allFiles.subList(fromIndex, toIndex)); + } else { + resultPage.setRecords(Collections.emptyList()); + } + return resultPage; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - - - // ==================== 3. 内存分页处理 ==================== - int total = allFiles.size(); - int pageSize = (int) page.getSize(); - int currentPage = (int) page.getCurrent(); - int fromIndex = (currentPage - 1) * pageSize; - int toIndex = Math.min(fromIndex + pageSize, total); - - // 构建分页结果 - Page resultPage = new Page<>(currentPage, pageSize, total); - if (fromIndex < total) { - resultPage.setRecords(allFiles.subList(fromIndex, toIndex)); - } else { - resultPage.setRecords(Collections.emptyList()); - } - return resultPage; - } // 递归查询所有子节点 @@ -2740,43 +2824,52 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public List compareLocalList(List dataset, String nodeId, String taskId) { - // ==================== 1. 构建查询条件 ==================== - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", - "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // ==================== 1. 构建查询条件 ==================== + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 - if (StringUtils.isNoneEmpty(nodeId, taskId)) { - queryWrapper.eq("node_id", nodeId) - .eq("task_id", taskId) - .isNotNull("work_path") - .ne("work_path", "") - .and(wq -> wq.isNull("backup_path").or().eq("backup_path", "")); - } else { - if (CollectionUtils.isEmpty(dataset)) { - throw new IllegalArgumentException("dataset参数不可为空"); // 优化点9:提前校验参数 + if (StringUtils.isNoneEmpty(nodeId, taskId)) { + queryWrapper.eq("node_id", nodeId) + .eq("task_id", taskId) + .isNotNull("work_path") + .ne("work_path", "") + .and(wq -> wq.isNull("backup_path").or().eq("backup_path", "")); + } else { + if (CollectionUtils.isEmpty(dataset)) { + throw new IllegalArgumentException("dataset参数不可为空"); // 优化点9:提前校验参数 + } + queryWrapper.in("id", dataset); + } + List records = tsFilesMapper.selectList(queryWrapper); + if (records == null) { + return records; } - queryWrapper.in("id", dataset); - } - List records = tsFilesMapper.selectList(queryWrapper); - if (records == null) { - return records; - } - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - for (TsFiles tsFiles : records) { - // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 - // 如果备份路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getBackupPath())) { - allFiles.add(tsFiles); + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + for (TsFiles tsFiles : records) { + // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 + // 如果备份路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getBackupPath())) { + allFiles.add(tsFiles); + } + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + List childFiles = getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); + } } - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - List childFiles = getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); - } + return allFiles; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - return allFiles; } /********************************** @@ -2794,67 +2887,77 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public Page compareMinio(List dataset, String nodeId, String taskId, Page page) { - // ==================== 1. 构建查询条件 ==================== - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", - "file_size", "work_path", "backup_path", "upload_time"); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + + // ==================== 1. 构建查询条件 ==================== + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); - if (StringUtils.isNoneEmpty(nodeId, taskId)) { - // 场景1:根据 nodeId + taskId 查询(确保数据库有联合索引) - queryWrapper.eq("node_id", nodeId) - .eq("task_id", taskId) - .isNotNull("backup_path") - .ne("backup_path", "") - .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); - } else { - // 场景2:根据 id 列表查询(id字段需有索引) - queryWrapper.in("id", dataset); + if (StringUtils.isNoneEmpty(nodeId, taskId)) { + // 场景1:根据 nodeId + taskId 查询(确保数据库有联合索引) + queryWrapper.eq("node_id", nodeId) + .eq("task_id", taskId) + .isNotNull("backup_path") + .ne("backup_path", "") + .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); + } else { + // 场景2:根据 id 列表查询(id字段需有索引) + queryWrapper.in("id", dataset); // .isNotNull("backup_path") // .ne("backup_path", "") // .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); - } - List parentFiles = tsFilesMapper.selectList(queryWrapper); - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - if (StringUtils.isNotBlank(nodeId) && StringUtils.isNotBlank(taskId)) { - for (TsFiles tsFiles : parentFiles) { - // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 - // 如果备份路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getWorkPath())) { - allFiles.add(tsFiles); + } + List parentFiles = tsFilesMapper.selectList(queryWrapper); + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + if (StringUtils.isNotBlank(nodeId) && StringUtils.isNotBlank(taskId)) { + for (TsFiles tsFiles : parentFiles) { + // tsFiles.setWorkPath(processingPath(tsFiles.getWorkPath(), tsFiles.getNodeId())); // 优化点11:路径处理内聚 + // 如果备份路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getWorkPath())) { + allFiles.add(tsFiles); + } + } + } else { + for (TsFiles tsFiles : parentFiles) { + // tsFiles.setBackupPath(processingPath(tsFiles.getBackupPath(), tsFiles.getNodeId())); + // 如果工作路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getWorkPath())) { + allFiles.add(tsFiles); + } + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + getChildFilesRecursiveMinio(tsFiles.getId(), allFiles); + } } } - } else { - for (TsFiles tsFiles : parentFiles) { - // tsFiles.setBackupPath(processingPath(tsFiles.getBackupPath(), tsFiles.getNodeId())); - // 如果工作路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getWorkPath())) { - allFiles.add(tsFiles); - } - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - getChildFilesRecursiveMinio(tsFiles.getId(), allFiles); - } + + + // ==================== 3. 内存分页处理 ==================== + int total = allFiles.size(); + int pageSize = (int) page.getSize(); + int currentPage = (int) page.getCurrent(); + int fromIndex = (currentPage - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, total); + + // 构建分页结果 + Page resultPage = new Page<>(currentPage, pageSize, total); + if (fromIndex < total) { + resultPage.setRecords(allFiles.subList(fromIndex, toIndex)); + } else { + resultPage.setRecords(Collections.emptyList()); } + return resultPage; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - - - // ==================== 3. 内存分页处理 ==================== - int total = allFiles.size(); - int pageSize = (int) page.getSize(); - int currentPage = (int) page.getCurrent(); - int fromIndex = (currentPage - 1) * pageSize; - int toIndex = Math.min(fromIndex + pageSize, total); - - // 构建分页结果 - Page resultPage = new Page<>(currentPage, pageSize, total); - if (fromIndex < total) { - resultPage.setRecords(allFiles.subList(fromIndex, toIndex)); - } else { - resultPage.setRecords(Collections.emptyList()); - } - return resultPage; } // 递归查询所有子节点 @@ -2886,46 +2989,56 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public List compareMinioList(List dataset, String nodeId, String taskId) { - // ==================== 1. 构建查询条件 ==================== - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", - "file_size", "work_path", "backup_path", "upload_time"); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + + // ==================== 1. 构建查询条件 ==================== + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); - if (StringUtils.isNoneEmpty(nodeId, taskId)) { - // 场景1:根据 nodeId + taskId 查询(确保数据库有联合索引) - queryWrapper.eq("node_id", nodeId) - .eq("task_id", taskId) - .isNotNull("backup_path") - .ne("backup_path", "") - .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); - } else { - // 场景2:根据 id 列表查询(id字段需有索引) - queryWrapper.in("id", dataset); + if (StringUtils.isNoneEmpty(nodeId, taskId)) { + // 场景1:根据 nodeId + taskId 查询(确保数据库有联合索引) + queryWrapper.eq("node_id", nodeId) + .eq("task_id", taskId) + .isNotNull("backup_path") + .ne("backup_path", "") + .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); + } else { + // 场景2:根据 id 列表查询(id字段需有索引) + queryWrapper.in("id", dataset); // .isNotNull("backup_path") // .ne("backup_path", "") // .and(wq -> wq.isNull("work_path").or().eq("work_path", "")); - } - List records = tsFilesMapper.selectList(queryWrapper); - if (records == null) { - return records; - - } - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - for (TsFiles tsFiles : records) { - //tsFiles.setBackupPath(processingPath(tsFiles.getBackupPath(), tsFiles.getNodeId())); - // 如果工作路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getWorkPath())) { - allFiles.add(tsFiles); + } + List records = tsFilesMapper.selectList(queryWrapper); + if (records == null) { + return records; } - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - List childFiles = getChildFilesRecursiveMinio(tsFiles.getId(), allFiles); + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + for (TsFiles tsFiles : records) { + //tsFiles.setBackupPath(processingPath(tsFiles.getBackupPath(), tsFiles.getNodeId())); + // 如果工作路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getWorkPath())) { + allFiles.add(tsFiles); + + } + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + List childFiles = getChildFilesRecursiveMinio(tsFiles.getId(), allFiles); + } } + return allFiles; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - return allFiles; } @@ -2938,138 +3051,156 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public Page compareMd5(List dataset, String nodeId, String taskId, Page page) { - // 获取本地文件路径根目录和存储空间名称 - StorageSourceConfig filePathConfig = getStorageConfig("filePath", "local"); - StorageSourceConfig bucketConfig = getStorageConfig("bucketName", "minio"); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 获取本地文件路径根目录和存储空间名称 + StorageSourceConfig filePathConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + StorageSourceConfig bucketConfig = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); - // ================ 1. 执行原始分页查询 ================ - QueryWrapper queryWrapper = buildQueryWrapper(dataset, nodeId, taskId); - Page tsFilesPage = tsFilesMapper.selectPage(page, queryWrapper); + // ================ 1. 执行原始分页查询 ================ + QueryWrapper queryWrapper = buildQueryWrapper(dataset, nodeId, taskId); + Page tsFilesPage = tsFilesMapper.selectPage(page, queryWrapper); - if (StringUtils.isEmpty(nodeId) || StringUtils.isEmpty(taskId)) { - if (tsFilesPage == null) { - tsFilesPage = new Page<>(); - tsFilesPage.setRecords(new ArrayList<>()); // 确保 records 被初始化 - } - - List records = tsFilesPage.getRecords(); - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - for (TsFiles tsFiles : records) { - // 将当前节点加入结果列表 - allFiles.add(tsFiles); - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - List childFiles = getChildFilesRecursiveMd5(tsFiles.getId(), allFiles); + if (StringUtils.isEmpty(nodeId) || StringUtils.isEmpty(taskId)) { + if (tsFilesPage == null) { + tsFilesPage = new Page<>(); + tsFilesPage.setRecords(new ArrayList<>()); // 确保 records 被初始化 } - } - tsFilesPage.setRecords(allFiles); // 同步到 tsFilesPage - System.out.println("Updated records: " + allFiles); - } - - // ================ 2. 过滤并处理符合条件的记录 ================ - List filteredRecords = tsFilesPage.getRecords().stream() - .filter(tsFile -> { - try { - // 计算本地文件MD5 - File localFile = new File(filePathConfig.getValue() + tsFile.getWorkPath(), tsFile.getFileName()); - String localMD5 = calculateMD5Data(new FileInputStream(localFile)); - - // 计算MinIO文件MD5 - - String minioMD5 = getMinioMD5Data(bucketConfig.getValue(), tsFile.getBackupPath(), tsFile.getFileName()); - - // 路径处理 - //tsFile.setWorkPath(processingPath(tsFile.getWorkPath(), tsFile.getNodeId())); - // tsFile.setBackupPath(processingPath(tsFile.getBackupPath(), tsFile.getNodeId())); - - // 设置MD5字段(即使不满足条件也保留字段) - tsFile.setLocatMd5(localMD5); - tsFile.setMinioMd5(minioMD5); - - // 返回是否满足过滤条件 - return StringUtils.isNoneEmpty(localMD5, minioMD5) && !localMD5.equals(minioMD5); - } catch (Exception e) { - LOGGER.error("MD5计算失败: {}", tsFile.getFileName(), e); - return false; + List records = tsFilesPage.getRecords(); + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + for (TsFiles tsFiles : records) { + // 将当前节点加入结果列表 + allFiles.add(tsFiles); + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + List childFiles = getChildFilesRecursiveMd5(tsFiles.getId(), allFiles); } - }) - .collect(Collectors.toList()); + } + tsFilesPage.setRecords(allFiles); // 同步到 tsFilesPage + System.out.println("Updated records: " + allFiles); + } + + // ================ 2. 过滤并处理符合条件的记录 ================ + List filteredRecords = tsFilesPage.getRecords().stream() + .filter(tsFile -> { + try { + // 计算本地文件MD5 + File localFile = new File(filePathConfig.getValue() + tsFile.getWorkPath(), tsFile.getFileName()); + String localMD5 = calculateMD5Data(new FileInputStream(localFile)); + + // 计算MinIO文件MD5 + + String minioMD5 = getMinioMD5Data(bucketConfig.getValue(), tsFile.getBackupPath(), tsFile.getFileName()); + + // 路径处理 + //tsFile.setWorkPath(processingPath(tsFile.getWorkPath(), tsFile.getNodeId())); + // tsFile.setBackupPath(processingPath(tsFile.getBackupPath(), tsFile.getNodeId())); + + // 设置MD5字段(即使不满足条件也保留字段) + tsFile.setLocatMd5(localMD5); + tsFile.setMinioMd5(minioMD5); + + // 返回是否满足过滤条件 + return StringUtils.isNoneEmpty(localMD5, minioMD5) && !localMD5.equals(minioMD5); + } catch (Exception e) { + LOGGER.error("MD5计算失败: {}", tsFile.getFileName(), e); + return false; + } + }) + .collect(Collectors.toList()); - // ================ 3. 构建新的分页结果 ================ - Page resultPage = new Page<>(); - resultPage.setRecords(filteredRecords); // 过滤后的数据 - resultPage.setTotal(filteredRecords.size()); // 总记录数为当前页过滤后数量 - resultPage.setCurrent(page.getCurrent()); // 保持当前页码 - resultPage.setSize(page.getSize()); // 保持每页大小 - resultPage.setPages( // 重新计算总页数 - (filteredRecords.size() + page.getSize() - 1) / page.getSize() - ); + // ================ 3. 构建新的分页结果 ================ + Page resultPage = new Page<>(); + resultPage.setRecords(filteredRecords); // 过滤后的数据 + resultPage.setTotal(filteredRecords.size()); // 总记录数为当前页过滤后数量 + resultPage.setCurrent(page.getCurrent()); // 保持当前页码 + resultPage.setSize(page.getSize()); // 保持每页大小 + resultPage.setPages( // 重新计算总页数 + (filteredRecords.size() + page.getSize() - 1) / page.getSize() + ); - return resultPage; + return resultPage; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); + } } @Override public List compareMd5List(List dataset, String nodeId, String taskId) { - // 获取本地文件路径根目录和存储空间名称 - StorageSourceConfig filePathConfig = getStorageConfig("filePath", "local"); - StorageSourceConfig bucketConfig = getStorageConfig("bucketName", "minio"); - // ================ 1. 执行原始分页查询 ================ - QueryWrapper queryWrapper = buildQueryWrapper(dataset, nodeId, taskId); - List records = tsFilesMapper.selectList(queryWrapper); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 获取本地文件路径根目录和存储空间名称 + StorageSourceConfig filePathConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + StorageSourceConfig bucketConfig = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); - if (StringUtils.isEmpty(nodeId) || StringUtils.isEmpty(taskId)) { - if (records == null) { - return records; - } + // ================ 1. 执行原始分页查询 ================ + QueryWrapper queryWrapper = buildQueryWrapper(dataset, nodeId, taskId); + List records = tsFilesMapper.selectList(queryWrapper); - // 递归查询每个记录的子节点,并添加到 records 中 - List allFiles = new ArrayList<>(); - for (TsFiles tsFiles : records) { - // 将当前节点加入结果列表 - allFiles.add(tsFiles); - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - List childFiles = getChildFilesRecursiveMd5(tsFiles.getId(), allFiles); + if (StringUtils.isEmpty(nodeId) || StringUtils.isEmpty(taskId)) { + if (records == null) { + return records; + } + + // 递归查询每个记录的子节点,并添加到 records 中 + List allFiles = new ArrayList<>(); + for (TsFiles tsFiles : records) { + // 将当前节点加入结果列表 + allFiles.add(tsFiles); + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + List childFiles = getChildFilesRecursiveMd5(tsFiles.getId(), allFiles); + } } } + + // ================ 2. 过滤并处理符合条件的记录 ================ + List filteredRecords = records.stream() + .filter(tsFile -> { + try { + // 计算本地文件MD5 + File localFile = new File(filePathConfig.getValue() + tsFile.getWorkPath(), tsFile.getFileName()); + String localMD5 = calculateMD5Data(new FileInputStream(localFile)); + + // 计算MinIO文件MD5 + + String minioMD5 = getMinioMD5Data(bucketConfig.getValue(), tsFile.getBackupPath(), tsFile.getFileName()); + + // 路径处理 + // tsFile.setWorkPath(processingPath(tsFile.getWorkPath(), tsFile.getNodeId())); + // tsFile.setBackupPath(processingPath(tsFile.getBackupPath(), tsFile.getNodeId())); + + // 设置MD5字段(即使不满足条件也保留字段) + tsFile.setLocatMd5(localMD5); + tsFile.setMinioMd5(minioMD5); + + // 返回是否满足过滤条件 + return StringUtils.isNoneEmpty(localMD5, minioMD5) && !localMD5.equals(minioMD5); + } catch (Exception e) { + LOGGER.error("MD5计算失败: {}", tsFile.getFileName(), e); + return false; + } + }) + .collect(Collectors.toList()); + + return filteredRecords; + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - - // ================ 2. 过滤并处理符合条件的记录 ================ - List filteredRecords = records.stream() - .filter(tsFile -> { - try { - // 计算本地文件MD5 - File localFile = new File(filePathConfig.getValue() + tsFile.getWorkPath(), tsFile.getFileName()); - String localMD5 = calculateMD5Data(new FileInputStream(localFile)); - - // 计算MinIO文件MD5 - - String minioMD5 = getMinioMD5Data(bucketConfig.getValue(), tsFile.getBackupPath(), tsFile.getFileName()); - - // 路径处理 - // tsFile.setWorkPath(processingPath(tsFile.getWorkPath(), tsFile.getNodeId())); - // tsFile.setBackupPath(processingPath(tsFile.getBackupPath(), tsFile.getNodeId())); - - // 设置MD5字段(即使不满足条件也保留字段) - tsFile.setLocatMd5(localMD5); - tsFile.setMinioMd5(minioMD5); - - // 返回是否满足过滤条件 - return StringUtils.isNoneEmpty(localMD5, minioMD5) && !localMD5.equals(minioMD5); - } catch (Exception e) { - LOGGER.error("MD5计算失败: {}", tsFile.getFileName(), e); - return false; - } - }) - .collect(Collectors.toList()); - - return filteredRecords; } @@ -3160,12 +3291,6 @@ public class TsFilesServiceImpl extends ServiceImpl impl } } - // 辅助方法:获取存储配置 - private StorageSourceConfig getStorageConfig(String name, String type) { - return storageSourceConfigMapper.selectOne( - new QueryWrapper().eq("name", name).eq("type", type) - ); - } /** * 确保路径格式为以 "/" 开头和结尾(例如 "/data/test/") @@ -3200,122 +3325,130 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public Boolean uploadToBackup(Parameter parameter) { Boolean value = false; + try { + TsTask tsTask = tsTaskMapper.selectById(parameter.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSourceLocal = getStorageConfig(tsTask.getLocalStorageId()); + StorageSource storageSourceMinio = getStorageConfig(tsTask.getBackupStorageId()); + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + StorageSourceConfig storageSourceConfig1 = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); + List parameterLists = parameter.getParameterLists(); - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); + // 在循环前记录开始时间 + long startTime = System.currentTimeMillis(); + //循环一条一条上传 + for (ParameterList parameterListData : parameterLists) { + if ("FOLDER".equals(parameterListData.getType())) { + String name = parameterListData.getName(); + // 处理路径格式 + String path = normalizePath(parameterListData.getPath()); + String minioPath = path;//// MinIO上传目标路径 + // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 + // 查询当前文件记录 + TsFiles currentFile = getFileRecord(name, path); + if (currentFile == null) return false; - StorageSourceConfig storageSourceConfig = getStorageConfig("filePath", "local"); - - StorageSourceConfig storageSourceConfig1 = getStorageConfig("bucketName", "minio"); - - - List parameterLists = parameter.getParameterLists(); - - //循环一条一条上传 - for (ParameterList parameterListData : parameterLists) { - if ("FOLDER".equals(parameterListData.getType())) { - String name = parameterListData.getName(); - String path = parameterListData.getPath(); - // 处理路径格式 - path = normalizePath(path); - - - String localPath = storageSourceConfig.getValue() + path;//localPath是本地的路径 - String minioPath = path;//// MinIO上传目标路径 - // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 - // 查询当前文件记录 - TsFiles currentFile = getFileRecord(name, path); - if (currentFile == null) return false; - - // 递归创建父文件夹 - boolean parentsCreated = createParentFolders(currentFile.getParentId()); - if (!parentsCreated) { - LOGGER.error("父文件夹创建失败"); - return false; - } - - //新增节点的时候 创建文件夹 - NewFolderRequest newFolderRequest = new NewFolderRequest(); - newFolderRequest.setName(currentFile.getFileName());//新建的文件夹名称,示例值(/a/b/c) - newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) - newFolderRequest.setPath(minioPath);//请求路径,示例值(/) - newFolderRequest.setStorageKey("minio");//存储源 key,示例值(local minio) - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); - boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); - LOGGER.info("同步本地到minio文件夹路径加名称" + newFolderRequest.getPath() + newFolderRequest.getName()); - - //如果文件夹创建成功 - if (flag) { - currentFile.setUpdateTime(currentTime); - currentFile.setBackupPath(minioPath); - int valueAdded = tsFilesMapper.updateById(currentFile); - if (valueAdded == 1) { - LOGGER.info("同步本地到minio,minio文件夹创建成功,表结构修改成功。"); - value = true; - } else { - LOGGER.error("同步本地到minio,minio文件夹创建成功,表结构修改失败"); - value = false; + // 递归创建父文件夹 + boolean parentsCreated = createParentFolders(currentFile.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; } - } else { - LOGGER.error("同步本地到minio,minio文件夹创建失败"); - value = false; - } - } else { + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(currentFile.getFileName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(minioPath);//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSourceMinio.getKey());//存储源 key,示例值(local minio) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + LOGGER.info("同步本地到minio文件夹路径加名称" + newFolderRequest.getPath() + newFolderRequest.getName()); - String name = parameterListData.getName(); - String path = parameterListData.getPath(); - String size = parameterListData.getSize(); - // 处理路径格式 - path = normalizePath(path); - - String localPath = storageSourceConfig.getValue() + path;//localPath是本地的路径 - String minioPath = path;//// MinIO上传目标路径 - - // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 - Path FilePath = Paths.get(localPath, name); - // 4. 上传压缩文件到MinIO - File zipFile = FilePath.toFile(); // 获取本地文件 - - // 查询当前文件记录 - TsFiles currentFile = getFileRecord(name, path); - if (currentFile == null) { - return false; - } - - // 递归创建父文件夹 - boolean parentsCreated = createParentFolders(currentFile.getParentId()); - if (!parentsCreated) { - LOGGER.error("父文件夹创建失败"); - return false; - } - //把本地文件上传到minio - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("minio"); - boolean flag1 = fileService.UploadFiles(storageSourceConfig1.getValue(), minioPath + name, zipFile); - LOGGER.info("同步本地到minio文件路径加名称" + storageSourceConfig1.getValue() + minioPath + name); - - //如果上传成功 修改 表结构 - if (flag1) { - currentFile.setUpdateTime(currentTime); - currentFile.setBackupPath(minioPath); - int valueAdded = tsFilesMapper.updateById(currentFile); - if (valueAdded == 1) { - LOGGER.info("同步本地到minio,minio文件创建成功,表结构修改成功。"); + //如果文件夹创建成功 + if (flag) { + LOGGER.info("同步本地到minio,minio文件夹创建成功"); value = true; +// currentFile.setUpdateTime(currentTime); +// currentFile.setBackupPath(minioPath); +// int valueAdded = tsFilesMapper.updateById(currentFile); +// if (valueAdded == 1) { +// LOGGER.info("同步本地到minio,minio文件夹创建成功,表结构修改成功。"); +// value = true; +// } else { +// LOGGER.error("同步本地到minio,minio文件夹创建成功,表结构修改失败"); +// value = false; +// } + } else { - LOGGER.error("同步本地到minio,minio文件创建成功,表结构修改失败"); + LOGGER.error("同步本地到minio,minio文件夹创建失败"); value = false; } } else { - LOGGER.error("同步本地到minio,minio文件创建失败"); - value = false; + + String name = parameterListData.getName(); + // 处理路径格式 + String path = normalizePath(parameterListData.getPath()); + + String localPath = storageSourceConfig.getValue() + path;//localPath是本地的路径 + String minioPath = path;//// MinIO上传目标路径 + + // 使用Java NIO的Path类来构造压缩文件的完整路径,存储在localPath目录下 + Path FilePath = Paths.get(localPath, name); + // 4. 上传压缩文件到MinIO + File zipFile = FilePath.toFile(); // 获取本地文件 + + // 查询当前文件记录 + TsFiles currentFile = getFileRecord(name, path); + if (currentFile == null) { + return false; + } + + // 递归创建父文件夹 + boolean parentsCreated = createParentFolders(currentFile.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; + } + //把本地文件上传到minio + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("minio"); + boolean flag1 = fileService.UploadFiles(storageSourceConfig1.getValue(), minioPath + name, zipFile); + LOGGER.info("同步本地到minio文件路径加名称" + storageSourceConfig1.getValue() + minioPath + name); + + //如果上传成功 修改 表结构 + if (flag1) { + LOGGER.info("同步本地到minio,minio文件创建成功"); + value = true; + +// currentFile.setUpdateTime(currentTime); +// currentFile.setBackupPath(minioPath); +// int valueAdded = tsFilesMapper.updateById(currentFile); +// if (valueAdded == 1) { +// LOGGER.info("同步本地到minio,minio文件创建成功,表结构修改成功。"); +// value = true; +// } else { +// LOGGER.error("同步本地到minio,minio文件创建成功,表结构修改失败"); +// value = false; +// } + } else { + LOGGER.error("同步本地到minio,minio文件创建失败"); + value = false; + } } } + // 计算总耗时 + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + LOGGER.info("把本地文件放到minio循环执行耗时: {} 毫秒 (约 {} 秒)", totalTime, totalTime / 1000.0); + + return value; + } catch (Exception e) { + LOGGER.error("上传到备份空间时发生异常: {}", e.getMessage(), e); + return false; + } finally { + TableNameContextHolder.clear(); } - return value; } // 规范化路径格式 @@ -3361,11 +3494,13 @@ public class TsFilesServiceImpl extends ServiceImpl impl // 创建MinIO文件夹 private boolean createMinioFolder(TsFiles folder) { try { + TsTask tsTask = tsTaskMapper.selectById(folder.getTaskId()); + StorageSource storageSource = getStorageConfig(tsTask.getBackupStorageId()); // 设置当前时间 LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp Timestamp currentTime = Timestamp.valueOf(now); - AbstractBaseFileService minioService = storageSourceContext.getByStorageKey("minio"); + AbstractBaseFileService minioService = storageSourceContext.getByStorageKey(storageSource.getKey()); //String folderPath = folder.getWorkPath() + folder.getFileName() + "/"; String folderPath = folder.getWorkPath() + folder.getFileName(); @@ -3374,7 +3509,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl newFolderRequest.setName(folder.getFileName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(folder.getWorkPath());//请求路径,示例值(/) - newFolderRequest.setStorageKey("minio");//存储源 key,示例值(local minio) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { @@ -3412,7 +3547,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl public void automaticFileBackupAsyncByIds(List dataset, String taskId, String nodeId) throws IOException { try { // 执行实际备份逻辑 - this.automaticFileBackupByIds(dataset); + this.automaticFileBackupByIds(dataset, taskId, nodeId); } finally { // 生成唯一Key String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); @@ -3431,54 +3566,97 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public String automaticFileBackup(String taskId, String nodeId) { - //首先查询节点下面所有 备份路径为空的数据 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("node_id", nodeId); - queryWrapper.eq("task_id", taskId); - queryWrapper.and(wrapper -> wrapper.isNull("backup_path").or().eq("backup_path", "")); - queryWrapper.isNotNull("work_path").ne("work_path", ""); - List tsFilelist = tsFilesMapper.selectList(queryWrapper); - int FileCount = 0, FolderCount = 0; - int BackupsFileCount = 0, BackupsFolderCount = 0; + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + try { - if (tsFilelist.isEmpty()) { - return "本地有新增文件 " + FileCount + " 个, 文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; - } + //首先查询节点下面所有 备份路径为空的数据 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); + queryWrapper.eq("node_id", nodeId); + queryWrapper.eq("task_id", taskId); + queryWrapper.and(wrapper -> wrapper.isNull("backup_path").or().eq("backup_path", "")); + queryWrapper.isNotNull("work_path").ne("work_path", ""); + List tsFilelist = tsFilesMapper.selectList(queryWrapper); + int FileCount = 0, FolderCount = 0; + int BackupsFileCount = 0, BackupsFolderCount = 0; - for (TsFiles tsFiles : tsFilelist) { - ParameterList parameterList = new ParameterList(); - Parameter fileParameter = new Parameter(); - Parameter FolderParameter = new Parameter(); - List fileParameterlist = new ArrayList<>(); - List FolderParameterlist = new ArrayList<>(); - - if ("FILE".equals(tsFiles.getIsFile())) { - parameterList.setName(tsFiles.getFileName()); - parameterList.setPath(tsFiles.getWorkPath()); - parameterList.setSize(tsFiles.getFileSize()); - parameterList.setType(tsFiles.getIsFile()); - fileParameterlist.add(parameterList); - fileParameter.setParameterLists(fileParameterlist); - Boolean value = uploadToBackup(fileParameter); - if (value) { - BackupsFileCount++; - } - FileCount++; - } else { - parameterList.setName(tsFiles.getFileName()); - parameterList.setPath(tsFiles.getWorkPath()); - parameterList.setSize(tsFiles.getFileSize()); - parameterList.setType(tsFiles.getIsFile()); - FolderParameterlist.add(parameterList); - FolderParameter.setParameterLists(FolderParameterlist); - Boolean value = uploadToBackup(FolderParameter); - if (value) { - BackupsFolderCount++; - } - FolderCount++; + if (tsFilelist.isEmpty()) { + return "本地有新增文件 " + FileCount + " 个, 文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; } + + // 在循环前记录开始时间 + long startTime = System.currentTimeMillis(); + for (TsFiles tsFiles : tsFilelist) { + ParameterList parameterList = new ParameterList(); + Parameter fileParameter = new Parameter(); + Parameter FolderParameter = new Parameter(); + List fileParameterlist = new ArrayList<>(); + List FolderParameterlist = new ArrayList<>(); + + if ("FILE".equals(tsFiles.getIsFile())) { + parameterList.setName(tsFiles.getFileName()); + parameterList.setPath(tsFiles.getWorkPath()); + parameterList.setSize(tsFiles.getFileSize()); + parameterList.setType(tsFiles.getIsFile()); + fileParameterlist.add(parameterList); + fileParameter.setParameterLists(fileParameterlist); + fileParameter.setTaskId(taskId); + Boolean value = uploadToBackup(fileParameter); + if (value) { + BackupsFileCount++; + } + FileCount++; + } else { + parameterList.setName(tsFiles.getFileName()); + parameterList.setPath(tsFiles.getWorkPath()); + parameterList.setSize(tsFiles.getFileSize()); + parameterList.setType(tsFiles.getIsFile()); + FolderParameterlist.add(parameterList); + FolderParameter.setParameterLists(FolderParameterlist); + FolderParameter.setTaskId(taskId); + Boolean value = uploadToBackup(FolderParameter); + if (value) { + BackupsFolderCount++; + } + FolderCount++; + } + } + // 计算总耗时 + long endTime = System.currentTimeMillis(); + long totalTime = endTime - startTime; + LOGGER.info("循环执行耗时: {} 毫秒 (约 {} 秒)", totalTime, totalTime / 1000.0); + + //批量修改表结构在上下文中执行更新 + updateBackupPaths(taskId, nodeId); + + return "本地有新增文件 " + FileCount + " 个, 新增文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; + } catch (Exception e) { + // 日志记录异常信息 + LOGGER.error("自动备份失败:任务ID={}, 节点ID={}", taskId, nodeId, e); + // 返回错误信息 + return "自动备份失败:" + e.getMessage(); + } finally { + TableNameContextHolder.clear(); } - return "本地有新增文件 " + FileCount + " 个, 新增文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; + } + + // 辅助方法:更新备份路径 + private void updateBackupPaths(String taskId, String nodeId) { + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.setSql("backup_path = work_path") + .eq("node_id", nodeId) + .eq("task_id", taskId) + .and(wrapper -> wrapper.isNull("backup_path").or().eq("backup_path", "")); + tsFilesMapper.update(null, updateWrapper); + }finally { + TableNameContextHolder.clear(); + } + } /********************************** @@ -3487,65 +3665,101 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 参数说明 nodeId 任务ID * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败 ***********************************/ - public String automaticFileBackupByIds(List dataset) { + public String automaticFileBackupByIds(List dataset, String taskId, String nodeId) { - List allFiles = new ArrayList<>(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", - "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 - queryWrapper.in("id", dataset); - List records = tsFilesMapper.selectList(queryWrapper); - for (TsFiles tsFiles : records) { - // 如果备份路径为空 增加 将当前节点加入结果列表 - if (StringUtils.isEmpty(tsFiles.getBackupPath())) { - allFiles.add(tsFiles); - } - // 查询该节点的所有子节点并递归添加 - if ("FOLDER".equals(tsFiles.getIsFile())) { - List childFiles = getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); - } - } - int FileCount = 0, FolderCount = 0; - int BackupsFileCount = 0, BackupsFolderCount = 0; + try { - if (allFiles.isEmpty()) { - return "本地有新增文件 " + FileCount + " 个, 文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; - } - - for (TsFiles tsFiles : allFiles) { - ParameterList parameterList = new ParameterList(); - Parameter fileParameter = new Parameter(); - Parameter FolderParameter = new Parameter(); - List fileParameterlist = new ArrayList<>(); - List FolderParameterlist = new ArrayList<>(); - - if ("FILE".equals(tsFiles.getIsFile())) { - parameterList.setName(tsFiles.getFileName()); - parameterList.setPath(tsFiles.getWorkPath()); - parameterList.setSize(tsFiles.getFileSize()); - parameterList.setType(tsFiles.getIsFile()); - fileParameterlist.add(parameterList); - fileParameter.setParameterLists(fileParameterlist); - Boolean value = uploadToBackup(fileParameter); - if (value) { - BackupsFileCount++; + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + List allFiles = new ArrayList<>(); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.select("id", "node_id", "task_id", "is_file", "parent_id", "file_name", + "file_size", "work_path", "backup_path", "upload_time"); // 移除无用字段 + queryWrapper.eq("task_id", taskId); + queryWrapper.eq("node_id", nodeId); + queryWrapper.in("id", dataset); + List records = tsFilesMapper.selectList(queryWrapper); + for (TsFiles tsFiles : records) { + // 如果备份路径为空 增加 将当前节点加入结果列表 + if (StringUtils.isEmpty(tsFiles.getBackupPath())) { + allFiles.add(tsFiles); } - FileCount++; - } else { - parameterList.setName(tsFiles.getFileName()); - parameterList.setPath(tsFiles.getWorkPath()); - parameterList.setSize(tsFiles.getFileSize()); - parameterList.setType(tsFiles.getIsFile()); - FolderParameterlist.add(parameterList); - FolderParameter.setParameterLists(FolderParameterlist); - Boolean value = uploadToBackup(FolderParameter); - if (value) { - BackupsFolderCount++; + // 查询该节点的所有子节点并递归添加 + if ("FOLDER".equals(tsFiles.getIsFile())) { + List childFiles = getChildFilesRecursiveLocal(tsFiles.getId(), allFiles); } - FolderCount++; } + int FileCount = 0, FolderCount = 0; + int BackupsFileCount = 0, BackupsFolderCount = 0; + + if (allFiles.isEmpty()) { + return "本地有新增文件 " + FileCount + " 个, 文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; + } + + for (TsFiles tsFiles : allFiles) { + ParameterList parameterList = new ParameterList(); + Parameter fileParameter = new Parameter(); + Parameter FolderParameter = new Parameter(); + List fileParameterlist = new ArrayList<>(); + List FolderParameterlist = new ArrayList<>(); + + if ("FILE".equals(tsFiles.getIsFile())) { + parameterList.setName(tsFiles.getFileName()); + parameterList.setPath(tsFiles.getWorkPath()); + parameterList.setSize(tsFiles.getFileSize()); + parameterList.setType(tsFiles.getIsFile()); + fileParameterlist.add(parameterList); + fileParameter.setParameterLists(fileParameterlist); + fileParameter.setTaskId(taskId); + Boolean value = uploadToBackup(fileParameter); + if (value) { + BackupsFileCount++; + } + FileCount++; + } else { + parameterList.setName(tsFiles.getFileName()); + parameterList.setPath(tsFiles.getWorkPath()); + parameterList.setSize(tsFiles.getFileSize()); + parameterList.setType(tsFiles.getIsFile()); + FolderParameterlist.add(parameterList); + FolderParameter.setParameterLists(FolderParameterlist); + FolderParameter.setTaskId(taskId); + Boolean value = uploadToBackup(FolderParameter); + if (value) { + BackupsFolderCount++; + } + FolderCount++; + } + } + //批量修改表结构 + updateBackupPathsByIds(dataset, taskId, nodeId); + return "本地有新增文件 " + FileCount + " 个, 新增文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; + } catch (Exception e) { + // 日志记录异常信息 + LOGGER.error("自动备份失败:任务ID={}, 节点ID={}", taskId, nodeId, e); + // 返回错误信息 + return "自动备份失败:" + e.getMessage(); + } finally { + TableNameContextHolder.clear(); } - return "本地有新增文件 " + FileCount + " 个, 新增文件夹 " + FolderCount + " 个, 已将 " + BackupsFileCount + " 个文件, " + BackupsFolderCount + " 个文件夹备份成功"; + } + + // 辅助方法:更新备份路径 + private void updateBackupPathsByIds(List dataset, String taskId, String nodeId) { + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + UpdateWrapper updateWrapper = new UpdateWrapper<>(); + updateWrapper.setSql("backup_path = work_path"); + // 设置更新条件 + updateWrapper.in("id", dataset) + .and(wrapper -> wrapper.isNull("backup_path").or().eq("backup_path", "")); + // 执行更新 + tsFilesMapper.update(null, updateWrapper); + }finally { + TableNameContextHolder.clear(); + } + } @@ -3557,162 +3771,172 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public Boolean downloadToLocal(Parameter parameter) { Boolean value = true; + try { + TsTask tsTask = tsTaskMapper.selectById(parameter.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); - // 设置当前时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); - //上传人是当前登录人 - UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + //上传人是当前登录人 + UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - StorageSourceConfig storageSourceConfig = getStorageConfig("filePath", "local"); + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); - StorageSourceConfig storageSourceConfig1 = getStorageConfig("bucketName", "minio"); + StorageSourceConfig storageSourceConfig1 = getStorageSourceConfig("bucketName", "minio",tsTask.getBackupStorageId()); - List parameterLists = parameter.getParameterLists(); - for (ParameterList parameterListData : parameterLists) { - //创建文件夹 - if ("FOLDER".equals(parameterListData.getType())) { - String name = parameterListData.getName(); - String path = parameterListData.getPath(); - // 处理路径格式 - path = normalizePath(path); + List parameterLists = parameter.getParameterLists(); + for (ParameterList parameterListData : parameterLists) { + //创建文件夹 + if ("FOLDER".equals(parameterListData.getType())) { + String name = parameterListData.getName(); + String path = parameterListData.getPath(); + // 处理路径格式 + path = normalizePath(path); - //通过名称和minio路径查询表结构的数据 - QueryWrapper queryWrapperFile = new QueryWrapper<>(); - queryWrapperFile.eq("file_name", name); - queryWrapperFile.eq("backup_path", path); - TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFile); - if (tsFiles == null) { - return false; - } - LOGGER.info("同步minio到本地,查询的文件夹对象", tsFiles); + //通过名称和minio路径查询表结构的数据 + QueryWrapper queryWrapperFile = new QueryWrapper<>(); + queryWrapperFile.eq("file_name", name); + queryWrapperFile.eq("backup_path", path); + TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFile); + if (tsFiles == null) { + return false; + } + LOGGER.info("同步minio到本地,查询的文件夹对象", tsFiles); - // 递归创建父文件夹 - boolean parentsCreated = createLocalParentFolders(tsFiles.getParentId()); - if (!parentsCreated) { - LOGGER.error("父文件夹创建失败"); - return false; - } + // 递归创建父文件夹 + boolean parentsCreated = createLocalParentFolders(tsFiles.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; + } - //新增节点的时候 创建文件夹 - NewFolderRequest newFolderRequest = new NewFolderRequest(); - newFolderRequest.setName(tsFiles.getFileName());//新建的文件夹名称,示例值(/a/b/c) - newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) - newFolderRequest.setPath(path);//请求路径,示例值(/) - newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio) - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); - boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); - LOGGER.info("同步minio到本地文件夹路径加名称" + newFolderRequest.getPath() + newFolderRequest.getName()); + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(tsFiles.getFileName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(path);//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + LOGGER.info("同步minio到本地文件夹路径加名称" + newFolderRequest.getPath() + newFolderRequest.getName()); + + //如果文件夹创建成功 + if (flag) { + tsFiles.setUpdateTime(currentTime); + tsFiles.setWorkPath(path); + int valueAdded = tsFilesMapper.updateById(tsFiles); + if (valueAdded == 1) { + LOGGER.info("同步minio到本地,本地文件夹创建成功,表结构修改成功。"); + value = true; + } else { + LOGGER.error("同步minio到本地,本地文件夹创建成功,表结构修改失败"); + value = false; + } - //如果文件夹创建成功 - if (flag) { - tsFiles.setUpdateTime(currentTime); - tsFiles.setWorkPath(path); - int valueAdded = tsFilesMapper.updateById(tsFiles); - if (valueAdded == 1) { - LOGGER.info("同步minio到本地,本地文件夹创建成功,表结构修改成功。"); - value = true; } else { - LOGGER.error("同步minio到本地,本地文件夹创建成功,表结构修改失败"); + LOGGER.error("同步minio到本地,本地文件夹创建失败"); value = false; } } else { - LOGGER.error("同步minio到本地,本地文件夹创建失败"); - value = false; - } + //如果是文件 + String name = parameterListData.getName(); + String path = parameterListData.getPath(); + String size = parameterListData.getSize(); + // 处理路径格式 + path = normalizePath(path); - } else { - //如果是文件 - String name = parameterListData.getName(); - String path = parameterListData.getPath(); - String size = parameterListData.getSize(); - // 处理路径格式 - path = normalizePath(path); - - //通过名称和minio路径查询表结构的数据 - QueryWrapper queryWrapperFile = new QueryWrapper<>(); - queryWrapperFile.eq("file_name", name); - queryWrapperFile.eq("backup_path", path); - TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFile); - if (tsFiles == null) { - return false; - } - // 递归创建父文件夹 - boolean parentsCreated = createLocalParentFolders(tsFiles.getParentId()); - if (!parentsCreated) { - LOGGER.error("父文件夹创建失败"); - return false; - } - - String localPath = storageSourceConfig.getValue() + path + name;//localPath是本地的路径 - String minioPath = path + name;//// MinIO上传目标路径 - - FileOutputStream outputStream = null; // 输出流 - S3ObjectInputStream inputStream = null; // 输入流 - S3Object s3Object = null; - try { - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("minio"); - // 获取 MinIO 文件对象 - s3Object = fileService.getObject(storageSourceConfig1.getValue(), minioPath); - // 获取文件输入流 - inputStream = s3Object.getObjectContent(); - - // 创建本地文件 - File localFile = new File(localPath); - if (!localFile.getParentFile().exists()) { - localFile.getParentFile().mkdirs(); // 创建父目录 + //通过名称和minio路径查询表结构的数据 + QueryWrapper queryWrapperFile = new QueryWrapper<>(); + queryWrapperFile.eq("file_name", name); + queryWrapperFile.eq("backup_path", path); + TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFile); + if (tsFiles == null) { + return false; + } + // 递归创建父文件夹 + boolean parentsCreated = createLocalParentFolders(tsFiles.getParentId()); + if (!parentsCreated) { + LOGGER.error("父文件夹创建失败"); + return false; } - // 将文件内容写入本地文件 - outputStream = new FileOutputStream(localFile); - IOUtils.copy(inputStream, outputStream); - //文件下载成功以后 修改表结构 - tsFiles.setUpdateTime(currentTime); - tsFiles.setWorkPath(path); - int valueAdded = tsFilesMapper.updateById(tsFiles); - if (valueAdded == 1) { - LOGGER.info("同步minio到本地,本地文件创建成功,表结构修改成功。"); - LOGGER.info("文件下载成功:" + localPath); - value = true; - } else { - LOGGER.error("同步minio到本地,本地文件创建成功,表结构修改失败"); - value = false; - } - } catch (Exception e) { - LOGGER.error("文件下载失败:" + e.getMessage()); - } finally { - // 关闭流 - if (inputStream != null) { - try { - inputStream.close(); - } catch (IOException e) { - LOGGER.error("关闭输入流失败:" + e.getMessage()); + String localPath = storageSourceConfig.getValue() + path + name;//localPath是本地的路径 + String minioPath = path + name;//// MinIO上传目标路径 + + FileOutputStream outputStream = null; // 输出流 + S3ObjectInputStream inputStream = null; // 输入流 + S3Object s3Object = null; + try { + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("minio"); + // 获取 MinIO 文件对象 + s3Object = fileService.getObject(storageSourceConfig1.getValue(), minioPath); + // 获取文件输入流 + inputStream = s3Object.getObjectContent(); + + // 创建本地文件 + File localFile = new File(localPath); + if (!localFile.getParentFile().exists()) { + localFile.getParentFile().mkdirs(); // 创建父目录 } - } - if (outputStream != null) { - try { - outputStream.close(); - } catch (IOException e) { - LOGGER.error("关闭输出流失败:" + e.getMessage()); + + // 将文件内容写入本地文件 + outputStream = new FileOutputStream(localFile); + IOUtils.copy(inputStream, outputStream); + //文件下载成功以后 修改表结构 + tsFiles.setUpdateTime(currentTime); + tsFiles.setWorkPath(path); + int valueAdded = tsFilesMapper.updateById(tsFiles); + if (valueAdded == 1) { + LOGGER.info("同步minio到本地,本地文件创建成功,表结构修改成功。"); + LOGGER.info("文件下载成功:" + localPath); + value = true; + } else { + LOGGER.error("同步minio到本地,本地文件创建成功,表结构修改失败"); + value = false; } - } - if (s3Object != null) { - try { - s3Object.close(); - } catch (IOException e) { - LOGGER.error("关闭 S3Object 失败:" + e.getMessage()); + } catch (Exception e) { + LOGGER.error("文件下载失败:" + e.getMessage()); + } finally { + // 关闭流 + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + LOGGER.error("关闭输入流失败:" + e.getMessage()); + } + } + if (outputStream != null) { + try { + outputStream.close(); + } catch (IOException e) { + LOGGER.error("关闭输出流失败:" + e.getMessage()); + } + } + if (s3Object != null) { + try { + s3Object.close(); + } catch (IOException e) { + LOGGER.error("关闭 S3Object 失败:" + e.getMessage()); + } } } } } + return value; + } catch (Exception e) { + LOGGER.error("从备份空间下载到工作空间时发生异常: {}", e.getMessage(), e); + return false; + } finally { + TableNameContextHolder.clear(); } - return value; } @@ -3738,6 +3962,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl // 创建本地文件夹 private boolean createLocalFolder(TsFiles folder) { try { + TsTask tsTask = tsTaskMapper.selectById(folder.getTaskId()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); // 设置当前时间 LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp @@ -3750,7 +3976,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl newFolderRequest.setName(folder.getFileName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(folder.getBackupPath());//请求路径,示例值(/) - newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { @@ -3783,61 +4009,76 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class) public String moveFileFolder(MoveCopyFileFolderRequest reques) throws IOException { - // 1. 获取存储根路径 - StorageSourceConfig config = getStorageConfig("filePath", "local"); + try { - Path rootPath = Paths.get(config.getValue()); + TsTask tsTask = tsTaskMapper.selectById(reques.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 1. 获取存储根路径 + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + Path rootPath = Paths.get(config.getValue()); + String newPath = reques.getNewPath(); + String oldpaths = reques.getOldpaths(); + String parentId = reques.getParentId(); + String rename = reques.getRename(); + String type = reques.getType(); + String[] newFileNames = reques.getNewFileName().split(","); + // 数组转集合 + List newFileNameList = Arrays.asList(newFileNames); + // 2. 构建目标父目录的物理路径(如 E:\yun\22) + Path targetParentPhysicalPath = buildPhysicalPath(newPath, rootPath); - String newPath = reques.getNewPath(); - String oldpaths = reques.getOldpaths(); - String parentId = reques.getParentId(); - String rename = reques.getRename(); - String type = reques.getType(); - String[] newFileNames = reques.getNewFileName().split(","); - // 数组转集合 - List newFileNameList = Arrays.asList(newFileNames); - // 2. 构建目标父目录的物理路径(如 E:\yun\22) - Path targetParentPhysicalPath = buildPhysicalPath(newPath, rootPath); - - // 3. 循环处理所有选中的文件/文件夹 - for (String fileName : newFileNameList) { - // 构建原文件物理路径(如 E:\yun\11\file.txt) - Path sourcePath = buildPhysicalPath(oldpaths + "/" + fileName, rootPath); - if (!Files.exists(sourcePath)) { - throw new IOException("源文件不存在: " + sourcePath); - } - - // ==== 新增关键校验 ==== - // 1. 禁止移动到自身 - if (sourcePath.equals(targetParentPhysicalPath)) { - throw new IllegalArgumentException("不能移动到自己所在目录"); - } - - // 2. 禁止文件夹移动到子目录 - if (Files.isDirectory(sourcePath)) { - if (targetParentPhysicalPath.startsWith(sourcePath)) { - throw new IllegalArgumentException("禁止将文件夹移动到自己内部"); + // 3. 循环处理所有选中的文件/文件夹 + for (String fileName : newFileNameList) { + // 构建原文件物理路径(如 E:\yun\11\file.txt) + Path sourcePath = buildPhysicalPath(oldpaths + "/" + fileName, rootPath); + if (!Files.exists(sourcePath)) { + throw new IOException("源文件不存在: " + sourcePath); } - } - // 生成目标文件名(处理重命名和冲突) - String targetFileName = generateTargetFileName(targetParentPhysicalPath, fileName, rename, type); - Path targetPath = targetParentPhysicalPath.resolve(targetFileName); - - // 3. 再次检查自移动 如果是覆盖不需要校验这个 - if ("1".equals(type)) { - if (sourcePath.equals(targetPath)) { - throw new IllegalArgumentException("不能移动到自己当前位置"); + // ==== 新增关键校验 ==== + // 1. 禁止移动到自身 + if (sourcePath.equals(targetParentPhysicalPath)) { + throw new IllegalArgumentException("不能移动到自己所在目录"); } - } - // 执行移动操作 - moveFile(sourcePath, targetPath, type); - // 更新数据库记录 - updateDatabase(parentId, oldpaths, fileName, newPath, targetFileName, type); + // 2. 禁止文件夹移动到子目录 + if (Files.isDirectory(sourcePath)) { + if (targetParentPhysicalPath.startsWith(sourcePath)) { + throw new IllegalArgumentException("禁止将文件夹移动到自己内部"); + } + } + + // 生成目标文件名(处理重命名和冲突) + String targetFileName = generateTargetFileName(targetParentPhysicalPath, fileName, rename, type); + Path targetPath = targetParentPhysicalPath.resolve(targetFileName); + + // 3. 再次检查自移动 如果是覆盖不需要校验这个 + if ("1".equals(type)) { + if (sourcePath.equals(targetPath)) { + throw new IllegalArgumentException("不能移动到自己当前位置"); + } + } + // 执行移动操作 + moveFile(sourcePath, targetPath, type); + + // 更新数据库记录 + updateDatabase(parentId, oldpaths, fileName, newPath, targetFileName, type); + } + return "移动成功"; + } catch (NoSuchFileException e) { + LOGGER.error("文件或目录不存在: {}", e.getMessage()); + return "文件或目录不存在,请检查路径"; + } catch (IOException e) { + LOGGER.error("文件移动失败: {}", e.getMessage()); + return "文件移动失败,请检查权限或路径"; + } catch (Exception e) { + LOGGER.error("发生未知错误: {}", e.getMessage(), e); + return "系统错误,请联系管理员"; + } finally { + TableNameContextHolder.clear(); + } - return "移动成功"; } @@ -3919,6 +4160,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl */ private void updateDatabase(String parentId, String oldpaths, String fileName, String newPath, String targetFileName, String type) { + TsFiles tsFilesData = tsFilesMapper.selectById(parentId); LOGGER.info("移动的时候删除Redis"); //todo 移动的时候成功以后 删除redis @@ -4075,62 +4317,73 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class) public String copyFileFolder(MoveCopyFileFolderRequest reques) throws IOException { - // 1. 获取存储根路径 - StorageSourceConfig config = getStorageConfig("filePath", "local"); + try { - Path rootPath = Paths.get(config.getValue()); + TsTask tsTask = tsTaskMapper.selectById(reques.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 1. 获取存储根路径 + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + Path rootPath = Paths.get(config.getValue()); - String newPath = reques.getNewPath(); - String oldpaths = reques.getOldpaths(); - String parentId = reques.getParentId(); - String rename = reques.getRename(); - String type = reques.getType(); - String[] newFileNames = reques.getNewFileName().split(","); - // 数组转集合 - List newFileNameList = Arrays.asList(newFileNames); + String newPath = reques.getNewPath(); + String oldpaths = reques.getOldpaths(); + String parentId = reques.getParentId(); + String rename = reques.getRename(); + String type = reques.getType(); + String[] newFileNames = reques.getNewFileName().split(","); + // 数组转集合 + List newFileNameList = Arrays.asList(newFileNames); - // 2. 构建目标父目录的物理路径 - Path targetParentPhysicalPath = buildPhysicalPath(newPath, rootPath); + // 2. 构建目标父目录的物理路径 + Path targetParentPhysicalPath = buildPhysicalPath(newPath, rootPath); - // 3. 循环处理所有选中的文件/文件夹 - for (String fileName : newFileNameList) { - // 构建原文件物理路径 - Path sourcePath = buildPhysicalPath(oldpaths + "/" + fileName, rootPath); - - - if (!Files.exists(sourcePath)) { - throw new IOException("源文件不存在: " + sourcePath); - } - - // ==== 新增关键校验 ==== - // 1. 禁止移动到自身 - if (sourcePath.equals(targetParentPhysicalPath)) { - throw new IllegalArgumentException("不能复制到自己所在目录"); - } - - // 2. 禁止文件夹移动到子目录 - if (Files.isDirectory(sourcePath)) { - if (targetParentPhysicalPath.startsWith(sourcePath)) { - throw new IllegalArgumentException("禁止将文件夹复制到自己内部"); + // 3. 循环处理所有选中的文件/文件夹 + for (String fileName : newFileNameList) { + // 构建原文件物理路径 + Path sourcePath = buildPhysicalPath(oldpaths + "/" + fileName, rootPath); + if (!Files.exists(sourcePath)) { + throw new IOException("源文件不存在: " + sourcePath); + } + // ==== 新增关键校验 ==== + // 1. 禁止移动到自身 + if (sourcePath.equals(targetParentPhysicalPath)) { + throw new IllegalArgumentException("不能复制到自己所在目录"); + } + // 2. 禁止文件夹移动到子目录 + if (Files.isDirectory(sourcePath)) { + if (targetParentPhysicalPath.startsWith(sourcePath)) { + throw new IllegalArgumentException("禁止将文件夹复制到自己内部"); + } } - } - // 生成目标文件名(处理重命名和冲突) - String targetFileName = generateTargetFileName(targetParentPhysicalPath, fileName, rename, type); - Path targetPath = targetParentPhysicalPath.resolve(targetFileName); + // 生成目标文件名(处理重命名和冲突) + String targetFileName = generateTargetFileName(targetParentPhysicalPath, fileName, rename, type); + Path targetPath = targetParentPhysicalPath.resolve(targetFileName); - // 3. 再次检查自移动 + // 3. 再次检查自移动 // if (sourcePath.equals(targetPath)) { // throw new IllegalArgumentException("不能复制到自己当前位置"); // } - // 执行物理复制 - copyPhysicalFile(sourcePath, targetPath, type); + // 执行物理复制 + copyPhysicalFile(sourcePath, targetPath, type); - // 5. 插入新记录到数据库 - insertDatabaseRecord(parentId, oldpaths, fileName, newPath, targetFileName, type); + // 5. 插入新记录到数据库 + insertDatabaseRecord(parentId, oldpaths, fileName, newPath, targetFileName, type); + } + return "复制成功"; + } catch (IllegalArgumentException e) { + LOGGER.error("复制操作参数错误: {}", e.getMessage(), e); + return "复制失败:" + e.getMessage(); + } catch (IOException e) { + LOGGER.error("复制操作IO异常: {}", e.getMessage(), e); + return "复制失败:IO异常,请检查路径或权限"; + } catch (Exception e) { + LOGGER.error("复制操作未知异常: {}", e.getMessage(), e); + return "复制失败:系统错误,请联系管理员"; + } finally { + TableNameContextHolder.clear(); } - return "复制成功"; } @@ -4386,49 +4639,58 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public DualTreeResponse listLocalTree(String taskId, String nodeId) { - // 记录方法入参 - LOGGER.info("Starting to build dual trees for taskId={}, nodeId={}", taskId, nodeId); - // 1. 批量查询所有相关节点 - QueryWrapper queryWrapper = new QueryWrapper<>(); - if (nodeId != null && !nodeId.isEmpty()) { - queryWrapper.eq("node_id", nodeId); - } - if (taskId != null && !taskId.isEmpty()) { - queryWrapper.eq("task_id", taskId); - } - queryWrapper.isNotNull("work_path").ne("work_path", ""); + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 记录方法入参 + LOGGER.info("Starting to build dual trees for taskId={}, nodeId={}", taskId, nodeId); + // 1. 批量查询所有相关节点 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (nodeId != null && !nodeId.isEmpty()) { + queryWrapper.eq("node_id", nodeId); + } + if (taskId != null && !taskId.isEmpty()) { + queryWrapper.eq("task_id", taskId); + } + queryWrapper.isNotNull("work_path").ne("work_path", ""); - List allNodes = tsFilesMapper.selectList(queryWrapper); + List allNodes = tsFilesMapper.selectList(queryWrapper); - // 2. 双树构建容器 - List localTrees = new ArrayList<>(); - if (allNodes.isEmpty()) { - return new DualTreeResponse(localTrees, null); - } - // 3. 构建内存索引提升查询效率 - Map> parentChildrenMap = allNodes.stream() - .collect(Collectors.groupingBy(TsFiles::getParentId)); - LOGGER.debug("使用{}个条目构建父子映射", parentChildrenMap.size()); + // 2. 双树构建容器 + List localTrees = new ArrayList<>(); + if (allNodes.isEmpty()) { + return new DualTreeResponse(localTrees, null); + } + // 3. 构建内存索引提升查询效率 + Map> parentChildrenMap = allNodes.stream() + .collect(Collectors.groupingBy(TsFiles::getParentId)); + LOGGER.debug("使用{}个条目构建父子映射", parentChildrenMap.size()); - // 4. 从顶级节点(parentId为00)开始构建树 - List rootNodes = parentChildrenMap.get("00"); - if (rootNodes == null || rootNodes.isEmpty()) { - LOGGER.warn("找不到的根节点 taskId={}, nodeId={}", taskId, nodeId); - return new DualTreeResponse(localTrees, null); - } + // 4. 从顶级节点(parentId为00)开始构建树 + List rootNodes = parentChildrenMap.get("00"); + if (rootNodes == null || rootNodes.isEmpty()) { + LOGGER.warn("找不到的根节点 taskId={}, nodeId={}", taskId, nodeId); + return new DualTreeResponse(localTrees, null); + } - if (rootNodes != null) { - for (TsFiles rootNode : rootNodes) { - // 构建本地树 - TreeDTO localTree = buildTree(rootNode, parentChildrenMap, true); - if (localTree != null) { - localTrees.add(localTree); - LOGGER.debug("添加了本地树节点: {}", localTree.getId()); + if (rootNodes != null) { + for (TsFiles rootNode : rootNodes) { + // 构建本地树 + TreeDTO localTree = buildTree(rootNode, parentChildrenMap, true); + if (localTree != null) { + localTrees.add(localTree); + LOGGER.debug("添加了本地树节点: {}", localTree.getId()); + } } } + LOGGER.info("Tree construction completed. Local nodes: {}", localTrees.size()); + return new DualTreeResponse(localTrees, null); + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - LOGGER.info("Tree construction completed. Local nodes: {}", localTrees.size()); - return new DualTreeResponse(localTrees, null); } @@ -4441,50 +4703,59 @@ public class TsFilesServiceImpl extends ServiceImpl impl ***********************************/ @Override public DualTreeResponse listBackupTree(String taskId, String nodeId) { - // 记录方法入参 - LOGGER.info("Starting to build dual trees for taskId={}, nodeId={}", taskId, nodeId); - // 1. 批量查询所有相关节点 - QueryWrapper queryWrapper = new QueryWrapper<>(); - if (nodeId != null && !nodeId.isEmpty()) { - queryWrapper.eq("node_id", nodeId); - } - if (taskId != null && !taskId.isEmpty()) { - queryWrapper.eq("task_id", taskId); - } + try { + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 记录方法入参 + LOGGER.info("Starting to build dual trees for taskId={}, nodeId={}", taskId, nodeId); + // 1. 批量查询所有相关节点 + QueryWrapper queryWrapper = new QueryWrapper<>(); + if (nodeId != null && !nodeId.isEmpty()) { + queryWrapper.eq("node_id", nodeId); + } + if (taskId != null && !taskId.isEmpty()) { + queryWrapper.eq("task_id", taskId); + } - queryWrapper.isNotNull("backup_path").ne("backup_path", ""); + queryWrapper.isNotNull("backup_path").ne("backup_path", ""); // queryWrapper.eq("parent_id", "00"); - List allNodes = tsFilesMapper.selectList(queryWrapper); - // 2. 双树构建容器 - List minioTrees = new ArrayList<>(); - // 3. 构建内存索引提升查询效率 - Map> parentChildrenMap = allNodes.stream() - .collect(Collectors.groupingBy(TsFiles::getParentId)); - LOGGER.debug("使用{}个条目构建父子映射", parentChildrenMap.size()); - if (allNodes.isEmpty()) { - return new DualTreeResponse(null, minioTrees); - } + List allNodes = tsFilesMapper.selectList(queryWrapper); + // 2. 双树构建容器 + List minioTrees = new ArrayList<>(); + // 3. 构建内存索引提升查询效率 + Map> parentChildrenMap = allNodes.stream() + .collect(Collectors.groupingBy(TsFiles::getParentId)); + LOGGER.debug("使用{}个条目构建父子映射", parentChildrenMap.size()); + if (allNodes.isEmpty()) { + return new DualTreeResponse(null, minioTrees); + } - // 4. 从顶级节点(parentId为00)开始构建树 - List rootNodes = parentChildrenMap.get("00"); - if (rootNodes == null || rootNodes.isEmpty()) { - LOGGER.warn("找不到的根节点 taskId={}, nodeId={}", taskId, nodeId); - return new DualTreeResponse(null, minioTrees); - } + // 4. 从顶级节点(parentId为00)开始构建树 + List rootNodes = parentChildrenMap.get("00"); + if (rootNodes == null || rootNodes.isEmpty()) { + LOGGER.warn("找不到的根节点 taskId={}, nodeId={}", taskId, nodeId); + return new DualTreeResponse(null, minioTrees); + } - if (rootNodes != null) { - for (TsFiles rootNode : rootNodes) { - // 构建本地树 - // 构建Minio树 - TreeDTO minioTree = buildTree(rootNode, parentChildrenMap, false); - if (minioTree != null) { - minioTrees.add(minioTree); - LOGGER.debug("添加了MINIO树节点: {}", minioTree.getId()); + if (rootNodes != null) { + for (TsFiles rootNode : rootNodes) { + // 构建本地树 + // 构建Minio树 + TreeDTO minioTree = buildTree(rootNode, parentChildrenMap, false); + if (minioTree != null) { + minioTrees.add(minioTree); + LOGGER.debug("添加了MINIO树节点: {}", minioTree.getId()); + } } } + LOGGER.info("Tree construction completed. MinIO nodes: {}", minioTrees.size()); + return new DualTreeResponse(null, minioTrees); + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - LOGGER.info("Tree construction completed. MinIO nodes: {}", minioTrees.size()); - return new DualTreeResponse(null, minioTrees); } /********************************** @@ -4493,23 +4764,35 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult 返回文件信息 ***********************************/ @Override - public FileItemResult obtainUrl(String id, String type) { + public FileItemResult obtainUrl(String id, String type, String taskId) { FileItemResult fileItemResult = new FileItemResult(); - TsFiles tsFiles = tsFilesMapper.selectById(id); - String fileNameData = tsFiles.getFileName(); - String path = ""; - if ("local".equals(type)) { - String workPath = tsFiles.getWorkPath(); - path = workPath + fileNameData; - } else { - String backupPath = tsFiles.getBackupPath(); - path = backupPath + fileNameData; - } + try { - //准备获取文件的信息 - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(type); - fileItemResult = fileService.getFileItem(path); - return fileItemResult; + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + TsFiles tsFiles = tsFilesMapper.selectById(id); + String fileNameData = tsFiles.getFileName(); + String path = ""; + if ("local".equals(type)) { + String workPath = tsFiles.getWorkPath(); + path = workPath + fileNameData; + } else { + String backupPath = tsFiles.getBackupPath(); + path = backupPath + fileNameData; + } + + //准备获取文件的信息 + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(type); + fileItemResult = fileService.getFileItem(path); + return fileItemResult; + } catch (Exception e) { + LOGGER.error("获取文件URL时发生异常,ID: {}, 类型: {}", id, type, e); + // 可选:返回空对象或自定义错误信息 + // throw new BusinessException("获取文件URL失败"); + return null; + } finally { + TableNameContextHolder.clear(); + } } @@ -4591,29 +4874,7 @@ public class TsFilesServiceImpl extends ServiceImpl impl return dto; } -// public String processingPath(String Path, String nodeId) { -// String newWorkPath = ""; -// if (Path == null || nodeId == null) { -// return newWorkPath; -// } -// // 获取原始路径和 nodeId -// String workPath1 = Path; -// // 拼接需要去掉的部分 -// String toRemove = File.separator + nodeId; -// // 将路径分隔符统一为 "/" -// String standardizedWorkPath = workPath1.replace("\\", "/"); -// String standardizedToRemove = toRemove.replace("\\", "/"); -// // 检查 standardizedWorkPath 是否包含 standardizedToRemove -// if (standardizedWorkPath.contains(standardizedToRemove)) { -// // 去掉目标部分 -// newWorkPath = standardizedWorkPath.replace(standardizedToRemove, ""); -// // 确保路径最后保留一个 '/' -// if (!newWorkPath.endsWith("/")) { -// newWorkPath += "/"; -// } -// } -// return newWorkPath; -// } + /*******************************************读取文件内容经纬度**************************************************************/ @@ -4625,83 +4886,93 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult ***********************************/ @Override - public void batchSendNaviOutDataJob(String id, int samTimes, String token) { - if (currentTaskFuture != null && !currentTaskFuture.isDone()) { - currentTaskFuture.cancel(true); // 中断之前的任务 - } - currentTaskFuture = executorService.submit(() -> { + public void batchSendNaviOutDataJob(String id, int samTimes, String token, String taskId) { + try { + + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); TsFiles tsFiles = tsFilesMapper.selectById(id); - StorageSourceConfig config = getStorageConfig("filePath", "local"); + if (currentTaskFuture != null && !currentTaskFuture.isDone()) { + currentTaskFuture.cancel(true); // 中断之前的任务 + } + currentTaskFuture = executorService.submit(() -> { + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); - Path filePath = Paths.get(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName()); + Path filePath = Paths.get(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName()); - try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toFile()))) { - reader.readLine(); // 跳过标题行 + try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toFile()))) { + reader.readLine(); // 跳过标题行 - // 不管 samTimes 如何,先读取第一行数据 - String firstLine = reader.readLine(); - if (firstLine != null) { - firstLine = firstLine.trim(); - String[] values = firstLine.split("\t"); - if (values.length >= 40) { - // 发送第一行数据 - sendData(token, values, 1); - } else { - System.err.println("忽略不完整行: " + firstLine); + // 不管 samTimes 如何,先读取第一行数据 + String firstLine = reader.readLine(); + if (firstLine != null) { + firstLine = firstLine.trim(); + String[] values = firstLine.split("\t"); + if (values.length >= 40) { + // 发送第一行数据 + sendData(token, values, 1); + } else { + System.err.println("忽略不完整行: " + firstLine); + } } - } + //todo 这个地方该从一下 换成200 + int step = samTimes * 200; // 计算行号间隔 + int lineCount = 1; // 从第一行开始 - int step = samTimes * 200; // 计算行号间隔 - int lineCount = 1; // 从第一行开始 + while (!Thread.currentThread().isInterrupted()) { + lineCount += step; // 直接跳到下一个需要读取的行 + String line = null; - while (!Thread.currentThread().isInterrupted()) { - lineCount += step; // 直接跳到下一个需要读取的行 - String line = null; + // 读取指定行 + for (int i = 0; i < step; i++) { + line = reader.readLine(); + if (line == null) { + break; // 文件结束 + } + } - // 读取指定行 - for (int i = 0; i < step; i++) { - line = reader.readLine(); if (line == null) { break; // 文件结束 } + + line = line.trim(); + String[] values = line.split("\t"); + if (values.length < 40) { + LOGGER.info("忽略不完整行: " + line); + continue; + } + + // 发送数据 + sendData(token, values, lineCount); + + // 固定休眠 3 秒 + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + // 如果休眠期间被中断,则退出循环 + Thread.currentThread().interrupt(); + break; + } } - if (line == null) { - break; // 文件结束 + // 发送完成信号(如果需要) + if (!Thread.currentThread().isInterrupted()) { + // ServerSendEventServer.sendMessage(token, "COMPLETED"); } - line = line.trim(); - String[] values = line.split("\t"); - if (values.length < 40) { - LOGGER.info("忽略不完整行: " + line); - continue; - } - - // 发送数据 - sendData(token, values, lineCount); - - // 固定休眠 3 秒 - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - // 如果休眠期间被中断,则退出循环 - Thread.currentThread().interrupt(); - break; - } + } catch (Exception e) { + // 捕获异常并记录日志 + LOGGER.error("任务执行失败: " + e.getMessage()); + e.printStackTrace(); } - - // 发送完成信号(如果需要) - if (!Thread.currentThread().isInterrupted()) { - // ServerSendEventServer.sendMessage(token, "COMPLETED"); - } - - } catch (Exception e) { - // 捕获异常并记录日志 - LOGGER.error("任务执行失败: " + e.getMessage()); - e.printStackTrace(); - } - }); + }); + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); + } } @@ -4748,33 +5019,41 @@ public class TsFilesServiceImpl extends ServiceImpl impl * @return 文件内容的纯文本(UTF-8 编码) */ @Override - public String readFileContent(String id) throws IOException { + public String readFileContent(String id, String taskId) throws IOException { + try { - StorageSourceConfig config = getStorageConfig("filePath", "local"); - - TsFiles tsFiles = tsFilesMapper.selectById(id); - // 1. 路径标准化与安全校验 - Path targetPath = validateAndNormalizePath(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName()); + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + TsFiles tsFiles = tsFilesMapper.selectById(id); + // 1. 路径标准化与安全校验 + Path targetPath = validateAndNormalizePath(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName(), tsTask); - StringBuilder content = new StringBuilder(); + StringBuilder content = new StringBuilder(); - // 使用缓冲流读取大文件(减少内存占用) - try (BufferedReader reader = Files.newBufferedReader(targetPath, StandardCharsets.UTF_8)) { - String line; - while ((line = reader.readLine()) != null) { - content.append(line).append("\n"); + // 使用缓冲流读取大文件(减少内存占用) + try (BufferedReader reader = Files.newBufferedReader(targetPath, StandardCharsets.UTF_8)) { + String line; + while ((line = reader.readLine()) != null) { + content.append(line).append("\n"); + } } + return content.toString().trim(); + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } - return content.toString().trim(); // 移除末尾多余换行 } /** * 验证路径是否合法并转换为标准化路径 */ - private Path validateAndNormalizePath(String filePath) throws SecurityException { - StorageSourceConfig config = getStorageConfig("filePath", "local"); + private Path validateAndNormalizePath(String filePath, TsTask tsTask) throws SecurityException { + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); Path targetPath = Paths.get(filePath).normalize(); Path baseDirPath = Paths.get(config.getValue()); @@ -4800,21 +5079,31 @@ public class TsFilesServiceImpl extends ServiceImpl impl * @throws IOException 文件写入失败时抛出 */ @Override - public void saveFileContent(String id, String content) throws SecurityException, IOException { + public void saveFileContent(String id, String content, String taskId) throws SecurityException, IOException { + try { - StorageSourceConfig config = getStorageConfig("filePath", "local"); - TsFiles tsFiles = tsFilesMapper.selectById(id); - // 1. 路径标准化与安全校验 - Path targetPath = validateAndNormalizePath(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName()); - // 2. 确保父目录存在 - Path parentDir = targetPath.getParent(); - if (parentDir != null && !Files.exists(parentDir)) { - Files.createDirectories(parentDir); - } - // 3. 写入文件内容(UTF-8 编码) - // 使用缓冲流写入大文件(支持流式上传) - try (BufferedWriter writer = Files.newBufferedWriter(targetPath, StandardCharsets.UTF_8)) { - writer.write(content); + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + TsFiles tsFiles = tsFilesMapper.selectById(id); + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + + // 1. 路径标准化与安全校验 + Path targetPath = validateAndNormalizePath(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName(),tsTask); + // 2. 确保父目录存在 + Path parentDir = targetPath.getParent(); + if (parentDir != null && !Files.exists(parentDir)) { + Files.createDirectories(parentDir); + } + // 3. 写入文件内容(UTF-8 编码) + // 使用缓冲流写入大文件(支持流式上传) + try (BufferedWriter writer = Files.newBufferedWriter(targetPath, StandardCharsets.UTF_8)) { + writer.write(content); + } + } catch (Exception e) { + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } } @@ -4824,58 +5113,67 @@ public class TsFilesServiceImpl extends ServiceImpl impl * 返回值说明: com.yfd.platform.config.ResponseResult操作结果 ***********************************/ @Override - public void batchUpdateFile(String id, List modifications) throws IOException { - StorageSourceConfig config = getStorageConfig("filePath", "local"); - TsFiles tsFile = tsFilesMapper.selectById(id); - if (tsFile == null) { - throw new IllegalArgumentException("文件ID不存在: " + id); - } - Path filePath = Paths.get(config.getValue(), tsFile.getWorkPath(), tsFile.getFileName()).normalize(); - // 安全校验 - if (!filePath.startsWith(config.getValue())) { - throw new SecurityException("路径越界: " + filePath); - } - - // 1.2 检查文件是否为文本类型 - validateTextFile(filePath); - - LOGGER.info("批量修改文件: {}, 修改指令数: {}", filePath, modifications.size()); - - - // 3. 创建临时文件(在指定目录下) - Path tempDir = Paths.get(config.getValue(), tsFile.getWorkPath()).normalize(); - if (!Files.exists(tempDir)) { - Files.createDirectories(tempDir); // 确保目录存在 - } - - // 临时文件名格式:原文件名_时间戳.tmp - String tempFileName = tsFile.getFileName() + "_" + System.currentTimeMillis() + ".tmp"; - Path tempPath = tempDir.resolve(tempFileName); - + public void batchUpdateFile(String id, List modifications, String taskId) throws IOException { try { - // 读取文件内容(兼容Java 8) - List lines = new ArrayList<>(); - try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { - String line; - while ((line = reader.readLine()) != null) { - lines.add(line); - } + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + TsFiles tsFile = tsFilesMapper.selectById(id); + StorageSourceConfig config = getStorageSourceConfig("filePath", "local",tsTask.getLocalStorageId()); + if (tsFile == null) { + throw new IllegalArgumentException("文件ID不存在: " + id); + } + Path filePath = Paths.get(config.getValue(), tsFile.getWorkPath(), tsFile.getFileName()).normalize(); + // 安全校验 + if (!filePath.startsWith(config.getValue())) { + throw new SecurityException("路径越界: " + filePath); } - applyModifications(lines, modifications); + // 1.2 检查文件是否为文本类型 + validateTextFile(filePath); - // 写入临时文件(兼容Java 8) - try (BufferedWriter writer = Files.newBufferedWriter(tempPath, StandardCharsets.UTF_8)) { - for (String line : lines) { - writer.write(line); - writer.newLine(); // 保留原换行符风格 - } + LOGGER.info("批量修改文件: {}, 修改指令数: {}", filePath, modifications.size()); + + + // 3. 创建临时文件(在指定目录下) + Path tempDir = Paths.get(config.getValue(), tsFile.getWorkPath()).normalize(); + if (!Files.exists(tempDir)) { + Files.createDirectories(tempDir); // 确保目录存在 } - Files.move(tempPath, filePath, StandardCopyOption.REPLACE_EXISTING); + // 临时文件名格式:原文件名_时间戳.tmp + String tempFileName = tsFile.getFileName() + "_" + System.currentTimeMillis() + ".tmp"; + Path tempPath = tempDir.resolve(tempFileName); + + try { + // 读取文件内容(兼容Java 8) + List lines = new ArrayList<>(); + try (BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + + applyModifications(lines, modifications); + + // 写入临时文件(兼容Java 8) + try (BufferedWriter writer = Files.newBufferedWriter(tempPath, StandardCharsets.UTF_8)) { + for (String line : lines) { + writer.write(line); + writer.newLine(); // 保留原换行符风格 + } + } + + Files.move(tempPath, filePath, StandardCopyOption.REPLACE_EXISTING); + } catch (Exception e) { + Files.deleteIfExists(tempPath); + throw e; + } } catch (Exception e) { - Files.deleteIfExists(tempPath); - throw e; + LOGGER.error("未知异常:{}", e.getMessage(), e); + throw new RuntimeException("系统错误,请联系管理员"); + } finally { + TableNameContextHolder.clear(); } } @@ -5041,7 +5339,18 @@ public class TsFilesServiceImpl extends ServiceImpl impl } ServerSendEventServer.removeUser(token); } + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig( Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } + // 辅助方法:获取存储配置 + private StorageSourceConfig getStorageSourceConfig(String name, String type,Integer id) { + return storageSourceConfigMapper.selectOne( + new LambdaQueryWrapper().eq(StorageSourceConfig::getName, name).eq(StorageSourceConfig::getType, type).eq(StorageSourceConfig::getStorageId,id) + ); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java index 77acd9e..edf398c 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsNodesServiceImpl.java @@ -22,21 +22,27 @@ import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper; import com.yfd.platform.modules.experimentalData.service.ITsFilesService; import com.yfd.platform.modules.experimentalData.service.ITsNodesService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper; +import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; +import com.yfd.platform.modules.storage.model.entity.StorageSource; 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; +import com.yfd.platform.modules.storage.model.request.RenameFolderRequest; import com.yfd.platform.modules.storage.model.result.FileItemResult; import com.yfd.platform.modules.storage.service.StorageSourceService; import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.utils.StringUtils; +import com.yfd.platform.utils.TableNameContextHolder; import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; @@ -93,6 +99,11 @@ public class TsNodesServiceImpl extends ServiceImpl impl @Resource private StorageSourceConfigMapper storageSourceConfigMapper; + @Resource + private StorageSourceMapper storageSourceMapper; + + @Autowired + private RedisTemplate redisTemplate; //顶级父节点 Top level parent node public static final String TOP_LEVEL_PARENT_NODE = "00"; @@ -289,76 +300,93 @@ public class TsNodesServiceImpl extends ServiceImpl impl @Override @Transactional(rollbackFor = Exception.class) // 添加事务注解,遇到异常时回滚 public ResponseResult addTsNodes(TsNodes tsnodes) { - - //查询文件表 如果有一样的名称不能新增 - List tsFiles = tsFilesMapper.selectList(new QueryWrapper() - .eq("task_id", tsnodes.getTaskId()) - .eq("parent_id", "00") - .eq("file_name", tsnodes.getNodeName()) - .eq("is_file", "FOLDER")); - if (tsFiles.size() > 0) { - return ResponseResult.error("数据管理中存在该文件夹!"); - } - // 校验文件名是否包含非法字符 - String nodeName = tsnodes.getNodeName(); - if (containsInvalidCharacters(nodeName)) { - return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); - } - // 差不多的流程 就是提出来 然后判断 如果两个 中有一个是true - //获取当前登录用户 - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - //创建人是当前登录人 - tsnodes.setCreator(loginuser.getUsername()); - - //当前操作时间 - LocalDateTime now = LocalDateTime.now(); - // 转换为 Timestamp - Timestamp currentTime = Timestamp.valueOf(now); - tsnodes.setCreateTime(currentTime); - - //通过获取上级节点的条数 设置节点顺序 - QueryWrapper queryWrapperNodeOrder = new QueryWrapper<>(); - int orderno = this.count(queryWrapperNodeOrder.eq("parent_id", tsnodes.getParentId())) + 1; - //判断节点名称是否存在 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("node_name", tsnodes.getNodeName());//名称 - queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID - queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID - int count = tsNodesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("节点名称已存在!"); - } - //序号 - tsnodes.setNodeOrder(orderno); + // 初始化变量 + ResponseResult result = ResponseResult.error(); - int valueAdded = tsNodesMapper.insert(tsnodes); - if (valueAdded == 1) { - LOGGER.info("tsnodes表结构增加成功"); + try { + TsTask tsTask = tsTaskMapper.selectById(tsnodes.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + //查询文件表 如果有一样的名称不能新增 + List tsFiles = tsFilesMapper.selectList(new QueryWrapper() + .eq("task_id", tsnodes.getTaskId()) + .eq("parent_id", "00") + .eq("file_name", tsnodes.getNodeName()) + .eq("is_file", "FOLDER")); + if (tsFiles.size() > 0) { + return ResponseResult.error("数据管理中存在该文件夹!"); + } + // 校验文件名是否包含非法字符 + String nodeName = tsnodes.getNodeName(); + if (containsInvalidCharacters(nodeName)) { + return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); + } + // 差不多的流程 就是提出来 然后判断 如果两个 中有一个是true + //获取当前登录用户 + UsernamePasswordAuthenticationToken authentication = + (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + //创建人是当前登录人 + tsnodes.setCreator(loginuser.getUsername()); + + //当前操作时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); + tsnodes.setCreateTime(currentTime); + + //通过获取上级节点的条数 设置节点顺序 + QueryWrapper queryWrapperNodeOrder = new QueryWrapper<>(); + int orderno = this.count(queryWrapperNodeOrder.eq("parent_id", tsnodes.getParentId())) + 1; + //判断节点名称是否存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("node_name", tsnodes.getNodeName());//名称 + queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID + queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID + int count = tsNodesMapper.selectCount(queryWrapper); + // 大于0说明 区域名称重复 + if (count > 0) { + return ResponseResult.error("节点名称已存在!"); + } + //序号 + tsnodes.setNodeOrder(orderno); - //新增节点的时候 创建文件夹 - NewFolderRequest newFolderRequest = new NewFolderRequest(); - newFolderRequest.setName(tsnodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c) - newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) - newFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/) - newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio sdlocal) - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); - boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); - if (flag) { - return ResponseResult.success(); + int valueAdded = tsNodesMapper.insert(tsnodes); + if (valueAdded == 1) { + LOGGER.info("tsnodes表结构增加成功"); + + + //新增节点的时候 创建文件夹 + NewFolderRequest newFolderRequest = new NewFolderRequest(); + newFolderRequest.setName(tsnodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c) + newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + newFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); + boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); + if (flag) { + result = ResponseResult.success(); + } else { + LOGGER.error("节点新增成功,但是local创建文件失败"); + result = ResponseResult.error("物理文件夹创建失败"); + } + return result; } else { - LOGGER.error("节点新增成功,但是local创建文件失败"); + LOGGER.error("tsnodes表结构增加失败"); return ResponseResult.error(); } - } else { - LOGGER.error("tsnodes表结构增加失败"); - return ResponseResult.error(); + } catch (Exception e) { + // 异常处理 + LOGGER.error("添加节点时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误: " + e.getMessage()); + } finally { + TableNameContextHolder.clear(); + return result; } + } @@ -380,45 +408,99 @@ public class TsNodesServiceImpl extends ServiceImpl impl @Override public ResponseResult updateTsNodes(TsNodes tsnodes) { - // 校验文件名是否包含非法字符 - String nodeName = tsnodes.getNodeName(); - if (containsInvalidCharacters(nodeName)) { - return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); - } - //查询没改之前的节点名称 - TsNodes nodesold = tsNodesMapper.selectById(tsnodes.getNodeId()); + try { + TsTask tsTask = tsTaskMapper.selectById(tsnodes.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); - //老的节点名称 - String nodeNameOld = null; - if (ObjUtil.isNotEmpty(nodesold)) { - nodeNameOld = nodesold.getNodeName(); - } + // 校验文件名是否包含非法字符 + String nodeName = tsnodes.getNodeName(); + if (containsInvalidCharacters(nodeName)) { + return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); + } - //获取当前登录用户 - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - //创建人是当前登录人 - tsnodes.setCreator(loginuser.getUsername()); + // 查询旧节点名称 + TsNodes nodesold = tsNodesMapper.selectById(tsnodes.getNodeId()); + String nodeNameOld = ObjUtil.isNotEmpty(nodesold) ? nodesold.getNodeName() : null; - //判断节点名称是否存在 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("node_name", tsnodes.getNodeName());//名称 - queryWrapper.eq("task_id", tsnodes.getTaskId());//所属任务ID - queryWrapper.eq("parent_id", tsnodes.getParentId());//所属任务ID - int count = tsNodesMapper.selectCount(queryWrapper); - // 大于0说明 区域名称重复 - if (count > 0) { - return ResponseResult.error("节点名称已存在!"); - } - int valueAdded = tsNodesMapper.updateById(tsnodes); - if (valueAdded == 1) { - LOGGER.info("tsnodes表结构修改成功"); - return ResponseResult.success(); - } else { - LOGGER.error("tsnodes表结构修改失败"); - return ResponseResult.error(); + // 获取当前登录用户 + UsernamePasswordAuthenticationToken authentication = + (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); + LoginUser loginuser = (LoginUser) authentication.getPrincipal(); + + // 设置创建人 + tsnodes.setCreator(loginuser.getUsername()); + + // 判断节点名称是否存在 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("node_name", tsnodes.getNodeName()) + .eq("task_id", tsnodes.getTaskId()) + .eq("parent_id", tsnodes.getParentId()); + int count = tsNodesMapper.selectCount(queryWrapper); + + if (count > 0) { + return ResponseResult.error("节点名称已存在!"); + } + + // 更新节点信息 + int valueAdded = tsNodesMapper.updateById(tsnodes); + + // 2. 构建新旧路径 + String oldBasePath = tsnodes.getPath() + nodeNameOld + "/"; + String newBasePath = tsnodes.getPath() + nodeName + "/"; + + + //4.更新文件表ts_files表 根据所属项目ID 老路径 和新路径 + tsFilesMapper.updateTsFileByPath(tsnodes.getTaskId(), oldBasePath, newBasePath); + + //获取项目下面的所有子节点 都清除缓存 + List nodesList = tsNodesMapper.selectList(new QueryWrapper().eq("task_id", tsnodes.getTaskId())); + if ((nodesList != null) && (nodesList.size() > 0)) { + for (TsNodes node : nodesList) { + //todo 修改节点成功以后 删除redis + for (int page = 1; page <= 5; page++) { + String redisKey = "tsfiles_" + node.getTaskId() + "_" + node.getNodeId() + "_parentId" + node.getParentId() + "_page_" + page; + redisTemplate.delete(redisKey); + } + } + } + + //判断如果更新了节点名称 + if (!nodeName.equals(nodeNameOld)) { + if (valueAdded == 1) { + //修改文件名称 + RenameFolderRequest renameFolderRequest = new RenameFolderRequest(); + renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie) + renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music) + renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + renameFolderRequest.setPath(tsnodes.getPath());//请求路径,示例值(/) + renameFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey()); + boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName()); + if (flag) { + return ResponseResult.success("重命名成功"); + } else { + LOGGER.error("节点修改成功,但是本地修改文件名失败"); + return ResponseResult.error("重命名失败"); + } + } else { + LOGGER.error("节点修改失败"); + return ResponseResult.error(); + } + + } else { + if (valueAdded == 1) { + return ResponseResult.success("重命名成功"); + } else { + return ResponseResult.error("重命名失败"); + } + } + } catch (Exception e) { + LOGGER.error("更新试验任务节点时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误,请稍后重试"); + } finally { + TableNameContextHolder.clear(); } } @@ -430,80 +512,92 @@ public class TsNodesServiceImpl extends ServiceImpl impl ***********************************/ @Override public boolean deleteTsNodesById(String id, String path) { - //根据ID 查询当前数据 - TsNodes tsNodes = tsNodesMapper.selectById(id); - //删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构 - //查询所有的子节点 - List tsNodesList = selectChildrentsNodes(tsNodes.getNodeId(), tsNodes.getTaskId()); - // 提取所有节点的 ID - List nodeIds = tsNodesList.stream() - .map(TsNodes::getNodeId) // 获取每个节点的 ID - .collect(Collectors.toList()); - //修改项目ID 和所有节点id的workPath字段为空 - if (CollectionUtils.isNotEmpty(nodeIds)) { - // 4. 批量更新:将这些节点的文件工作路径置空 - LambdaUpdateWrapper updateWrapper1 = new LambdaUpdateWrapper<>(); - updateWrapper1.in(TsFiles::getNodeId, nodeIds).eq(TsFiles::getTaskId, tsNodes.getTaskId()).set(TsFiles::getWorkPath, ""); - tsFilesMapper.update(null, updateWrapper1); + try { + //根据ID 查询当前数据 + TsNodes tsNodes = tsNodesMapper.selectById(id); + TsTask tsTask = tsTaskMapper.selectById(tsNodes.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + //删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构 + //查询所有的子节点 + List tsNodesList = selectChildrentsNodes(tsNodes.getNodeId(), tsNodes.getTaskId()); + // 提取所有节点的 ID + List nodeIds = tsNodesList.stream() + .map(TsNodes::getNodeId) // 获取每个节点的 ID + .collect(Collectors.toList()); + //修改项目ID 和所有节点id的workPath字段为空 + if (CollectionUtils.isNotEmpty(nodeIds)) { + // 4. 批量更新:将这些节点的文件工作路径置空 + LambdaUpdateWrapper updateWrapper1 = new LambdaUpdateWrapper<>(); + updateWrapper1.in(TsFiles::getNodeId, nodeIds).eq(TsFiles::getTaskId, tsNodes.getTaskId()).set(TsFiles::getWorkPath, ""); + tsFilesMapper.update(null, updateWrapper1); - // 5. 删除符合条件的文件记录 - LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); - deleteWrapper.in(TsFiles::getNodeId, nodeIds) - .eq(TsFiles::getTaskId, tsNodes.getTaskId()) - .and(wrapper -> wrapper.isNull(TsFiles::getBackupPath).or().eq(TsFiles::getBackupPath, "")) - .and(wrapper -> wrapper.isNull(TsFiles::getWorkPath).or().eq(TsFiles::getWorkPath, "")); - tsFilesMapper.delete(deleteWrapper); - } + // 5. 删除符合条件的文件记录 + LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); + deleteWrapper.in(TsFiles::getNodeId, nodeIds) + .eq(TsFiles::getTaskId, tsNodes.getTaskId()) + .and(wrapper -> wrapper.isNull(TsFiles::getBackupPath).or().eq(TsFiles::getBackupPath, "")) + .and(wrapper -> wrapper.isNull(TsFiles::getWorkPath).or().eq(TsFiles::getWorkPath, "")); + tsFilesMapper.delete(deleteWrapper); + } - //删除当前节点的文件夹 todo 这个地方改动 - // 删除 sdlocal 中的文件夹 - List deleteItemList = new ArrayList<>(); - BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); - deleteItemData.setName(tsNodes.getNodeName()); - deleteItemData.setPassword(""); - deleteItemData.setPath(path); - deleteItemData.setType(FileTypeEnum.FOLDER); - deleteItemList.add(deleteItemData); + //删除当前节点的文件夹 todo 这个地方改动 + // 删除 sdlocal 中的文件夹 + List deleteItemList = new ArrayList<>(); + BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); + deleteItemData.setName(tsNodes.getNodeName()); + deleteItemData.setPassword(""); + deleteItemData.setPath(path); + deleteItemData.setType(FileTypeEnum.FOLDER); + deleteItemList.add(deleteItemData); - BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); - batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("local"); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); + BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); + batchDeleteRequest.setDeleteItems(deleteItemList); + batchDeleteRequest.setStorageKey(storageSource.getKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); - int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); - for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) { - boolean flag = false; - try { - if (deleteItem.getType() == FileTypeEnum.FILE) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); - } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { - flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); - } + int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); + for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) { + boolean flag = false; + try { + if (deleteItem.getType() == FileTypeEnum.FILE) { + flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } - if (flag) { - deleteSuccessCount++; - } else { + if (flag) { + deleteSuccessCount++; + } else { + deleteFailCount++; + } + } catch (Exception e) { + LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } - } catch (Exception e) { - LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); - deleteFailCount++; } - } - if (deleteSuccessCount >= 1) { - // 删除当前节点 - int deleteCount = tsNodesMapper.deleteBatchIds(nodeIds); - if (deleteCount >= 1) { - LOGGER.info("tsnodes表结删除改成功"); - return true; + if (deleteSuccessCount >= 1) { + // 删除当前节点 + int deleteCount = tsNodesMapper.deleteBatchIds(nodeIds); + if (deleteCount >= 1) { + LOGGER.info("tsnodes表结删除改成功"); + return true; + } else { + LOGGER.error("tsnodes表结构删除失败"); + return false; + } } else { - LOGGER.error("tsnodes表结构删除失败"); return false; } - } else { + } catch (Exception e) { + LOGGER.error("删除试验任务节点时发生异常: {}", e.getMessage(), e); return false; + } finally { + TableNameContextHolder.clear(); } + + } private List selectChildrentsNodes(String parentId, String taskId) { @@ -559,7 +653,7 @@ public class TsNodesServiceImpl extends ServiceImpl impl } //批量删除TsFiles表数据 if (dataset.size() > 0) { - tsFilesService.deleteTsFilesByIds(dataset, "local"); + tsFilesService.deleteTsFilesByIds(dataset, "local", taskId); } } } @@ -580,6 +674,9 @@ public class TsNodesServiceImpl extends ServiceImpl impl if (tsNodesList.size() == 0) { return true; } + TsTask tsTask = tsTaskMapper.selectById(taskId); + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + for (TsNodes tsNodes : tsNodesList) { //删除文件表 @@ -595,7 +692,7 @@ public class TsNodesServiceImpl extends ServiceImpl impl BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("local"); + batchDeleteRequest.setStorageKey(storageSource.getKey()); AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); @@ -643,10 +740,10 @@ public class TsNodesServiceImpl extends ServiceImpl impl ***********************************/ @Override @Async("asyncExecutor") - public void testDataScanByIdAsync(String id,LoginUser loginuser) throws Exception { + public void testDataScanByIdAsync(String id, LoginUser loginuser) throws Exception { try { // 执行扫描并且插入数据库 - this.testDataScanById(id,loginuser); + this.testDataScanById(id, loginuser); } finally { // 生成唯一Key String asyncKey = taskStatusHolder.testDatascanKey(id); @@ -663,48 +760,64 @@ public class TsNodesServiceImpl extends ServiceImpl impl ***********************************/ @Override public Object confirmDeleteNodes(String id) { - JSONObject jsonObject = new JSONObject(); - TsNodes tsNodes = tsNodesMapper.selectById(id); - if (tsNodes == null) { - jsonObject.putOpt("status", "1"); + try { + JSONObject jsonObject = new JSONObject(); + TsNodes tsNodes = tsNodesMapper.selectById(id); + TsTask tsTask = tsTaskMapper.selectById(tsNodes.getTaskId()); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + if (tsNodes == null) { + jsonObject.putOpt("status", "1"); + return ResponseResult.successData(jsonObject); + } + //SQL通过节点ID 递归查询节点下面的所有子节点 以及files表中 backup_path IS NOT NULL + int count = tsFilesService.countFiles(id); + //如果大于0不让删 + if (count > 0) { + jsonObject.putOpt("status", "0"); + } else { + jsonObject.putOpt("status", "1"); + } return ResponseResult.successData(jsonObject); + } catch (Exception e) { + LOGGER.error("检查节点是否允许删除时发生异常: {}", e.getMessage(), e); + return ResponseResult.error("系统错误,请稍后重试"); + } finally { + TableNameContextHolder.clear(); } - //SQL通过节点ID 递归查询节点下面的所有子节点 以及files表中 backup_path IS NOT NULL - int count = tsFilesService.countFiles(id); - //如果大于0不让删 - if (count > 0) { - jsonObject.putOpt("status", "0"); - } else { - jsonObject.putOpt("status", "1"); - } - return ResponseResult.successData(jsonObject); } - private String testDataScanById(String id,LoginUser loginuser) throws Exception { + private String testDataScanById(String id, LoginUser loginuser) throws Exception { + try { + //查询试验任务信息 + TsTask tsTask = tsTaskMapper.selectById(id); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + //文件的第一层是节点 下面的层级是文件夹 + //获取文件列表 + String absolutePath = "/" + tsTask.getTaskName() + "/"; + FileListRequest fileListRequest = buildFileRequest(absolutePath, tsTask); + 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 fileItemList = fileService.fileList(fileListRequest.getPath()); - //查询试验任务信息 - TsTask tsTask = tsTaskMapper.selectById(id); - //文件的第一层是节点 下面的层级是文件夹 - //获取文件列表 - String absolutePath = "/" + tsTask.getTaskName() + "/"; - FileListRequest fileListRequest = buildFileRequest(absolutePath); - String storageKey = fileListRequest.getStorageKey(); - Integer storageId = storageSourceService.findIdByKey(storageKey); - if (storageId == null) { - throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); + if (fileItemList.size() == 0) { + throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。"); + } + firstLayerData(fileItemList, id, loginuser); + + return "扫描完成"; + } catch (Exception e) { + LOGGER.error("执行试验数据扫描时发生未知异常: {}", e.getMessage(), e); + return "扫描失败:" + e.getMessage(); + } finally { + TableNameContextHolder.clear(); } - // 处理请求参数默认值 - fileListRequest.handleDefaultValue(); - AbstractBaseFileService fileService = storageSourceContext.getByStorageId(storageId); - //todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件,递归增加 - List fileItemList = fileService.fileList(fileListRequest.getPath()); - - if (fileItemList.size() == 0) { - throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。"); - } - firstLayerData(fileItemList, id, loginuser); - - return "扫描完成"; } /** @@ -714,8 +827,11 @@ public class TsNodesServiceImpl extends ServiceImpl impl * @param taskId 所属任务ID * @throws Exception */ - public void firstLayerData(List fileItemList, String taskId,LoginUser loginuser) throws Exception { - + public void firstLayerData(List fileItemList, String taskId, LoginUser loginuser) throws Exception { + // 设置当前时间 + LocalDateTime now = LocalDateTime.now(); + // 转换为 Timestamp + Timestamp currentTime = Timestamp.valueOf(now); for (FileItemResult item : fileItemList) { //思路就是 如果是文件夹 就查询一下 没有就新增, 新的的时候递归往下走 if (item.getType() == FileTypeEnum.FOLDER) { @@ -730,9 +846,83 @@ public class TsNodesServiceImpl extends ServiceImpl impl TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, item.getName()); otherLevelsData(taskId, node.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser); } else { - otherLevelsData(taskId, nodeData.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser); + //otherLevelsData(taskId, nodeData.getNodeId(), item.getName(), item.getPath(), TOP_LEVEL_PARENT_NODE, loginuser); + continue; } + } else { + //todo 如果是文件 首先判断表中有没有 如果没有 就新增 到节点名称为根节点的 节点下面 + + //查询节点表中 有没有根节点的节点 如果有就直接使用 如果没有就新增 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsNodes::getTaskId, taskId); + queryWrapper.eq(TsNodes::getParentId, TOP_LEVEL_PARENT_NODE); + queryWrapper.eq(TsNodes::getNodeName, "根节点"); + TsNodes nodeData = tsNodesMapper.selectOne(queryWrapper); + if (nodeData == null) { + //新增一个根节点 + TsNodes node = savetsNodes(taskId, TOP_LEVEL_PARENT_NODE, "根节点"); + + String finalPath = item.getPath().replace(item.getName(), ""); + //保存文件信息 + TsFiles tsFiles1 = new TsFiles(); + //任务 + tsFiles1.setTaskId(taskId); + //节点 + tsFiles1.setNodeId(node.getNodeId()); + //文件 文件夹 区分 + tsFiles1.setIsFile("FILE"); + //上级ID + tsFiles1.setParentId("00"); + //文件名称 + tsFiles1.setFileName(item.getName()); + //工作空间路径 + tsFiles1.setWorkPath(ensurePathFormat(finalPath)); + tsFiles1.setUploadTime(currentTime); + tsFiles1.setUploader(loginuser.getUsername()); + long bytes = item.getSize(); + // 转换为 KB 并保留两位小数 + double fileSizeInKB = bytes / (1024.0); + String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 + tsFiles1.setFileSize(fileSizeFormatted); + tsFilesMapper.insert(tsFiles1); + } else { + //先通过名称 + 节点 + 任务 + 路径 查询 如果有就跳过 没有就继续新增 + LambdaQueryWrapper queryWrapperFiles = new LambdaQueryWrapper<>(); + queryWrapperFiles.eq(TsFiles::getNodeId, nodeData.getNodeId()); + queryWrapperFiles.eq(TsFiles::getTaskId, taskId); + queryWrapperFiles.eq(TsFiles::getWorkPath, item.getPath()); + queryWrapperFiles.eq(TsFiles::getFileName, item.getName()); + TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapperFiles); + if (tsFiles == null) { + String finalPath = item.getPath().replace(item.getName(), ""); + //保存文件信息 + TsFiles tsFiles1 = new TsFiles(); + //任务 + tsFiles1.setTaskId(taskId); + //节点 + tsFiles1.setNodeId(nodeData.getNodeId()); + //文件 文件夹 区分 + tsFiles1.setIsFile("FILE"); + //上级ID + tsFiles1.setParentId("00"); + //文件名称 + tsFiles1.setFileName(item.getName()); + //工作空间路径 + tsFiles1.setWorkPath(ensurePathFormat(finalPath)); + tsFiles1.setUploadTime(currentTime); + tsFiles1.setUploader(loginuser.getUsername()); + long bytes = item.getSize(); + // 转换为 KB 并保留两位小数 + double fileSizeInKB = bytes / (1024.0); + String fileSizeFormatted = String.format("%.2f", fileSizeInKB); // 保留两位小数 + tsFiles1.setFileSize(fileSizeFormatted); + tsFilesMapper.insert(tsFiles1); + } else { + continue; + } + + } } } } @@ -745,7 +935,7 @@ public class TsNodesServiceImpl extends ServiceImpl impl * @param parentId 父级ID * @return */ - private void otherLevelsData(String taskId, String nodeId, String nodeName, String path, String parentId,LoginUser loginuser) throws Exception { + private void otherLevelsData(String taskId, String nodeId, String nodeName, String path, String parentId, LoginUser loginuser) throws Exception { // 存储所有目录和文件的列表 List tsFilesToCreate = new ArrayList<>(); @@ -757,6 +947,7 @@ public class TsNodesServiceImpl extends ServiceImpl impl // 查询本地文件路径根目录(如 E:\yun) QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "filePath"); + queryWrapper.eq("storage_id", "1"); queryWrapper.eq("type", "local"); StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); //获取文件列表 这个地方path+name @@ -984,15 +1175,21 @@ public class TsNodesServiceImpl extends ServiceImpl impl return node; } - private FileListRequest buildFileRequest(String path) { + private FileListRequest buildFileRequest(String path, TsTask tsTask) { + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); FileListRequest fileListRequest = new FileListRequest(); fileListRequest.setOrderBy("time"); fileListRequest.setOrderDirection("desc"); fileListRequest.setPassword(""); fileListRequest.setPath(path); - fileListRequest.setStorageKey("local"); + fileListRequest.setStorageKey(storageSource.getKey()); return fileListRequest; } + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig(Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java index 604a162..180c89a 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/service/impl/TsTaskServiceImpl.java @@ -18,13 +18,16 @@ import com.yfd.platform.modules.experimentalData.service.ITsFilesService; import com.yfd.platform.modules.experimentalData.service.ITsNodesService; import com.yfd.platform.modules.experimentalData.service.ITsTaskService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.modules.specialDocument.domain.Project; import com.yfd.platform.modules.storage.context.StorageSourceContext; +import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; +import com.yfd.platform.modules.storage.model.entity.StorageSource; +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; import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; import com.yfd.platform.utils.StringUtils; +import com.yfd.platform.utils.TableNameContextHolder; import io.netty.channel.ChannelInboundHandlerAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -32,12 +35,17 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import javax.annotation.Resource; -import java.sql.Timestamp; -import java.time.LocalDateTime; +import java.sql.*; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.util.Collections; import java.util.List; + +import javax.annotation.Resource; +import javax.sql.DataSource; +import java.time.LocalDateTime; + /** *

* 试验任务表 服务实现类 @@ -72,6 +80,11 @@ public class TsTaskServiceImpl extends ServiceImpl impleme @Resource private StorageSourceContext storageSourceContext; + @Resource + private StorageSourceMapper storageSourceMapper; + + @Autowired + private DataSource dataSource; private static final String INITIAL_CODE = "00001"; private static final int MAX_CODE_VALUE = 99999; @@ -169,15 +182,15 @@ public class TsTaskServiceImpl extends ServiceImpl impleme //生成任务名称 任务开始时间_结束时间_地点_载机名称_设备代号_编号 String taskName = buildTaskName(tsTask); tsTask.setTaskName(taskName); - - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsTask::getTaskName,tsTask.getTaskName()); + queryWrapper.eq(TsTask::getTaskName, tsTask.getTaskName()); TsTask tsTask1 = tsTaskMapper.selectOne(queryWrapper); - if (tsTask1 != null){ + if (tsTask1 != null) { throw new RuntimeException("试验任务管理项目已存在!"); } + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + // 设置当前时间 LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp @@ -193,10 +206,12 @@ public class TsTaskServiceImpl extends ServiceImpl impleme newFolderRequest.setName(tsTask.getTaskName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(path);//请求路径,示例值(/) - newFolderRequest.setStorageKey("local");//存储源 key,示例值(local minio) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { + // 动态创建数据表 + createTaskFileTable(taskCode); return true; } else { LOGGER.error("试验任务增加成功,但是本地试验任务文件夹创建失败"); @@ -208,12 +223,74 @@ public class TsTaskServiceImpl extends ServiceImpl impleme } + // 动态创建任务文件表 + private void createTaskFileTable(String taskCode) { + + // 添加表名校验(重要!防止SQL注入) + if (!taskCode.matches("^\\d{5}$")) { // 假设任务编号是5位数字 + throw new IllegalArgumentException("非法任务编号格式: " + taskCode); + } + + String tableName = "ts_files_" + taskCode; + String sql = String.format( + "CREATE TABLE IF NOT EXISTS `%s` LIKE `ts_files`", + tableName + ); + try (Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement()) { + // 1. 记录要执行的SQL + LOGGER.info("执行DDL: {}", sql); + // 2. 执行SQL + boolean result = stmt.execute(sql); + // 3. 验证结果 + LOGGER.debug("执行结果: {}", result); + // 4. 二次验证 + if (!tableExists(tableName)) { + throw new RuntimeException("表创建后验证失败: " + tableName); + } + + } catch (SQLException e) { + // 提取MySQL错误信息 + String errorMsg = extractMysqlError(e); + LOGGER.error("创建表失败: {} - {}", tableName, errorMsg); + throw new RuntimeException("创建表失败: " + errorMsg, e); + } + } + + private boolean tableExists(String tableName) { + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData meta = conn.getMetaData(); + // 获取当前数据库信息 + String catalog = conn.getCatalog(); + String schema = conn.getSchema(); + // 查询表是否存在 + try (ResultSet rs = meta.getTables(catalog, schema, tableName, new String[]{"TABLE"})) { + return rs.next(); + } + } catch (SQLException e) { + LOGGER.error("检查表存在失败: {}", tableName, e); + return false; + } + } + + private String extractMysqlError(SQLException e) { + // 提取MySQL特有的错误信息 + while (e != null) { + if (e.getMessage().contains("MySQL")) { + return String.format("MySQL 错误 [%d]: %s", e.getErrorCode(), e.getMessage()); + } + e = e.getNextException(); + } + return "未知数据库错误"; + } + public static String buildTaskName(TsTask tsTask) { List parts = new ArrayList<>(); - + // 定义日期格式化模板 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); // 按顺序添加非空字段 - addIfNotEmpty(parts, String.valueOf(tsTask.getTaskStartdate())); - addIfNotEmpty(parts, String.valueOf(tsTask.getTaskEnddate())); + addIfNotEmpty(parts, formatDate(tsTask.getTaskStartdate(), formatter)); + addIfNotEmpty(parts, formatDate(tsTask.getTaskEnddate(), formatter)); addIfNotEmpty(parts, tsTask.getTaskPlace()); addIfNotEmpty(parts, tsTask.getCarrierName()); addIfNotEmpty(parts, tsTask.getDeviceCode()); @@ -222,6 +299,15 @@ public class TsTaskServiceImpl extends ServiceImpl impleme return String.join("_", parts); } + // 格式化日期的方法 + private static String formatDate(Object date, DateTimeFormatter formatter) { + if (date != null) { + return ((java.time.LocalDate) date).format(formatter); + } + return null; + } + + private static void addIfNotEmpty(List list, String value) { if (StringUtils.isNotBlank(value)) { // 使用Apache Commons Lang的空判断 list.add(value.trim()); // 去除首尾空格 @@ -262,21 +348,27 @@ public class TsTaskServiceImpl extends ServiceImpl impleme public boolean deleteTstaskByIds(List dataset) { Boolean value = false; - //循环所有的ID - for (String taskId : dataset) { - //删除项目 + try { - // 删除节点表 - LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); - deleteWrapper.eq(TsNodes::getTaskId, taskId); - tsNodesMapper.delete(deleteWrapper); - // 删除文件表 - LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); - deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); - tsFilesMapper.delete(deleteWrapperFiles); + //循环所有的ID + for (String taskId : dataset) { + //删除项目 + TsTask tsTask = tsTaskMapper.selectById(taskId); + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + // 删除节点表 + LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); + deleteWrapper.eq(TsNodes::getTaskId, taskId); + tsNodesMapper.delete(deleteWrapper); + + // 删除文件表 + LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); + deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); + tsFilesMapper.delete(deleteWrapperFiles); + //todo 删除文件表数据 +// tsFilesMapper.deleteSdFilesBytaskId(taskId); + - TsTask tsTask = tsTaskMapper.selectById(taskId); // String path = "/" + tsTask.getTaskName() + "/"; // //调用删除节点 根据任务ID // Boolean deleteTsnodes = tsNodesService.deleteTsNodesByTaskId(taskId, path); @@ -289,59 +381,65 @@ public class TsTaskServiceImpl extends ServiceImpl impleme // value = false; // } + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + // 删除 local 中的文件夹 项目文件夹 + List deleteItemList = new ArrayList<>(); + BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); + deleteItemData.setName(tsTask.getTaskName()); + deleteItemData.setPassword(""); + deleteItemData.setPath("/"); + deleteItemData.setType(FileTypeEnum.FOLDER); + deleteItemList.add(deleteItemData); - // 删除 local 中的文件夹 项目文件夹 - List deleteItemList = new ArrayList<>(); - BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); - deleteItemData.setName(tsTask.getTaskName()); - deleteItemData.setPassword(""); - deleteItemData.setPath("/"); - deleteItemData.setType(FileTypeEnum.FOLDER); - deleteItemList.add(deleteItemData); + BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); + batchDeleteRequest.setDeleteItems(deleteItemList); + batchDeleteRequest.setStorageKey(storageSource.getKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); + int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); - BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); - batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("local"); - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); - int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); + for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) { + boolean flag = false; + try { + if (deleteItem.getType() == FileTypeEnum.FILE) { + flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); + } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } - for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) { - boolean flag = false; - try { - if (deleteItem.getType() == FileTypeEnum.FILE) { - flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); - } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { - flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); - } - - if (flag) { - deleteSuccessCount++; - } else { + if (flag) { + deleteSuccessCount++; + } else { + deleteFailCount++; + } + } catch (Exception e) { + LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); deleteFailCount++; } - } catch (Exception e) { - LOGGER.error("删除文件/文件夹失败, 文件路径: {}, 文件名称: {}", deleteItem.getPath(), deleteItem.getName(), e); - deleteFailCount++; } - } - if (deleteSuccessCount >= 1) { - // 删除当前项目 - int deleteCount = tsTaskMapper.deleteById(taskId); - if (deleteCount == 1) { - LOGGER.info("tstask表结删除改成功"); - value = true; + if (deleteSuccessCount >= 1) { + // 删除当前项目 + int deleteCount = tsTaskMapper.deleteById(taskId); + if (deleteCount == 1) { + LOGGER.info("tstask表结删除改成功"); + value = true; + } else { + LOGGER.error("tstask表结构删除失败"); + value = false; + } } else { - LOGGER.error("tstask表结构删除失败"); value = false; } - } else { - value = false; + + } + return value; + } catch (Exception e) { + } finally { + TableNameContextHolder.clear(); } - return value; } @@ -352,20 +450,53 @@ public class TsTaskServiceImpl extends ServiceImpl impleme ***********************************/ @Override public Object confirmDeleteTask(List dataset) { - JSONObject jsonObject = new JSONObject(); - // 删除 getBackupPath 和 getWorkPath 都为空的记录 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(TsFiles::getTaskId, dataset) - .and(wrapper -> wrapper.isNotNull(TsFiles::getBackupPath) - .or().ne(TsFiles::getBackupPath, "")); - int count = tsFilesService.count(queryWrapper); - //如果大于0不让删 - if (count > 0) { - jsonObject.putOpt("status", "0"); - } else { - jsonObject.putOpt("status", "1"); + try { + LambdaQueryWrapper queryWrapperTsk = new LambdaQueryWrapper<>(); + queryWrapperTsk.in(TsTask::getId, dataset); + List tsTasks = tsTaskMapper.selectList(queryWrapperTsk); + + JSONObject result = new JSONObject(); + boolean allDeletable = true; + + for (TsTask tsTask : tsTasks) { + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + + // 查询是否有备份路径或非空路径的文件 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getTaskId, tsTask.getId()) + .and(wrapper -> wrapper.isNotNull(TsFiles::getBackupPath) + .or().ne(TsFiles::getBackupPath, "")); + + int count = tsFilesService.count(queryWrapper); + + if (count > 0) { + allDeletable = false; + break; // 一旦发现不可删除项,提前终止循环 + } + } + + result.putOpt("status", allDeletable ? "1" : "0"); + return ResponseResult.successData(result); + + } catch (Exception e) { + // 使用日志框架代替 printStackTrace + LOGGER.error("确认删除实验任务时发生异常", e); + return ResponseResult.error("查询失败"); + } finally { + TableNameContextHolder.clear(); } - return ResponseResult.successData(jsonObject); + } + + @Override + public List listTsTask() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.orderByDesc(TsTask::getTaskStartdate); + List tsTasks = tsTaskMapper.selectList(queryWrapper); + for (TsTask tsTask : tsTasks){ + StorageSource storageSource = getStorageConfig(tsTask.getLocalStorageId()); + tsTask.setKey(storageSource.getKey()); + } + return tsTasks; } @Transactional(rollbackFor = Exception.class) @@ -398,4 +529,10 @@ public class TsTaskServiceImpl extends ServiceImpl impleme } } + + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig( Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java index dec0dba..905da3c 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/ProjectController.java @@ -161,9 +161,7 @@ public class ProjectController { @ResponseBody //@PreAuthorize("@el.check('select:devicesignal')") public ResponseResult listSdproject() { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.orderByDesc(Project::getProjectTime); - List projects = projectService.list(queryWrapper); + List projects = projectService.listProject(); return ResponseResult.successData(projects); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/domain/Project.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/domain/Project.java index 6764dce..3f9f8b7 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/domain/Project.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/domain/Project.java @@ -6,6 +6,7 @@ import java.sql.Timestamp; import java.time.LocalDate; import java.time.LocalDateTime; import java.io.Serializable; +import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; import lombok.Data; @@ -91,4 +92,22 @@ public class Project implements Serializable { private String custom3; + + /** + * 本地存储空间id + */ + private Integer localStorageId; + + /** + * 上传用到KEY:TODO 增加用于前端展示 + */ + @TableField(exist = false) + private String key; + + /** + * 上传用到type:TODO 增加用于前端展示 + */ + @TableField(exist = false) + private String type; + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/FilesMapper.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/FilesMapper.java index 101e893..76ef683 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/FilesMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/FilesMapper.java @@ -1,9 +1,11 @@ package com.yfd.platform.modules.specialDocument.mapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.specialDocument.domain.Files; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Param; +import java.util.Date; import java.util.List; /** @@ -22,4 +24,33 @@ public interface FilesMapper extends BaseMapper { //根据节点删除文件(递归子节点文件) int deleteByNodeId(@Param("nodeId")String nodeId); + + void updateFileByPath(@Param("projectId") String projectId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath); + + //分页查询文件表 + Page selectFilesPage(@Param("page") Page page, + @Param("fileName") String fileName, + @Param("keywords") String keywords, + @Param("startDate") Date startDate, + @Param("endDate") Date endDate, + @Param("projectId") String projectId, + @Param("nodeId") String nodeId, + @Param("fileName1") String fileName1, + @Param("tableName") String tableName + ); + + //插入文件表 + int insertSdFilesTable(@Param("tableName") String tableName, @Param("files") Files filess); + + //更新文件表 + int updateSdFiles(@Param("tableName") String tableName, @Param("files") Files files); + + //批量查询文件表 + List selectSdFilesBatchIds(@Param("dataset") List dataset,@Param("tableName") String tableName); + + //删除文件表 + int deleteSdFiles(@Param("tableName") String tableName, @Param("files") Files files); + + //查询文件表根据ID + Files selectSdFilesById(@Param("tableName") String tableName, @Param("id") String id); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/NodesMapper.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/NodesMapper.java index 704dee1..8262cd8 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/NodesMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/NodesMapper.java @@ -2,6 +2,7 @@ package com.yfd.platform.modules.specialDocument.mapper; import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -20,4 +21,6 @@ public interface NodesMapper extends BaseMapper { int updateParentIdByPathHierarchy(); int deleteNodesRecursively(String nodeId); + + void updateNodesByPath(@Param("projectId") String projectId,@Param("oldBasePath") String oldBasePath,@Param("newBasePath") String newBasePath); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java index 3769978..b2609e4 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/mapper/ProjectMapper.java @@ -2,6 +2,7 @@ package com.yfd.platform.modules.specialDocument.mapper; import com.yfd.platform.modules.specialDocument.domain.Project; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; /** *

@@ -13,4 +14,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface ProjectMapper extends BaseMapper { + // 新增动态建表方法 + static int createFileTable(@Param("tableName") String tableName) { + return 0; + } } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java index f8bc4b0..9cd3512 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IProjectService.java @@ -46,4 +46,6 @@ public interface IProjectService extends IService { boolean deleteProjectByIds(List dataset); String generateNextProjectCode(); + + List listProject(); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java index 3f2db99..64d80b6 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/FilesServiceImpl.java @@ -11,16 +11,18 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.modules.config.model.request.FileListRequest; -import com.yfd.platform.modules.experimentalData.domain.TsFiles; import com.yfd.platform.modules.specialDocument.domain.Files; +import com.yfd.platform.modules.specialDocument.domain.Project; import com.yfd.platform.modules.specialDocument.mapper.FilesMapper; +import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper; import com.yfd.platform.modules.specialDocument.service.IFilesService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.modules.storage.chain.FileChain; -import com.yfd.platform.modules.storage.chain.FileContext; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.controller.file.FileController; import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper; +import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; +import com.yfd.platform.modules.storage.model.entity.StorageSource; 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; @@ -81,7 +83,9 @@ public class FilesServiceImpl extends ServiceImpl implements private FilesMapper filesMapper; @Autowired - private FileController fileController; + private ProjectMapper projectMapper; + @Resource + private StorageSourceMapper storageSourceMapper; @Resource private StorageSourceContext storageSourceContext; @@ -223,9 +227,11 @@ public class FilesServiceImpl extends ServiceImpl implements public FileItemResult sdLocalUrl(String id) { FileItemResult fileItemResult = new FileItemResult(); Files files = filesMapper.selectById(id); + Project project = projectMapper.selectById(files.getProjectId()); + StorageSource storageSource = storageSourceMapper.selectById(project.getLocalStorageId()); String pathAndName = files.getFilePath() + files.getFileName(); //准备获取文件的信息 - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("sdlocal"); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(storageSource.getKey()); fileItemResult = fileService.getFileItem(pathAndName); return fileItemResult; } @@ -299,13 +305,13 @@ public class FilesServiceImpl extends ServiceImpl implements if (authentication != null) { loginuser = (LoginUser) authentication.getPrincipal(); } + Project project = projectMapper.selectById(files.getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + //新增之前从处理一下源路径的数据 ,String sourcePath,String targetPath // 查询本地文件路径根目录(如 E:\yun) - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("name", "filePath"); - queryWrapper.eq("type", "sdlocal"); - StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); + StorageSourceConfig storageSourceConfig = getStorageSourceConfig("filePath","local",project.getLocalStorageId()); //源路径 临时路径 String sourceFilePath = files.getSourcePath(); //目标路径 @@ -322,7 +328,7 @@ public class FilesServiceImpl extends ServiceImpl implements //校验是否真正上传 String pathAndName = filess.getFilePath() + filess.getFileName(); //准备获取文件的信息 - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey("sdlocal"); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(storageSource.getKey()); FileItemResult fileItemResult = fileService.getFileItem(pathAndName); if (fileItemResult == null || fileItemResult.getName() == null) { return ResponseResult.error(filess.getFileName() + "文件没有上传到空间,请重新选择上传!"); @@ -380,8 +386,8 @@ public class FilesServiceImpl extends ServiceImpl implements LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp Timestamp currentTime = Timestamp.valueOf(now); - FileListRequest sourcefileListRequest = buildFileRequest(sourceFilePath); - FileListRequest targetfileListRequest = buildFileRequest(targetFilePath); + FileListRequest sourcefileListRequest = buildFileRequest(sourceFilePath,files.getProjectId()); + FileListRequest targetfileListRequest = buildFileRequest(targetFilePath,files.getProjectId()); //获取源文件列表 包含文件和文件夹 List sourceFileItemList = obtainFileItemResultData(sourcefileListRequest); @@ -583,13 +589,16 @@ public class FilesServiceImpl extends ServiceImpl implements return fileItemList; } - private FileListRequest buildFileRequest(String path) { + private FileListRequest buildFileRequest(String path,String projectId) { + Project project = projectMapper.selectById(projectId); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + FileListRequest fileListRequest = new FileListRequest(); fileListRequest.setOrderBy("time"); fileListRequest.setOrderDirection("desc"); fileListRequest.setPassword(""); fileListRequest.setPath(path); - fileListRequest.setStorageKey("sdlocal"); + fileListRequest.setStorageKey(storageSource.getKey()); return fileListRequest; } @@ -673,6 +682,8 @@ public class FilesServiceImpl extends ServiceImpl implements redisTemplate.delete(redisKey); } int SuccessCount = 0, FailCount = 0, total = CollUtil.size(dataset); + Project project = projectMapper.selectById(filesList.get(0).getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); //Todo 最直接的办法 循环出来 一条一条删除 for (Files files : filesList) { @@ -689,7 +700,7 @@ public class FilesServiceImpl extends ServiceImpl implements BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("sdlocal"); + batchDeleteRequest.setStorageKey(storageSource.getKey()); AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); List deleteItems = batchDeleteRequest.getDeleteItems(); @@ -745,12 +756,15 @@ public class FilesServiceImpl extends ServiceImpl implements // 修改 sdlocal 文件名的方法 private boolean updateMinioFileName(Files filesData, Files files) { try { + Project project = projectMapper.selectById(files.getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + RenameFileRequest renameFileRequest = new RenameFileRequest(); renameFileRequest.setName(filesData.getFileName()); renameFileRequest.setNewName(files.getFileName()); renameFileRequest.setPassword(""); renameFileRequest.setPath(filesData.getFilePath()); - renameFileRequest.setStorageKey("sdlocal"); + renameFileRequest.setStorageKey(storageSource.getKey()); AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFileRequest.getStorageKey()); return fileService.renameFile(renameFileRequest.getPath(), renameFileRequest.getName(), renameFileRequest.getNewName()); @@ -759,4 +773,17 @@ public class FilesServiceImpl extends ServiceImpl implements return false; } } + + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig(Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } + + // 辅助方法:获取存储配置 + private StorageSourceConfig getStorageSourceConfig(String name, String type,Integer id) { + return storageSourceConfigMapper.selectOne( + new LambdaQueryWrapper().eq(StorageSourceConfig::getName, name).eq(StorageSourceConfig::getType, type).eq(StorageSourceConfig::getStorageId,id) + ); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java index c6bc103..1f60759 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/NodesServiceImpl.java @@ -3,8 +3,6 @@ package com.yfd.platform.modules.specialDocument.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.io.FileUtil; -import com.amazonaws.util.IOUtils; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.component.TaskStatusHolder; @@ -23,6 +21,8 @@ import com.yfd.platform.modules.specialDocument.service.INodesService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.modules.storage.context.StorageSourceContext; import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper; +import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; +import com.yfd.platform.modules.storage.model.entity.StorageSource; 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; @@ -41,6 +41,7 @@ import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; @@ -100,10 +101,17 @@ public class NodesServiceImpl extends ServiceImpl implements @Autowired private TaskStatusHolder taskStatusHolder; + + @Resource + private StorageSourceMapper storageSourceMapper; + //专项项目表Mapper @Resource private ProjectMapper projectMapper; + @Autowired + private RedisTemplate redisTemplate; + //顶级父节点 Top level parent node public static final String TOP_LEVEL_PARENT_NODE = "00"; @@ -301,6 +309,9 @@ public class NodesServiceImpl extends ServiceImpl implements @Transactional(rollbackFor = Exception.class) // 添加事务注解,遇到异常时回滚 public ResponseResult addNodes(Nodes nodes) { + Project project = projectMapper.selectById(nodes.getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + // 校验文件名是否包含非法字符 String nodeName = nodes.getNodeName(); if (containsInvalidCharacters(nodeName)) { @@ -362,7 +373,7 @@ public class NodesServiceImpl extends ServiceImpl implements newFolderRequest.setName(nodes.getNodeName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/) - newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio sdlocal) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { @@ -392,6 +403,9 @@ public class NodesServiceImpl extends ServiceImpl implements if (containsInvalidCharacters(nodeName)) { return ResponseResult.error("文件名包含非法字符(<>:\"/\\|?*)!"); } + Project project = projectMapper.selectById(nodes.getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + //查询没改之前的节点名称 Nodes nodesold = nodesMapper.selectById(nodes.getId()); @@ -401,9 +415,6 @@ public class NodesServiceImpl extends ServiceImpl implements nodeNameOld = nodesold.getNodeName(); } - //获取专项文档项目 - Project project = projectMapper.selectById(nodes.getProjectId()); - //获取当前登录用户 UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); @@ -424,49 +435,84 @@ public class NodesServiceImpl extends ServiceImpl implements if (count > 0) { return ResponseResult.error("节点名称已存在!"); } + //更新当前数据 int valueUpdate = nodesMapper.updateById(nodes); - // 4. 递归获取所有子节点ID(包含当前节点) - List affectedNodeIds = getAllChildNodeIds(nodes.getId()); + // 2. 构建新旧路径 + String oldBasePath = nodes.getPath() + nodeNameOld + "/"; + String newBasePath = nodes.getPath() + nodeName + "/"; - // 5. 更新相关文件路径 - updateFilePaths(affectedNodeIds, nodes.getProjectId(), nodeNameOld, nodeName); + //3.跟新节点表sd_nodes表 根据所属项目ID 老路径 和新路径 + nodesMapper.updateNodesByPath(nodes.getProjectId(), oldBasePath, newBasePath); - if (valueUpdate == 1) { - List pathNodes = new ArrayList<>(); - Nodes nodesData = nodesMapper.selectById(nodes.getParentId()); - // 从当前节点向上遍历,直到根节点 - while (nodesData != null) { - pathNodes.add(nodesData.getNodeName()); - // 如果父节点是 "00",说明已经到了根节点,停止遍历 - if ("00".equals(nodesData.getParentId())) { - break; + //4.更新文件表sd_files表 根据所属项目ID 老路径 和新路径 + filesMapper.updateFileByPath(nodes.getProjectId(), oldBasePath, newBasePath); + + //获取项目下面的所有子节点 都清除缓存 + List nodesList = nodesMapper.selectList(new QueryWrapper().eq("project_id", nodes.getProjectId())); + if ((nodesList != null) && (nodesList.size() > 0)) { + for (Nodes node : nodesList) { + //todo 修改节点成功以后 删除redis + for (int page = 1; page <= 5; page++) { + String redisKey = "sdfiles_" + node.getProjectId() + "_" + node.getId() + "_page_" + page; + redisTemplate.delete(redisKey); } - // 获取父节点 - nodesData = nodesMapper.selectById(nodesData.getParentId()); // 修正:从 nodesData 中获取 parentId + LOGGER.info("已清理缓存:project={}, node={}, pages=1-5", nodes.getProjectId(), nodes.getId()); } - // 反转路径,使其从根节点到当前节点 - Collections.reverse(pathNodes); - String path = String.join("/", pathNodes); + } - //修改文件名称 - RenameFolderRequest renameFolderRequest = new RenameFolderRequest(); - renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie) - renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music) - renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) - renameFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/) - renameFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio sdlocal) - AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey()); - boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName()); - if (flag) { + + //判断如果更新了节点名称 + if (!nodeName.equals(nodeNameOld)) { +// // 4. 递归获取所有子节点ID(包含当前节点) +// List affectedNodeIds = getAllChildNodeIds(nodes.getId()); +// +// // 5. 更新相关文件路径 +// updateFilePaths(affectedNodeIds, nodes.getProjectId(), nodeNameOld, nodeName); + + if (valueUpdate == 1) { +// List pathNodes = new ArrayList<>(); +// Nodes nodesData = nodesMapper.selectById(nodes.getParentId()); +// // 从当前节点向上遍历,直到根节点 +// while (nodesData != null) { +// pathNodes.add(nodesData.getNodeName()); +// // 如果父节点是 "00",说明已经到了根节点,停止遍历 +// if ("00".equals(nodesData.getParentId())) { +// break; +// } +// // 获取父节点 +// nodesData = nodesMapper.selectById(nodesData.getParentId()); // 修正:从 nodesData 中获取 parentId +// } +// // 反转路径,使其从根节点到当前节点 +// Collections.reverse(pathNodes); +// String path = String.join("/", pathNodes); + + //修改文件名称 + RenameFolderRequest renameFolderRequest = new RenameFolderRequest(); + renameFolderRequest.setName(nodeNameOld);//重命名的原文件夹名称,示例值(movie) + renameFolderRequest.setNewName(nodeName);// 重命名后的文件名称,示例值(music) + renameFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) + renameFolderRequest.setPath(nodes.getPath());//请求路径,示例值(/) + renameFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio sdlocal) + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(renameFolderRequest.getStorageKey()); + boolean flag = fileService.renameFolder(renameFolderRequest.getPath(), renameFolderRequest.getName(), renameFolderRequest.getNewName()); + if (flag) { + return ResponseResult.success("重命名成功"); + } else { + LOGGER.error("节点修改成功,但是sdlocal修改文件名失败"); + return ResponseResult.error("重命名失败"); + } + } else { + LOGGER.error("节点修改失败"); + return ResponseResult.error(); + } + + } else { + if (valueUpdate == 1) { return ResponseResult.success("重命名成功"); } else { - LOGGER.error("节点修改成功,但是sdlocal修改文件名失败"); return ResponseResult.error("重命名失败"); } - } else { - LOGGER.error("节点修改失败"); - return ResponseResult.error(); } } @@ -545,6 +591,8 @@ public class NodesServiceImpl extends ServiceImpl implements if (nodes == null) { return false; // 节点不存在 } + Project project = projectMapper.selectById(nodes.getProjectId()); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); // //递归获取当前节点和它下面的所有节点 // List nodesList = selectChildrenNodes(id, nodes.getProjectId()); // // 提取所有节点的 ID @@ -581,7 +629,7 @@ public class NodesServiceImpl extends ServiceImpl implements BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("sdlocal"); + batchDeleteRequest.setStorageKey(storageSource.getKey()); AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); @@ -699,12 +747,13 @@ public class NodesServiceImpl extends ServiceImpl implements //查询项目信息 Project project = projectMapper.selectById(id); - + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); // 查询本地文件路径根目录(如 E:\yun) QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "filePath"); - queryWrapper.eq("type", "sdlocal"); + queryWrapper.eq("storage_id", project.getLocalStorageId()); + queryWrapper.eq("type", storageSource.getType()); StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); //获取文件列表 @@ -944,7 +993,7 @@ public class NodesServiceImpl extends ServiceImpl implements String absolutePath = path + nodeName + "/"; //获取文件列表 - FileListRequest fileListRequest = buildFileRequest(absolutePath); + FileListRequest fileListRequest = buildFileRequest(absolutePath,projectId); String storageKey = fileListRequest.getStorageKey(); Integer storageId = storageSourceService.findIdByKey(storageKey); if (storageId == null) { @@ -1012,13 +1061,15 @@ public class NodesServiceImpl extends ServiceImpl implements return map.get(adjustedIndex); } - private FileListRequest buildFileRequest(String path) { + private FileListRequest buildFileRequest(String path,String projectId) { + Project project = projectMapper.selectById(projectId); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); FileListRequest fileListRequest = new FileListRequest(); fileListRequest.setOrderBy("time"); fileListRequest.setOrderDirection("desc"); fileListRequest.setPassword(""); fileListRequest.setPath(path); - fileListRequest.setStorageKey("sdlocal"); + fileListRequest.setStorageKey(storageSource.getKey()); return fileListRequest; } @@ -1123,14 +1174,14 @@ public class NodesServiceImpl extends ServiceImpl implements try { // 1. 优化:合并重复的异常捕获 //------------------------------------------ - // 查询存储配置 - StorageSourceConfig config = getStorageConfig(); - if (config == null) throw new RuntimeException("未找到本地存储路径配置"); + // 优化:提前验证项目存在性(避免后续无效操作) Project project = projectMapper.selectById(id); if (project == null) throw new RuntimeException("项目不存在: " + id); - + // 查询存储配置 wrapper.eq("name", "filePath").eq("type", "sdlocal"); + StorageSourceConfig config = getStorageSourceConfig("filePath", "local", project.getLocalStorageId()); + if (config == null) throw new RuntimeException("未找到本地存储路径配置"); // 优化:解压路径统一构建逻辑 final String tempDir = "temporary"; final String zipName = getFileNameWithoutExtension(fileName); @@ -1172,12 +1223,7 @@ public class NodesServiceImpl extends ServiceImpl implements } } - // 新增辅助方法:解耦核心逻辑 -------------------------------------------------- - private StorageSourceConfig getStorageConfig() { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("name", "filePath").eq("type", "sdlocal"); - return storageSourceConfigMapper.selectOne(wrapper); - } + private void transferProjectFiles(String projectId, String basePath, String sourceDir, String targetDir) throws Exception { String sourcePath = "/temporary/" + sourceDir + "/"; @@ -1201,78 +1247,7 @@ public class NodesServiceImpl extends ServiceImpl implements } } -// public void documentUploadByIdAsync(String id, String fileName, LoginUser loginuser) throws IOException { -// try { -// -// // 查询本地文件路径根目录(如 E:\yun) -// QueryWrapper queryWrapper = new QueryWrapper<>(); -// queryWrapper.eq("name", "filePath"); -// queryWrapper.eq("type", "sdlocal"); -// StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); -// -// if (storageSourceConfig == null) { -// throw new RuntimeException("未找到本地存储路径配置"); -// } -// -// //解压以后的文件夹名称 -// String zipName = getFileNameWithoutExtension(fileName); // 示例:222 -// -// //查询项目信息 -// Project project = projectMapper.selectById(id); -// if (project == null) { -// throw new RuntimeException("项目不存在"); -// } -// -// if (!project.getProjectName().equals(zipName)) { -// throw new RuntimeException("压缩包名称需要和项目名称保持一致"); -// } -// -// String decompressionPath = "/" + "temporary"; -// //构建要解压的zip文件路径 例如 D:\yun\temporary\111.zip -// Path zipFilePath = Paths.get(storageSourceConfig.getValue(), decompressionPath, fileName); -// // 4. 构建解压目标路径 例如 D:\yun\temporary\111 -// Path destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath); -// -// LOGGER.info("要解压文件路径:{}", zipFilePath); -// LOGGER.info("解压以后文件路径:{}", destRoot); -// -// -// //todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描 -// -// //源文件夹路径 -// String sourceFolderPath = "/" + "temporary" + "/" + zipName + "/"; -// //目标文件夹路径 -// String targetFolderPath = "/" + project.getProjectName() + "/"; -// -// //首先执行解压缩 -// unzipToTemp(zipFilePath, String.valueOf(destRoot)); -// // 执行上传并且插入数据库 -// this.documentUploadById(id, sourceFolderPath, targetFolderPath, storageSourceConfig.getValue()); -// //开始执行更新表数据 名称是去掉后缀以后的 -// uploadProject(zipName, loginuser); -// LOGGER.info("开始更新表数据:{}", zipName); -// -// //获取文件路径 -// Path destRootPath = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName); -// File targetZip = new File(String.valueOf(zipFilePath)); -// File target = new File(String.valueOf(destRootPath)); -// //删除临时文件ZIP -// deleteDirectory(targetZip); -// //删除临时文件 -// deleteDirectory(target); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } catch (Exception e) { -// throw new RuntimeException(e); -// } finally { -// // 生成唯一Key -// String asyncKey = taskStatusHolder.documentUploadKey(id); -// // 无论成功失败都标记完成 -// taskStatusHolder.finishTask(asyncKey); -// WebSocketServer.sendMessageTo("专项文档上传任务处理完成!", "projectId_" + id); -// -// } -// } + public static void deleteDirectory(File directory) throws Exception { if (!directory.exists()) { @@ -1317,8 +1292,8 @@ public class NodesServiceImpl extends ServiceImpl implements return null; } - FileListRequest sourcefileListRequest = buildFileRequest(sourceFolderPath); - FileListRequest targetfileListRequest = buildFileRequest(targetFolderPath); + FileListRequest sourcefileListRequest = buildFileRequest(sourceFolderPath, id); + FileListRequest targetfileListRequest = buildFileRequest(targetFolderPath, id); //获取源文件列表 包含文件和文件夹 List sourceFileItemList = obtainFileItemResultData(sourcefileListRequest); @@ -1415,8 +1390,10 @@ public class NodesServiceImpl extends ServiceImpl implements LambdaQueryWrapper projectLambdaQueryWrapper = new LambdaQueryWrapper<>(); projectLambdaQueryWrapper.eq(Project::getProjectName, projectName); Project project = projectMapper.selectOne(projectLambdaQueryWrapper); + //如果项目不存在 if (project == null) { + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); String projectCode = this.generateNextProjectCode(); project.setProjectCode("1"); @@ -1435,7 +1412,7 @@ public class NodesServiceImpl extends ServiceImpl implements newFolderRequest.setName(project.getProjectName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(path);//请求路径,示例值(/) - newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); } @@ -1748,5 +1725,21 @@ public class NodesServiceImpl extends ServiceImpl implements } } + + + + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig( Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } + + // 辅助方法:获取存储配置 + private StorageSourceConfig getStorageSourceConfig(String name, String type,Integer id) { + return storageSourceConfigMapper.selectOne( + new LambdaQueryWrapper().eq(StorageSourceConfig::getName, name).eq(StorageSourceConfig::getType, type).eq(StorageSourceConfig::getStorageId,id) + ); + } + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java index 0e3c5ea..f1f9043 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/impl/ProjectServiceImpl.java @@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -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.specialDocument.mapper.ProjectMapper; @@ -12,23 +11,26 @@ import com.yfd.platform.modules.specialDocument.service.INodesService; import com.yfd.platform.modules.specialDocument.service.IProjectService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.yfd.platform.modules.storage.context.StorageSourceContext; +import com.yfd.platform.modules.storage.mapper.StorageSourceMapper; +import com.yfd.platform.modules.storage.model.entity.StorageSource; 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; import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; -import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; import com.yfd.platform.utils.StringUtils; import io.netty.channel.ChannelInboundHandlerAdapter; -import net.bytebuddy.implementation.bytecode.Throw; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.sql.Timestamp; +import javax.sql.DataSource; +import java.sql.*; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Collections; import java.util.List; /** @@ -57,13 +59,16 @@ public class ProjectServiceImpl extends ServiceImpl impl @Resource private INodesService nodesService; - //字典表Mapper - @Resource - private SysDictionaryItemsMapper sysDictionaryItemsMapper; @Resource private StorageSourceContext storageSourceContext; + @Resource + private StorageSourceMapper storageSourceMapper; + + @Autowired + private DataSource dataSource; + /********************************** * 用途说明: 分页查询专项文档管理-项目管理 * 参数说明 @@ -125,6 +130,7 @@ public class ProjectServiceImpl extends ServiceImpl impl // 转换为 Timestamp Timestamp currentTime = Timestamp.valueOf(now); project.setCreateTime(currentTime); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Project::getProjectName,project.getProjectName()); @@ -144,10 +150,13 @@ public class ProjectServiceImpl extends ServiceImpl impl newFolderRequest.setName(project.getProjectName());//新建的文件夹名称,示例值(/a/b/c) newFolderRequest.setPassword("");//文件夹密码, 如果文件夹需要密码才能访问,则支持请求密码,示例值(123456) newFolderRequest.setPath(path);//请求路径,示例值(/) - newFolderRequest.setStorageKey("sdlocal");//存储源 key,示例值(local minio) + newFolderRequest.setStorageKey(storageSource.getKey());//存储源 key,示例值(local minio) AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); if (flag) { + + // 动态创建数据表 + //createTaskFileTable(projectCode); return true; } else { LOGGER.error("节点新增成功,但是本地专项文件夹创建失败"); @@ -158,31 +167,67 @@ public class ProjectServiceImpl extends ServiceImpl impl return false; } + } -// //查询字典表获取项目类型对应数据字典 -// QueryWrapper queryWrapperSysDictionary = new QueryWrapper<>(); -// queryWrapperSysDictionary.eq("parentcode", "compressType"); -// queryWrapperSysDictionary.orderByAsc("orderno"); -// SysDictionaryItems sysDictionaryItems = sysDictionaryItemsMapper.selectOne(queryWrapperSysDictionary); -// if(sysDictionaryItems != null){ -// project.setProjectType(sysDictionaryItems.getDictName()); -// } + // 动态创建任务文件表 + private void createTaskFileTable(String taskCode) { + // 添加表名校验(重要!防止SQL注入) + if (!taskCode.matches("^\\d{5}$")) { // 假设任务编号是5位数字 + throw new IllegalArgumentException("非法任务编号格式: " + taskCode); + } - //TODO 01.21沟通以后说是先不用管重复校验问题 -// //通过项目名称 项目编号查询 查看是否存在 -// QueryWrapper queryWrapper = new QueryWrapper<>(); -// if(project.getProjectCode() != null){ -// queryWrapper.eq("project_code",project.getProjectCode()); -// } -// if(project.getProjectName() != null){ -// queryWrapper.eq("project_name",project.getProjectName()); -// } -// List projects = projectMapper.selectList(queryWrapper); -// if(){ -// -// } + String tableName = "sd_files_" + taskCode; + String sql = String.format( + "CREATE TABLE IF NOT EXISTS `%s` LIKE `sd_files`", + tableName + ); + try (Connection conn = dataSource.getConnection(); + Statement stmt = conn.createStatement()) { + // 1. 记录要执行的SQL + LOGGER.info("执行DDL: {}", sql); + // 2. 执行SQL + boolean result = stmt.execute(sql); + // 3. 验证结果 + LOGGER.debug("执行结果: {}", result); + // 4. 二次验证 + if (!tableExists(tableName)) { + throw new RuntimeException("表创建后验证失败: " + tableName); + } + } catch (SQLException e) { + // 提取MySQL错误信息 + String errorMsg = extractMysqlError(e); + LOGGER.error("创建表失败: {} - {}", tableName, errorMsg); + throw new RuntimeException("创建表失败: " + errorMsg, e); + } + } + + private boolean tableExists(String tableName) { + try (Connection conn = dataSource.getConnection()) { + DatabaseMetaData meta = conn.getMetaData(); + // 获取当前数据库信息 + String catalog = conn.getCatalog(); + String schema = conn.getSchema(); + // 查询表是否存在 + try (ResultSet rs = meta.getTables(catalog, schema, tableName, new String[]{"TABLE"})) { + return rs.next(); + } + } catch (SQLException e) { + LOGGER.error("检查表存在失败: {}", tableName, e); + return false; + } + } + + private String extractMysqlError(SQLException e) { + // 提取MySQL特有的错误信息 + while (e != null) { + if (e.getMessage().contains("MySQL")) { + return String.format("MySQL 错误 [%d]: %s", e.getErrorCode(), e.getMessage()); + } + e = e.getNextException(); + } + return "未知数据库错误"; } // 编号生成工具方法 @@ -216,6 +261,8 @@ public class ProjectServiceImpl extends ServiceImpl impl } + + /********************************** * 用途说明: 修改专项文档管理-项目管理 * 参数说明 @@ -256,6 +303,8 @@ public class ProjectServiceImpl extends ServiceImpl impl //循环所有的ID for (String id : dataset) { Project project = projectMapper.selectById(id); + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + String path = "/" + project.getProjectName() + "/"; QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("project_id", id); @@ -288,7 +337,7 @@ public class ProjectServiceImpl extends ServiceImpl impl BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); batchDeleteRequest.setDeleteItems(deleteItemList); - batchDeleteRequest.setStorageKey("sdlocal"); + batchDeleteRequest.setStorageKey(storageSource.getKey()); AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); int deleteSuccessCount = 0, deleteFailCount = 0, totalCount = CollUtil.size(deleteItemList); @@ -330,4 +379,23 @@ public class ProjectServiceImpl extends ServiceImpl impl } return value; } + + @Override + public List listProject() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.orderByDesc(Project::getProjectTime); + List projects = projectMapper.selectList(queryWrapper); + for (Project project : projects){ + StorageSource storageSource = getStorageConfig(project.getLocalStorageId()); + project.setKey(storageSource.getKey()); + project.setType(String.valueOf(storageSource.getType())); + } + return projects; + } + + // 辅助方法:获取存储配置 + private StorageSource getStorageConfig(Integer id) { + return storageSourceMapper.selectOne(new LambdaQueryWrapper().eq(StorageSource::getId, id) + ); + } } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/context/StorageSourceContext.java b/java/src/main/java/com/yfd/platform/modules/storage/context/StorageSourceContext.java index 52ebf4b..0decaf4 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/context/StorageSourceContext.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/context/StorageSourceContext.java @@ -13,6 +13,8 @@ import com.yfd.platform.modules.storage.model.entity.StorageSource; import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig; import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum; import com.yfd.platform.modules.storage.model.param.IStorageParam; +import com.yfd.platform.modules.storage.service.StorageSourceConfigService; +import com.yfd.platform.modules.storage.service.StorageSourceService; import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; import com.yfd.platform.modules.storage.support.StorageSourceSupport; import com.yfd.platform.utils.ClassUtils; @@ -176,12 +178,23 @@ public class StorageSourceContext { * * @return 存储源对应未初始化的 Service */ - private AbstractBaseFileService getInitStorageBeanByStorageId(Integer storageId) { - String keyById = storageSourceMapper.findKeyById(storageId); - StorageSource storageSource = storageSourceMapper.findByStorageKey(keyById); - String type = String.valueOf(storageSource.getType()); +// private AbstractBaseFileService getInitStorageBeanByStorageId(Integer storageId) { +// String keyById = storageSourceMapper.findKeyById(storageId); +//// StorageSource storageSource = storageSourceMapper.findByStorageKey(keyById); +// storageSourceMapper +//// String type = String.valueOf(storageSource.getType()); +// +// StorageTypeEnum storageTypeEnum = Optional.ofNullable(storageSourceMapper.findByStorageKey(keyById)).map(StorageSource::getType).orElse(null); +// for (AbstractBaseFileService value : storageTypeEnumFileServiceMap.values()) { +// if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) { +// return SpringUtil.getBean(value.getClass()); +// } +// } +// return null; +// } - StorageTypeEnum storageTypeEnum = Optional.ofNullable(storageSourceMapper.findByStorageKey(keyById)).map(StorageSource::getType).orElse(null); + private AbstractBaseFileService getInitStorageBeanByStorageId(Integer storageId) { + StorageTypeEnum storageTypeEnum = Optional.ofNullable(this.findById(storageId)).map(StorageSource::getType).orElse(null);; for (AbstractBaseFileService value : storageTypeEnumFileServiceMap.values()) { if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) { return SpringUtil.getBean(value.getClass()); @@ -190,6 +203,9 @@ public class StorageSourceContext { return null; } + public StorageSource findById(Integer id) { + return storageSourceMapper.selectById(id); + } /** * 获取指定存储源的初始化参数. diff --git a/java/src/main/java/com/yfd/platform/modules/storage/controller/base/StorageSourceController.java b/java/src/main/java/com/yfd/platform/modules/storage/controller/base/StorageSourceController.java index 5c4307a..6305fb9 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/controller/base/StorageSourceController.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/controller/base/StorageSourceController.java @@ -1,14 +1,17 @@ package com.yfd.platform.modules.storage.controller.base; import cn.hutool.core.bean.BeanUtil; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiSort; import com.yfd.platform.config.ResponseResult; import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest; import com.yfd.platform.modules.config.model.request.UpdateStorageSortRequest; +import com.yfd.platform.modules.experimentalData.domain.TsFiles; import com.yfd.platform.modules.storage.convert.StorageSourceConvert; import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO; import com.yfd.platform.modules.storage.model.entity.StorageSource; +import com.yfd.platform.modules.storage.model.enums.SearchModeEnum; import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult; import com.yfd.platform.modules.storage.service.StorageSourceService; import io.swagger.annotations.Api; @@ -48,6 +51,33 @@ public class StorageSourceController { return ResponseResult.successData(storageSourceAdminResults); } + @ApiOperationSupport(order = 11) + @ApiOperation(value = "根据类型获取所有存储源列表", notes = "根据类型获取所有添加的存储源列表,按照排序值由小到大排序") + @GetMapping("/storagesBytype") + public ResponseResult storageListBytype(String type) { + List list = storageSourceService.findAllOrderByOrderNumByType(type); + List storageSourceAdminResults = storageSourceConvert.entityToAdminResultList(list); + return ResponseResult.successData(storageSourceAdminResults); + } + + @ApiOperationSupport(order = 10) + @ApiOperation(value = "分页获取所有存储源列表", notes = "分页获取所有添加的存储源列表,按照排序值由小到大排序") + @GetMapping("/storagesPage") + public ResponseResult storagePage(Page page,String type,String name) { + Page pageResult = storageSourceService.findAllOrderByOrderNumPage(page, type,name); + + Page storageSourceAdminResults = storageSourceConvert.entityToAdminResultPage(pageResult); + return ResponseResult.successData(storageSourceAdminResults); + } + @ApiOperationSupport(order = 12) + @ApiOperation(value = "通过key查询type", notes = "通过key查询type") + @GetMapping("/storagesType") + public ResponseResult storagesType(String key) { + StorageSource storageSource = storageSourceService.findAllOrderBystoragesType(key); + return ResponseResult.successData(storageSource); + } + + @ApiOperationSupport(order = 2) @ApiOperation(value = "获取指定存储源参数", notes = "获取指定存储源基本信息及其参数") @@ -63,6 +93,10 @@ public class StorageSourceController { @ApiOperation(value = "保存存储源参数", notes = "保存存储源的所有参数") @PostMapping("/storage") public ResponseResult saveStorageItem(@RequestBody SaveStorageSourceRequest saveStorageSourceRequest) { + saveStorageSourceRequest.setEnable( true); + saveStorageSourceRequest.setEnableFileOperator( true); + saveStorageSourceRequest.setSearchMode(SearchModeEnum.SEARCH_CACHE_MODE); + saveStorageSourceRequest.setEnableFileAnnoOperator(false); Integer id = storageSourceService.saveStorageSource(saveStorageSourceRequest); return ResponseResult.successData(id); } @@ -78,6 +112,7 @@ public class StorageSourceController { } + @ApiOperationSupport(order = 5) @ApiOperation(value = "启用存储源", notes = "开启存储源后可在前台显示") @ApiImplicitParam(paramType = "path", name = "storageId", value = "存储源 id", required = true, dataTypeClass = Integer.class) diff --git a/java/src/main/java/com/yfd/platform/modules/storage/convert/StorageSourceConvert.java b/java/src/main/java/com/yfd/platform/modules/storage/convert/StorageSourceConvert.java index 6371658..ef5d2a3 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/convert/StorageSourceConvert.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/convert/StorageSourceConvert.java @@ -1,5 +1,6 @@ package com.yfd.platform.modules.storage.convert; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest; import com.yfd.platform.modules.readme.model.entity.ReadmeConfig; import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO; @@ -53,6 +54,7 @@ public interface StorageSourceConvert { */ List entityToAdminResultList(List list); + Page entityToAdminResultPage(Page pageResult); StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam); @@ -68,4 +70,5 @@ public interface StorageSourceConvert { StorageSource saveRequestToEntity(SaveStorageSourceRequest saveStorageSourceRequest); + } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java b/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java index 82a6fbb..768cda9 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/convert/impl/StorageSourceConvertImpl.java @@ -1,18 +1,31 @@ package com.yfd.platform.modules.storage.convert.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest; +import com.yfd.platform.modules.experimentalData.domain.TsTask; +import com.yfd.platform.modules.experimentalData.mapper.TsTaskMapper; import com.yfd.platform.modules.readme.model.entity.ReadmeConfig; +import com.yfd.platform.modules.specialDocument.domain.Project; +import com.yfd.platform.modules.specialDocument.mapper.ProjectMapper; import com.yfd.platform.modules.storage.convert.StorageSourceConvert; +import com.yfd.platform.modules.storage.mapper.StorageSourceConfigMapper; import com.yfd.platform.modules.storage.model.dto.StorageSourceAllParamDTO; import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO; import com.yfd.platform.modules.storage.model.entity.StorageSource; +import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig; import com.yfd.platform.modules.storage.model.result.StorageSourceAdminResult; import com.yfd.platform.modules.storage.model.result.StorageSourceConfigResult; import com.yfd.platform.modules.storage.model.result.StorageSourceResult; import org.springframework.stereotype.Service; +import javax.annotation.Resource; +import java.io.File; +import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; /** * @Date: 2025/1/10 12:44 @@ -21,6 +34,18 @@ import java.util.List; @Service public class StorageSourceConvertImpl implements StorageSourceConvert { + @Resource + private StorageSourceConfigMapper storageSourceConfigMapper; + + //专项项目表Mapper + @Resource + private ProjectMapper projectMapper; + + //试验任务Mapper + @Resource + private TsTaskMapper tsTaskMapper; + + @Override public List entityToResultList(List list) { if ( list == null ) { @@ -57,18 +82,127 @@ public class StorageSourceConvertImpl implements StorageSourceConvert { @Override public List entityToAdminResultList(List list) { - if ( list == null ) { - return null; + if (list == null) { + return Collections.emptyList(); } - List list1 = new ArrayList( list.size() ); - for ( StorageSource storageSource : list ) { - list1.add( storageSourceToStorageSourceAdminResult( storageSource ) ); - } - - return list1; + return list.stream() + .map(this::storageSourceToStorageSourceAdminResult) + .collect(Collectors.toList()); } + @Override + public Page entityToAdminResultPage(Page sourcePage) { + if (sourcePage == null) { + return new Page<>(); + } + List recordData = sourcePage.getRecords(); + for (StorageSource storageSource : recordData) { + StringBuilder result = new StringBuilder(); // 用于拼接结果 + String type = storageSource.getType().getKey(); + if ("local".equals(type)) { + //获取关联的存储内容 先获取专项文档 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Project::getLocalStorageId, storageSource.getId()); + List projects = projectMapper.selectList(queryWrapper); + if (projects.size()>0){ + for (Project project : projects) { + if (result.length() > 0) { + result.append(", "); // 如果结果不为空,加上逗号分隔 + } + result.append(project.getProjectName()); // 添加项目名称 + } + + } + + LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); + queryWrapper1.eq(TsTask::getLocalStorageId, storageSource.getId()); + List tsTasks = tsTaskMapper.selectList(queryWrapper1); + if (tsTasks.size()>0){ + for (TsTask task : tsTasks) { + if (result.length() > 0) { + result.append(", "); // 如果结果不为空,加上逗号分隔 + } + result.append(task.getTaskName()); // 添加任务名称 + } + } + + storageSource.setStoreContent(String.valueOf(result)); + //存储路径 + LambdaQueryWrapper queryWrapperData = new LambdaQueryWrapper<>(); + queryWrapperData.eq(StorageSourceConfig::getStorageId, storageSource.getId()); + queryWrapperData.eq(StorageSourceConfig::getName, "filePath"); + String value = storageSourceConfigMapper.selectOne(queryWrapperData).getValue(); + storageSource.setValueData(value); + + //空间使用率 + storageSource.setSpaceOccupancyRatio(calculateLocalStorageUsage(value)); + + }else { + LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); + queryWrapper1.eq(TsTask::getBackupStorageId, storageSource.getId()); + List tsTasks = tsTaskMapper.selectList(queryWrapper1); + if (tsTasks.size()>0){ + for (TsTask task : tsTasks) { + if (result.length() > 0) { + result.append(", "); // 如果结果不为空,加上逗号分隔 + } + result.append(task.getTaskName()); // 添加任务名称 + } + } + storageSource.setStoreContent(String.valueOf(result)); + storageSource.setValueData(null); + } + } + + + // 转换记录列表 + List records = entityToAdminResultList(sourcePage.getRecords()); + + // 创建目标分页对象并复制所有分页属性 + Page resultPage = new Page<>(); + + // 复制分页属性 + resultPage.setRecords(records); + resultPage.setTotal(sourcePage.getTotal()); + resultPage.setSize(sourcePage.getSize()); + resultPage.setCurrent(sourcePage.getCurrent()); + resultPage.setOrders(sourcePage.getOrders()); + resultPage.setOptimizeCountSql(sourcePage.optimizeCountSql()); + resultPage.setSearchCount(sourcePage.isSearchCount()); + resultPage.setCountId(sourcePage.getCountId()); + resultPage.setMaxLimit(sourcePage.getMaxLimit()); + + + + return resultPage; + } + + // 计算本地路径的空间使用率 + public static String calculateLocalStorageUsage(String path) { + File file = new File(path); + if (!file.exists()) { + throw new IllegalArgumentException("路径不存在: " + path); + } + + // 获取磁盘空间信息 + long totalSpace = file.getTotalSpace(); + long freeSpace = file.getFreeSpace(); + // 计算使用率 + long usedSpace = totalSpace - freeSpace; + double usagePercentage = (double) usedSpace / totalSpace * 100; + + // 格式化输出 + DecimalFormat df = new DecimalFormat("#.##"); + + return df.format(usagePercentage) + "%"; + + } + + + + + @Override public StorageSourceDTO entityToDTO(StorageSource storageSource, StorageSourceAllParamDTO storageSourceAllParam) { if ( storageSource == null && storageSourceAllParam == null ) { @@ -178,7 +312,9 @@ public class StorageSourceConvertImpl implements StorageSourceConvert { storageSourceAdminResult.setOrderNum( storageSource.getOrderNum() ); storageSourceAdminResult.setDefaultSwitchToImgMode( storageSource.getDefaultSwitchToImgMode() ); storageSourceAdminResult.setCompatibilityReadme( storageSource.getCompatibilityReadme() ); - + storageSourceAdminResult.setStoreContent( storageSource.getStoreContent()); + storageSourceAdminResult.setSpaceOccupancyRatio( storageSource.getSpaceOccupancyRatio()); + storageSourceAdminResult.setValueData( storageSource.getValueData()); return storageSourceAdminResult; } } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/mapper/StorageSourceMapper.java b/java/src/main/java/com/yfd/platform/modules/storage/mapper/StorageSourceMapper.java index f2b9048..380d356 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/mapper/StorageSourceMapper.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/mapper/StorageSourceMapper.java @@ -2,6 +2,7 @@ package com.yfd.platform.modules.storage.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.yfd.platform.modules.storage.model.entity.StorageSource; import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum; import org.apache.ibatis.annotations.Mapper; @@ -96,4 +97,7 @@ public interface StorageSourceMapper extends BaseMapper { */ String findKeyById(@Param("id") Integer id); + Page findAllOrderByOrderNumPage(@Param("page") Page page,@Param("type") String type,@Param("name") String name); + + List findAllOrderByOrderNumByType(@Param("type") String type); } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/model/entity/StorageSource.java b/java/src/main/java/com/yfd/platform/modules/storage/model/entity/StorageSource.java index b4dbd95..5624a8e 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/model/entity/StorageSource.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/model/entity/StorageSource.java @@ -102,5 +102,13 @@ public class StorageSource implements Serializable { @ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件") private Boolean compatibilityReadme; - + //存储内容 + @TableField(exist = false) + private String storeContent; + //存储空间使用率 + @TableField(exist = false) + private String spaceOccupancyRatio; + //存储路径 + @TableField(exist = false) + private String valueData; } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/model/enums/StorageTypeEnum.java b/java/src/main/java/com/yfd/platform/modules/storage/model/enums/StorageTypeEnum.java index ae63d06..335fd54 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/model/enums/StorageTypeEnum.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/model/enums/StorageTypeEnum.java @@ -2,8 +2,10 @@ package com.yfd.platform.modules.storage.model.enums; import com.baomidou.mybatisplus.annotation.EnumValue; import com.baomidou.mybatisplus.annotation.IEnum; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonValue; import io.swagger.annotations.ApiModelProperty; import java.util.HashMap; @@ -59,6 +61,12 @@ public enum StorageTypeEnum implements IEnum { this.description = description; } + // 添加反序列化方法 + @JsonCreator // 告诉Jackson用此方法反序列化 + public static StorageTypeEnum fromKey(String key) { + return ENUM_MAP.get(key); + } + @JsonValue // 告诉Jackson序列化时使用此字段 public String getKey() { return key; } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/model/result/StorageSourceAdminResult.java b/java/src/main/java/com/yfd/platform/modules/storage/model/result/StorageSourceAdminResult.java index 645443a..acfd7d1 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/model/result/StorageSourceAdminResult.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/model/result/StorageSourceAdminResult.java @@ -1,5 +1,6 @@ package com.yfd.platform.modules.storage.model.result; +import com.baomidou.mybatisplus.annotation.TableField; import com.yfd.platform.modules.storage.model.enums.SearchModeEnum; import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum; import io.swagger.annotations.ApiModel; @@ -81,4 +82,14 @@ public class StorageSourceAdminResult { @ApiModelProperty(value = "兼容 readme 模式", example = "true", notes = "兼容模式, 目录文档读取 readme.md 文件") private Boolean compatibilityReadme; + //存储内容 + @TableField(exist = false) + private String storeContent; + //存储空间使用率 + @TableField(exist = false) + private String spaceOccupancyRatio; + //存储路径 + @TableField(exist = false) + private String valueData; + } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java b/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java index 2154936..d82210f 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/service/StorageSourceService.java @@ -3,6 +3,9 @@ package com.yfd.platform.modules.storage.service; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ReflectUtil; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yfd.platform.exception.BadRequestException; import com.yfd.platform.exception.StorageSourceException; import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.modules.config.model.request.SaveStorageSourceRequest; @@ -15,6 +18,7 @@ import com.yfd.platform.modules.storage.model.dto.StorageSourceDTO; import com.yfd.platform.modules.storage.model.entity.StorageSource; import com.yfd.platform.modules.storage.model.entity.StorageSourceConfig; import com.yfd.platform.modules.storage.model.enums.StorageTypeEnum; +import com.yfd.platform.modules.storage.model.param.QiniuParam; import com.yfd.platform.utils.CodeMsg; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheConfig; @@ -61,6 +65,14 @@ public class StorageSourceService { return storageSourceMapper.findAllOrderByOrderNum(); } + public List findAllOrderByOrderNumByType(String type) { + return storageSourceMapper.findAllOrderByOrderNumByType(type); + } + + public Page findAllOrderByOrderNumPage(Page page,String type,String name) { + return storageSourceMapper.findAllOrderByOrderNumPage(page,type,name); + } + /** * 获取所有已启用的存储源列表,按照存储源的排序号排序 @@ -132,7 +144,21 @@ public class StorageSourceService { * * @return 存储源 DTO */ - @Cacheable(key = "'dto-' + #id", unless = "#result == null") +// @Cacheable(key = "'dto-' + #id", unless = "#result == null") +// public StorageSourceDTO findDTOById(Integer id) { +// // 将参数列表通过反射写入到 StorageSourceAllParam 中. +// StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO(); +// storageSourceConfigService.selectStorageConfigByStorageId(id) +// .forEach(storageSourceConfig -> +// ReflectUtil.setFieldValue(storageSourceAllParam, storageSourceConfig.getName(), storageSourceConfig.getValue()) +// ); +// +// // 获取数据库对象,转为 dto 对象返回 +// StorageSource storageSource = findById(id); +// return storageSourceConvert.entityToDTO(storageSource, storageSourceAllParam); +// } + + //从表中直接获取 不从缓存 public StorageSourceDTO findDTOById(Integer id) { // 将参数列表通过反射写入到 StorageSourceAllParam 中. StorageSourceAllParamDTO storageSourceAllParam = new StorageSourceAllParamDTO(); @@ -289,6 +315,11 @@ public class StorageSourceService { saveStorageSourceRequest.getId(), saveStorageSourceRequest.getName(), saveStorageSourceRequest.getKey(), saveStorageSourceRequest.getType().getDescription()); + StorageSource storageSourceData = storageSourceMapper.findByStorageKey(saveStorageSourceRequest.getKey()); + if (storageSourceData != null ){ + throw new BadRequestException("填充存储源别名已存在"); + } + // 转换为存储源 entity 对象 StorageSource storageSource = storageSourceConvert.saveRequestToEntity(saveStorageSourceRequest); @@ -319,4 +350,8 @@ public class StorageSourceService { return storageId; } + + public StorageSource findAllOrderBystoragesType(String storageKey) { + return storageSourceMapper.findByStorageKey(storageKey); + } } diff --git a/java/src/main/java/com/yfd/platform/utils/CodeMsg.java b/java/src/main/java/com/yfd/platform/utils/CodeMsg.java index 819e95e..0b9d95b 100644 --- a/java/src/main/java/com/yfd/platform/utils/CodeMsg.java +++ b/java/src/main/java/com/yfd/platform/utils/CodeMsg.java @@ -57,6 +57,7 @@ public class CodeMsg { public static CodeMsg STORAGE_SOURCE_INIT_FAIL = new CodeMsg("50100", "初始化存储源失败"); public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_CONFIG_FAIL = new CodeMsg("50101", "初始化存储源参数失败"); public static CodeMsg STORAGE_SOURCE_INIT_STORAGE_PARAM_FIELD_FAIL = new CodeMsg("50102", "填充存储源字段失败"); + public static CodeMsg STORAGE_SOURCE_INIT_REPEAT = new CodeMsg("50103", "填充存储源别名重复"); // 文件操作相关错误 diff --git a/java/src/main/java/com/yfd/platform/utils/TableNameContextHolder.java b/java/src/main/java/com/yfd/platform/utils/TableNameContextHolder.java new file mode 100644 index 0000000..08597a9 --- /dev/null +++ b/java/src/main/java/com/yfd/platform/utils/TableNameContextHolder.java @@ -0,0 +1,18 @@ +package com.yfd.platform.utils; + +public class TableNameContextHolder { + + private static final ThreadLocal TASK_CODE = new ThreadLocal<>(); + + public static void setTaskCode(String taskCode) { + TASK_CODE.set(taskCode); + } + + public static String getTaskCode() { + return TASK_CODE.get(); + } + + public static void clear() { + TASK_CODE.remove(); + } +} diff --git a/java/src/main/resources/mapper/experimentalData/TsFilesMapper.xml b/java/src/main/resources/mapper/experimentalData/TsFilesMapper.xml index 22e743b..9aca134 100644 --- a/java/src/main/resources/mapper/experimentalData/TsFilesMapper.xml +++ b/java/src/main/resources/mapper/experimentalData/TsFilesMapper.xml @@ -38,7 +38,16 @@ SELECT count(*) FROM ts_files WHERE node_id IN (SELECT node_id FROM node_tree) - AND backup_path IS NOT NULL + AND (backup_path IS NOT NULL AND backup_path != '') + + UPDATE ts_files + SET work_path = REPLACE ( + work_path,#{oldBasePath}, #{newBasePath}) + + WHERE + task_id = #{taskId} + AND work_path LIKE CONCAT(#{oldBasePath}, '%') + diff --git a/java/src/main/resources/mapper/specialDocument/FilesMapper.xml b/java/src/main/resources/mapper/specialDocument/FilesMapper.xml index 2b46a12..53298d6 100644 --- a/java/src/main/resources/mapper/specialDocument/FilesMapper.xml +++ b/java/src/main/resources/mapper/specialDocument/FilesMapper.xml @@ -37,4 +37,120 @@ DELETE FROM sd_files WHERE node_id IN (SELECT id FROM node_tree) + + + UPDATE sd_files + SET file_path = REPLACE ( + file_path,#{oldBasePath}, #{newBasePath}) + + WHERE + project_id = #{projectId} + AND file_path LIKE CONCAT(#{oldBasePath}, '%') + + + + + + + INSERT INTO `${tableName}` ( + id, + project_id, + node_id, + file_name, + file_path, + keywords, + file_size, + upload_time, + uploader + + ) VALUES ( + #{files.id}, + #{files.projectId}, + #{files.nodeId}, + #{files.fileName}, + #{files.filePath}, + #{files.keywords}, + #{files.fileSize}, + #{files.uploadTime}, + #{files.uploader} + + ) + + + + UPDATE `${tableName}` + SET + file_name = #{files.fileName}, + file_path = #{files.filePath}, + keywords = #{files.keywords}, + file_size = #{files.fileSize}, + upload_time = #{files.uploadTime}, + uploader = #{files.uploader} + + WHERE id = #{files.id} + + + + + + + + + + DELETE FROM `${tableName}` + + + + AND id = #{files.id} + + + diff --git a/java/src/main/resources/mapper/specialDocument/NodesMapper.xml b/java/src/main/resources/mapper/specialDocument/NodesMapper.xml index 463e51d..94d7d47 100644 --- a/java/src/main/resources/mapper/specialDocument/NodesMapper.xml +++ b/java/src/main/resources/mapper/specialDocument/NodesMapper.xml @@ -37,4 +37,16 @@ DELETE FROM sd_nodes WHERE id IN (SELECT id FROM node_tree) + + + UPDATE sd_nodes + SET custom3 = REPLACE ( + custom3,#{oldBasePath}, #{newBasePath}) + + WHERE + project_id = #{projectId} + + AND custom3 LIKE CONCAT(#{oldBasePath}, '%') + + diff --git a/java/src/main/resources/mapper/specialDocument/ProjectMapper.xml b/java/src/main/resources/mapper/specialDocument/ProjectMapper.xml index ba7fc4e..2846e15 100644 --- a/java/src/main/resources/mapper/specialDocument/ProjectMapper.xml +++ b/java/src/main/resources/mapper/specialDocument/ProjectMapper.xml @@ -2,4 +2,8 @@ + + CREATE TABLE IF NOT EXISTS `${tableName}` LIKE `sd_files` + + diff --git a/java/src/main/resources/mapper/storage/StorageSourceMapper.xml b/java/src/main/resources/mapper/storage/StorageSourceMapper.xml index 7db82ee..e1b28f1 100644 --- a/java/src/main/resources/mapper/storage/StorageSourceMapper.xml +++ b/java/src/main/resources/mapper/storage/StorageSourceMapper.xml @@ -74,4 +74,37 @@ from fi_storage_source where `id`=#{id,jdbcType=INTEGER} + + + + +