解决节点删除问题

This commit is contained in:
wanxiaoli 2025-11-26 14:02:33 +08:00
parent f4f7511603
commit 594c4d4189
4 changed files with 99 additions and 24 deletions

View File

@ -253,6 +253,8 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> 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<TsFilesMapper, TsFiles> 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());

View File

@ -551,51 +551,74 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> impleme
@Override
public boolean deleteTstaskByIds(List<String> 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<TsNodes> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(TsNodes::getTaskId, taskId);
tsNodesMapper.delete(deleteWrapper);
int deletedNodes = tsNodesMapper.delete(deleteWrapper);
LOGGER.info("删除任务相关的节点数据任务ID: {}, 删除条数: {}", taskId, deletedNodes);
// 删除文件表
LambdaQueryWrapper<TsFiles> deleteWrapperFiles = new LambdaQueryWrapper<>();
deleteWrapperFiles.eq(TsFiles::getTaskId, taskId);
tsFilesMapper.delete(deleteWrapperFiles);
// 只有当任务文件表存在时才尝试删除文件数据
if (tableExists("ts_files_" + tsTask.getTaskCode())) {
// 删除文件表
LambdaQueryWrapper<TsFiles> 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<TsTaskMapper, TsTask> 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<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
BatchDeleteRequest.DeleteItem deleteItemData = new BatchDeleteRequest.DeleteItem();
deleteItemData.setName(tsTask.getTaskName());
@ -616,33 +652,50 @@ public class TsTaskServiceImpl extends ServiceImpl<TsTaskMapper, TsTask> 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<TsTaskMapper, TsTask> impleme
boolean allDeletable = true;
for (TsTask tsTask : tsTasks) {
// 检查对应的任务文件表是否存在
if (!tableExists("ts_files_" + tsTask.getTaskCode())) {
// 如果表不存在可以安全删除
continue;
}
TableNameContextHolder.setTaskCode(tsTask.getTaskCode());
// 查询 backup_path 既不为 null 也不为空字符串的记录
LambdaQueryWrapper<TsFiles> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(TsFiles::getTaskId, tsTask.getId())
.isNotNull(TsFiles::getBackupPath)
.ne(TsFiles::getBackupPath, "");
try {
// 查询 backup_path 既不为 null 也不为空字符串的记录
LambdaQueryWrapper<TsFiles> 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<TsTaskMapper, TsTask> impleme
// 使用日志框架代替 printStackTrace
LOGGER.error("确认删除实验任务时发生异常", e);
return ResponseResult.error("查询失败");
} finally {
TableNameContextHolder.clear();
}
}

View File

@ -165,7 +165,10 @@ public class LocalServiceImpl extends AbstractProxyTransferService<LocalParam> {
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<LocalParam> {
}
// 递归修改文件夹内所有文件的权限
setWritableRecursively(folder);
//setWritableRecursively(folder);
return FileUtil.del(fullPath);
} catch (Exception e) {

View File

@ -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