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 01e7937..7b599b6 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 @@ -253,6 +253,8 @@ public class TsFilesServiceImpl extends ServiceImpl impl FileItemResult fileItemResult = fileService.getFileItem(path); if (fileItemResult == null || fileItemResult.getName() == null) { LOGGER.error("{}文件没有上传到工作空间,请重新选择上传", fileNameData); + // 跳过处理这个文件,避免空指针异常 + continue; } tsFiles.setUrl(fileItemResult.getUrl()); //如果是压缩文件 类型就给zip @@ -260,7 +262,12 @@ public class TsFilesServiceImpl extends ServiceImpl impl if (isValid) { tsFiles.setType("ZIP"); } else { - tsFiles.setType(fileItemResult.getType().getValue()); + // 添加空值检查,防止空指针异常 + if (fileItemResult.getType() != null) { + tsFiles.setType(fileItemResult.getType().getValue()); + } else { + tsFiles.setType("UNKNOWN"); + } } if (tsFiles.getUpdateTime() == null) { tsFiles.setUpdateTime(tsFiles.getUploadTime()); 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 a121dee..aabab62 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 @@ -551,51 +551,74 @@ public class TsTaskServiceImpl extends ServiceImpl impleme @Override public boolean deleteTstaskByIds(List dataset) { Boolean value = false; + + LOGGER.info("开始批量删除试验任务,任务数量: {}", dataset.size()); + LOGGER.debug("待删除的任务ID列表: {}", dataset); try { //循环所有的ID for (String taskId : dataset) { try { + LOGGER.info("开始处理任务删除,任务ID: {}", taskId); + //获取试验任务及任务编码 TsTask tsTask = tsTaskMapper.selectById(taskId); + if (tsTask == null) { + LOGGER.warn("未找到指定的任务,任务ID: {}", taskId); + continue; + } + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); + LOGGER.debug("设置任务编码上下文,任务编码: {}", tsTask.getTaskCode()); // 删除节点表 LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); deleteWrapper.eq(TsNodes::getTaskId, taskId); - tsNodesMapper.delete(deleteWrapper); + int deletedNodes = tsNodesMapper.delete(deleteWrapper); + LOGGER.info("删除任务相关的节点数据,任务ID: {}, 删除条数: {}", taskId, deletedNodes); - // 删除文件表 - LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); - deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); - tsFilesMapper.delete(deleteWrapperFiles); + // 只有当任务文件表存在时才尝试删除文件数据 + if (tableExists("ts_files_" + tsTask.getTaskCode())) { + // 删除文件表 + LambdaQueryWrapper deleteWrapperFiles = new LambdaQueryWrapper<>(); + deleteWrapperFiles.eq(TsFiles::getTaskId, taskId); + int deletedFiles = tsFilesMapper.delete(deleteWrapperFiles); + LOGGER.info("删除任务相关的文件数据,任务ID: {}, 删除条数: {}", taskId, deletedFiles); + } else { + LOGGER.info("任务文件表不存在,跳过文件数据删除,任务ID: {}", taskId); + } // 删除本地存储空间中的文件夹 StorageSource localStorageSource = getStorageConfig(tsTask.getLocalStorageId()); + LOGGER.info("开始删除本地存储空间中的文件夹,任务ID: {}, 本地存储ID: {}", taskId, tsTask.getLocalStorageId()); deleteStorageFolder(localStorageSource, tsTask); // 如果有备份存储空间,也删除备份存储空间中的文件夹 if (tsTask.getBackupStorageId() != null && tsTask.getBackupStorageId() > 0) { StorageSource backupStorageSource = getStorageConfig(tsTask.getBackupStorageId()); + LOGGER.info("开始删除备份存储空间中的文件夹,任务ID: {}, 备份存储ID: {}", taskId, tsTask.getBackupStorageId()); deleteStorageFolder(backupStorageSource, tsTask); } + // 删除当前试验任务 int deleteCount = tsTaskMapper.deleteById(taskId); if (deleteCount == 1) { - LOGGER.info("tstask表结构删除成功"); + LOGGER.info("试验任务删除成功,任务ID: {}", taskId); value = true; } else { - LOGGER.error("tstask表结构删除失败"); + LOGGER.error("试验任务删除失败,任务ID: {}, 实际删除条数: {}", taskId, deleteCount); value = false; } } finally { // 每次处理完一个任务后清理上下文 + LOGGER.debug("清理任务上下文,任务ID: {}", taskId); TableNameContextHolder.clear(); } } + LOGGER.info("批量删除试验任务完成,任务数量: {}", dataset.size()); return value; } catch (Exception e) { - LOGGER.error("删除试验任务时发生异常", e); + LOGGER.error("删除试验任务时发生异常,任务ID列表: {}", dataset, e); return false; } } @@ -604,7 +627,20 @@ public class TsTaskServiceImpl extends ServiceImpl impleme // 这个方法会递归删除试验任务文件夹及其下的所有子文件夹和文件。当调用 fileService.deleteFolder() 方法时,存储服务实现会自动处理递归删除逻辑,确保整个文件夹树都被清除。 //这是文件存储系统的基本特性,不论是本地文件系统还是MinIO等云存储服务,在删除文件夹时都会删除其包含的所有内容。 private void deleteStorageFolder(StorageSource storageSource, TsTask tsTask) { + LOGGER.info("==deleteStorageFolder begin===="); + if (storageSource == null) { + LOGGER.warn("存储源配置为空,跳过删除操作,任务名称: {}", tsTask.getTaskName()); + return; + } + + if (tsTask == null || tsTask.getTaskName() == null) { + LOGGER.warn("任务信息不完整,跳过删除操作"); + return; + } + try { + LOGGER.info("准备删除存储文件夹,存储类型: {}, 任务名称: {}", storageSource.getKey(), tsTask.getTaskName()); + List deleteItemList = new ArrayList<>(); BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem(); deleteItemData.setName(tsTask.getTaskName()); @@ -616,33 +652,50 @@ public class TsTaskServiceImpl extends ServiceImpl impleme BatchDeleteRequest batchDeleteRequest = new BatchDeleteRequest(); batchDeleteRequest.setDeleteItems(deleteItemList); batchDeleteRequest.setStorageKey(storageSource.getKey()); + AbstractBaseFileService fileService = storageSourceContext.getByStorageKey(batchDeleteRequest.getStorageKey()); + if (fileService == null) { + LOGGER.error("未能获取到文件服务实例,存储类型: {}", storageSource.getKey()); + return; + } int deleteSuccessCount = 0; for (BatchDeleteRequest.DeleteItem deleteItem : deleteItemList) { boolean flag = false; try { if (deleteItem.getType() == FileTypeEnum.FILE) { + LOGGER.info("删除文件,存储类型: {}, 路径: {}, 名称: {}", + storageSource.getKey(), deleteItem.getPath(), deleteItem.getName()); flag = fileService.deleteFile(deleteItem.getPath(), deleteItem.getName()); } else if (deleteItem.getType() == FileTypeEnum.FOLDER) { + LOGGER.info("删除文件夹,存储类型: {}, 路径: {}, 名称: {}", + storageSource.getKey(), deleteItem.getPath(), deleteItem.getName()); flag = fileService.deleteFolder(deleteItem.getPath(), deleteItem.getName()); + } if (flag) { deleteSuccessCount++; LOGGER.info("删除成功 - 存储类型: {}, 类型: {}, 路径: {}, 名称: {}", - storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); + storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); } else { LOGGER.warn("删除失败 - 存储类型: {}, 类型: {}, 路径: {}, 名称: {}", - storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); + storageSource.getKey(), deleteItem.getType(), deleteItem.getPath(), deleteItem.getName()); } } catch (Exception e) { LOGGER.error("删除文件/文件夹失败, 存储类型: {}, 文件路径: {}, 文件名称: {}", storageSource.getKey(), deleteItem.getPath(), deleteItem.getName(), e); + // 继续处理其他项目,不中断整个删除过程 } } + + LOGGER.info("存储文件夹删除完成,存储类型: {}, 成功删除项数量: {}", storageSource.getKey(), deleteSuccessCount); } catch (Exception e) { LOGGER.error("删除存储空间文件夹时发生异常, 存储类型: {}", storageSource.getKey(), e); + } catch (Error err) { + // 捕获Error防止JVM退出 + LOGGER.error("删除存储空间文件夹时发生严重错误, 存储类型: {}", storageSource.getKey(), err); + // 不重新抛出Error,防止Tomcat退出 } } @@ -662,19 +715,29 @@ public class TsTaskServiceImpl extends ServiceImpl impleme boolean allDeletable = true; for (TsTask tsTask : tsTasks) { + // 检查对应的任务文件表是否存在 + if (!tableExists("ts_files_" + tsTask.getTaskCode())) { + // 如果表不存在,可以安全删除 + continue; + } + TableNameContextHolder.setTaskCode(tsTask.getTaskCode()); - // 查询 backup_path 既不为 null 也不为空字符串的记录 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(TsFiles::getTaskId, tsTask.getId()) - .isNotNull(TsFiles::getBackupPath) - .ne(TsFiles::getBackupPath, ""); + try { + // 查询 backup_path 既不为 null 也不为空字符串的记录 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(TsFiles::getTaskId, tsTask.getId()) + .isNotNull(TsFiles::getBackupPath) + .ne(TsFiles::getBackupPath, ""); - int count = tsFilesService.count(queryWrapper); + int count = tsFilesService.count(queryWrapper); - if (count > 0) { - allDeletable = false; - break; // 一旦发现不可删除项,提前终止循环 + if (count > 0) { + allDeletable = false; + break; // 一旦发现不可删除项,提前终止循环 + } + } finally { + TableNameContextHolder.clear(); } } @@ -685,8 +748,6 @@ public class TsTaskServiceImpl extends ServiceImpl impleme // 使用日志框架代替 printStackTrace LOGGER.error("确认删除实验任务时发生异常", e); return ResponseResult.error("查询失败"); - } finally { - TableNameContextHolder.clear(); } } diff --git a/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java b/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java index 8fe2f12..73cfbb3 100644 --- a/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java +++ b/java/src/main/java/com/yfd/platform/modules/storage/service/impl/LocalServiceImpl.java @@ -165,7 +165,10 @@ public class LocalServiceImpl extends AbstractProxyTransferService { checkPathSecurity(path); checkNameSecurity(name); - String fullPath = StringUtils.concat(param.getFilePath(), path, name); + String fullPath = StringUtils.concatTrimStartSlashes(param.getFilePath(), name); + log.info("param.getFilePath==========,{}", param.getFilePath()); + log.info("fullPath==========,{}", fullPath); + try { // 检查文件夹是否存在 File folder = new File(fullPath); @@ -184,7 +187,7 @@ public class LocalServiceImpl extends AbstractProxyTransferService { } // 递归修改文件夹内所有文件的权限 - setWritableRecursively(folder); + //setWritableRecursively(folder); return FileUtil.del(fullPath); } catch (Exception e) { diff --git a/java/src/main/resources/application-prod.yml b/java/src/main/resources/application-prod.yml index f5fca98..d3acab8 100644 --- a/java/src/main/resources/application-prod.yml +++ b/java/src/main/resources/application-prod.yml @@ -17,6 +17,10 @@ spring: url: jdbc:mysql://db-container:3306/filemanagedb?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true username: root password: pwd@FileMgr + initial-size: 5 + min-idle: 5 + max-active: 20 + validation-query: SELECT 1 mvc: pathmatch: matching-strategy: ant_path_matcher