代码提交

This commit is contained in:
lilin 2025-05-27 14:52:54 +08:00
parent 83a819b84f
commit 01d1bf1dbf
10 changed files with 245 additions and 206 deletions

View File

@ -21,7 +21,7 @@ public class TaskStatusHolder {
// 生成专项扫描唯一Keyproject_id // 生成专项扫描唯一Keyproject_id
public String specialGenerateKey(String id) { public String specialGenerateKey(String id) {
return id + ":"; return id + "扫描:";
} }
// 生成专项文档上传唯一Keyproject_id+上传: // 生成专项文档上传唯一Keyproject_id+上传:
public String documentUploadKey(String id) { public String documentUploadKey(String id) {

View File

@ -3,6 +3,7 @@ package com.yfd.platform.modules.experimentalData.controller;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
@ -65,11 +66,12 @@ public class TsFilesController {
//分页查询 //分页查询
int currentPage = (int) page.getCurrent(); int currentPage = (int) page.getCurrent();
// 先尝试从缓存获取 // 先尝试从缓存获取
IPage<TsFiles> cachedPage = tsFilesService.getCachedTsFilesPage(taskId, nodeId, currentPage); if(!StrUtil.isEmpty(id)){
if (cachedPage != null) { IPage<TsFiles> cachedPage = tsFilesService.getCachedTsFilesPage(taskId, nodeId, currentPage,id);
return ResponseResult.successData(cachedPage); if (cachedPage != null) {
return ResponseResult.successData(cachedPage);
}
} }
Page<TsFiles> tsfilesPage = tsFilesService.getTsFilesPage(id, fileName, startDate, endDate, keywords, nodeId, taskId, fileName, childNode, page); Page<TsFiles> tsfilesPage = tsFilesService.getTsFilesPage(id, fileName, startDate, endDate, keywords, nodeId, taskId, fileName, childNode, page);
return ResponseResult.successData(tsfilesPage); return ResponseResult.successData(tsfilesPage);
} }
@ -589,16 +591,19 @@ public class TsFilesController {
} }
// 生成唯一Key // 生成唯一Key
String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); String asyncKey = taskStatusHolder.generateKey(taskId, nodeId);
JSONObject jsonObject1 = new JSONObject();
// 检查任务是否已存在 // 检查任务是否已存在
String existingStatus = taskStatusHolder.getStatus(asyncKey); String existingStatus = taskStatusHolder.getStatus(asyncKey);
if ("TASK_NOT_FOUND".equals(existingStatus)) { if ("TASK_NOT_FOUND".equals(existingStatus)) {
return ResponseResult.success("1"); jsonObject1.putOpt("status", "1");
return ResponseResult.successData(jsonObject1);
} }
if ("IN_PROGRESS".equals(existingStatus)) { if ("IN_PROGRESS".equals(existingStatus)) {
return ResponseResult.success("0"); jsonObject1.putOpt("status", "0");
return ResponseResult.successData(jsonObject1);
} else if ("COMPLETED".equals(existingStatus)) { } else if ("COMPLETED".equals(existingStatus)) {
return ResponseResult.success("自动备份任务已完成!"); jsonObject1.putOpt("status", "1");
return ResponseResult.successData(jsonObject1);
} }
return null; return null;

View File

@ -3,6 +3,7 @@ package com.yfd.platform.modules.experimentalData.controller;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
@ -103,11 +104,11 @@ public class TsNodesController {
@PostMapping("/deleteTsNodesById") @PostMapping("/deleteTsNodesById")
@ApiOperation("根据ID删除试验任务节点") @ApiOperation("根据ID删除试验任务节点")
@PreAuthorize("@el.check('del:tsnodes')") @PreAuthorize("@el.check('del:tsnodes')")
public ResponseResult deleteTsNodesById(@RequestParam String id,String path) { public ResponseResult deleteTsNodesById(@RequestParam String id, String path) {
if (StrUtil.isBlank(id)) { if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空"); return ResponseResult.error("参数为空");
} }
boolean isOk = tsNodesService.deleteTsNodesById(id,path); boolean isOk = tsNodesService.deleteTsNodesById(id, path);
if (isOk) { if (isOk) {
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
@ -160,6 +161,7 @@ public class TsNodesController {
if (StrUtil.isEmpty(id)) { if (StrUtil.isEmpty(id)) {
return ResponseResult.error("id为空"); return ResponseResult.error("id为空");
} }
JSONObject jsonObject1 = new JSONObject();
// 生成唯一Key // 生成唯一Key
String asyncKey = taskStatusHolder.testDatascanKey(id); String asyncKey = taskStatusHolder.testDatascanKey(id);
@ -167,12 +169,15 @@ public class TsNodesController {
// 检查任务是否已存在 // 检查任务是否已存在
String existingStatus = taskStatusHolder.getStatus(asyncKey); String existingStatus = taskStatusHolder.getStatus(asyncKey);
if ("TASK_NOT_FOUND".equals(existingStatus)) { if ("TASK_NOT_FOUND".equals(existingStatus)) {
return ResponseResult.success("1"); jsonObject1.putOpt("status", "1");
return ResponseResult.successData(jsonObject1);
} }
if ("IN_PROGRESS".equals(existingStatus)) { if ("IN_PROGRESS".equals(existingStatus)) {
return ResponseResult.success("0"); jsonObject1.putOpt("status", "0");
return ResponseResult.successData(jsonObject1);
} else if ("COMPLETED".equals(existingStatus)) { } else if ("COMPLETED".equals(existingStatus)) {
return ResponseResult.success("专项文档扫描任务已完成!"); jsonObject1.putOpt("status", "1");
return ResponseResult.successData(jsonObject1);
} }
return null; return null;

View File

@ -247,7 +247,7 @@ public interface ITsFilesService extends IService<TsFiles> {
Object compareMd5List(List<String> dataset, String nodeId, String taskId); Object compareMd5List(List<String> dataset, String nodeId, String taskId);
void automaticFileBackupAsyncByIds(List<String> dataset); void automaticFileBackupAsyncByIds(List<String> dataset) throws IOException;
IPage<TsFiles> getCachedTsFilesPage(String taskId, String nodeId, int currentPage); IPage<TsFiles> getCachedTsFilesPage(String taskId, String nodeId, int currentPage,String id);
} }

View File

@ -17,6 +17,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.services.s3.model.S3Object;
@ -31,6 +32,7 @@ import com.opencsv.CSVWriter;
import com.opencsv.exceptions.CsvValidationException; import com.opencsv.exceptions.CsvValidationException;
import com.yfd.platform.component.ServerSendEventServer; import com.yfd.platform.component.ServerSendEventServer;
import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.experimentalData.domain.*; import com.yfd.platform.modules.experimentalData.domain.*;
import com.yfd.platform.modules.experimentalData.mapper.TsFilesMapper; import com.yfd.platform.modules.experimentalData.mapper.TsFilesMapper;
@ -52,6 +54,7 @@ import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService;
import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.system.domain.LoginUser;
import com.yfd.platform.system.domain.SysDictionaryItems; import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.task.TaskMessage;
import com.yfd.platform.utils.StringUtils; import com.yfd.platform.utils.StringUtils;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
@ -79,6 +82,7 @@ import java.io.*;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.zip.*; import java.util.zip.*;
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
@ -132,9 +136,9 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
private TaskStatusHolder taskStatusHolder; private TaskStatusHolder taskStatusHolder;
@Autowired @Autowired
private RedisTemplate<String, Object> redisTemplate; private RedisTemplate<String, Object> redisTemplate;
private TaskMessage taskMessage;
/********************************** /**********************************
* 用途说明: 分页查询试验数据管理-文档内容 * 用途说明: 分页查询试验数据管理-文档内容
@ -264,9 +268,14 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
tsFilesPage.setRecords(records); // 同步到 tsFilesPage tsFilesPage.setRecords(records); // 同步到 tsFilesPage
int currentPage = (int) page.getCurrent(); int currentPage = (int) page.getCurrent();
// 如果是前五页将结果存入Redis有效期建议30分钟 // 如果是前五页将结果存入Redis有效期建议30分钟
if (currentPage >= 1 && currentPage <= 5) { 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);
}
} else {
String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_page_" + currentPage; String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_page_" + currentPage;
redisTemplate.opsForValue().set(redisKey, tsFilesPage, 2, TimeUnit.HOURS); redisTemplate.delete(redisKey);
} }
return tsFilesPage; return tsFilesPage;
@ -274,14 +283,17 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
/** /**
* Redis缓存获取 * Redis缓存获取
*
* @param taskId * @param taskId
* @param nodeId * @param nodeId
* @param currentPage * @param currentPage
* @return * @return
*/ */
@Override @Override
public IPage<TsFiles> getCachedTsFilesPage(String taskId, String nodeId, int currentPage) { public IPage<TsFiles> getCachedTsFilesPage(String taskId, String nodeId, int currentPage, String id) {
String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_page_" + currentPage; String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_parentId" + id + "_page_" + currentPage;
Object data = redisTemplate.opsForValue().get(redisKey); Object data = redisTemplate.opsForValue().get(redisKey);
if (data instanceof IPage<?>) { if (data instanceof IPage<?>) {
@ -299,10 +311,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
return null; return null;
} }
public void cachePageData(String taskId, String nodeId, int currentPage, Page<TsFiles> pageData) {
String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_page_" + currentPage;
redisTemplate.opsForValue().set(redisKey, pageData, 2, TimeUnit.HOURS);
}
public boolean hasValidExtension(String name, List<SysDictionaryItems> sysDictionaryItems) { public boolean hasValidExtension(String name, List<SysDictionaryItems> sysDictionaryItems) {
// 如果传入的文件名为空返回 false // 如果传入的文件名为空返回 false
@ -407,7 +416,9 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
//todo 新增成功以后 删除redis //todo 新增成功以后 删除redis
for (int page = 1; page <= 5; page++) { for (int page = 1; page <= 5; page++) {
String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_page_" + page; String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page;
redisTemplate.delete(redisKey); redisTemplate.delete(redisKey);
} }
LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId());
@ -539,7 +550,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
//todo 新增成功以后 删除redis //todo 新增成功以后 删除redis
for (int page = 1; page <= 5; page++) { for (int page = 1; page <= 5; page++) {
String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_page_" + page; String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page;
redisTemplate.delete(redisKey); redisTemplate.delete(redisKey);
} }
LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId());
@ -649,7 +660,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
//todo 新增成功以后 删除redis //todo 新增成功以后 删除redis
for (int page = 1; page <= 5; page++) { for (int page = 1; page <= 5; page++) {
String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_page_" + page; String redisKey = "tsfiles_" + tsFiles.getTaskId() + "_" + tsFiles.getNodeId() + "_parentId" + tsFiles.getParentId() + "_page_" + page;
redisTemplate.delete(redisKey); redisTemplate.delete(redisKey);
} }
LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId()); LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", tsFiles.getTaskId(), tsFiles.getNodeId());
@ -932,14 +943,6 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
int LocalSuccessCount = 0, LocalFailCount = 0, Localtotal = CollUtil.size(dataset); int LocalSuccessCount = 0, LocalFailCount = 0, Localtotal = CollUtil.size(dataset);
//Todo 最直接的办法 循环出来 一条一条删除 //Todo 最直接的办法 循环出来 一条一条删除
for (TsFiles files : filesList) { for (TsFiles files : filesList) {
// //todo 新增成功以后 删除redis
// for (int page = 1; page <= 5; page++) {
// String redisKey = "tsfiles_" + files.getTaskId() + "_" + files.getNodeId() + "_page_" + page;
// redisTemplate.delete(redisKey);
// }
// LOGGER.info("已清理缓存taskid={}, node={}, pages=1-5", files.getTaskId(), files.getNodeId());
//判断是文件还是文件夹 //判断是文件还是文件夹
if ("FOLDER".equals(files.getIsFile())) { if ("FOLDER".equals(files.getIsFile())) {
//如果是文件夹 //如果是文件夹
@ -3372,12 +3375,13 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); String asyncKey = taskStatusHolder.generateKey(taskId, nodeId);
// 无论成功失败都标记完成 // 无论成功失败都标记完成
taskStatusHolder.finishTask(asyncKey); taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("文件自动备份完成", "backups");
} }
} }
@Override @Override
@Async("asyncExecutor") @Async("asyncExecutor")
public void automaticFileBackupAsyncByIds(List<String> dataset) { public void automaticFileBackupAsyncByIds(List<String> dataset) throws IOException {
try { try {
// 执行实际备份逻辑 // 执行实际备份逻辑
this.automaticFileBackupByIds(dataset); this.automaticFileBackupByIds(dataset);
@ -3386,12 +3390,11 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
String asyncKey = taskStatusHolder.generateKeybyId(dataset); String asyncKey = taskStatusHolder.generateKeybyId(dataset);
// 无论成功失败都标记完成 // 无论成功失败都标记完成
taskStatusHolder.finishTask(asyncKey); taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("文件自动备份完成", "backups");
} }
} }
/********************************** /**********************************
* 用途说明: 文件自动备份通过节点和任务 * 用途说明: 文件自动备份通过节点和任务
* 参数说明 taskId 节点ID * 参数说明 taskId 节点ID

View File

@ -5,7 +5,9 @@ import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.exception.file.InvalidStorageSourceException;
import com.yfd.platform.modules.config.model.request.FileListRequest; import com.yfd.platform.modules.config.model.request.FileListRequest;
@ -449,24 +451,51 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
//根据ID 查询当前数据 //根据ID 查询当前数据
TsNodes tsNodes = tsNodesMapper.selectById(id); TsNodes tsNodes = tsNodesMapper.selectById(id);
//删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构 //删除之前 先拼路径 然后删除本地和minio的文件夹 最后删除表结构
//删除当前节点的 文件 //查询所有的子节点
List<TsNodes> tsNodesList = selectChildrentsNodes(tsNodes.getNodeId(), tsNodes.getTaskId());
// 提取所有节点的 ID
List<String> nodeIds = tsNodesList.stream()
.map(TsNodes::getNodeId) // 获取每个节点的 ID
.collect(Collectors.toList());
//查询所有的文件
QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>(); QueryWrapper<TsFiles> queryWrapper1 = new QueryWrapper<>();
queryWrapper1.eq("node_id", tsNodes.getNodeId()); queryWrapper1.in("node_id", nodeIds);
queryWrapper1.eq("task_id", tsNodes.getTaskId()); queryWrapper1.eq("task_id", tsNodes.getTaskId());
List<TsFiles> tsFiles = tsFilesMapper.selectList(queryWrapper1); List<TsFiles> tsFiles = tsFilesMapper.selectList(queryWrapper1);
//获取所有文件的ID集合
List<String> dataset = new ArrayList<>(); List<String> dataset = new ArrayList<>();
if (tsFiles != null && !tsFiles.isEmpty()) { if (tsFiles != null && !tsFiles.isEmpty()) {
dataset = tsFiles.stream() dataset.addAll(tsFiles.stream()
.map(TsFiles::getId) // 假设 TsFiles 类中有 getId() 方法 .map(TsFiles::getId)
.collect(Collectors.toList()); .collect(Collectors.toList()));
} }
//批量删除TsFiles表数据 if (dataset.size() <= 0) {
if (dataset.size() > 0) { return true;
tsFilesService.deleteTsFilesByIds(dataset, "local");
} }
// // 递归删除子节点 //批量修改
LambdaUpdateWrapper<TsFiles> updateWrapper1 = new LambdaUpdateWrapper<>();
updateWrapper1.in(TsFiles::getId,dataset).isNotNull(TsFiles::getBackupPath).ne(TsFiles::getBackupPath,"").set(TsFiles::getWorkPath, "");
tsFilesMapper.update(null, updateWrapper1);
//批量删除
LambdaQueryWrapper<TsFiles> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.in(TsFiles::getId,dataset).isNull(TsFiles::getBackupPath).eq(TsFiles::getBackupPath,"").isNull(TsFiles::getWorkPath).eq(TsFiles::getWorkPath,"");
tsFilesMapper.delete(deleteWrapper);
// //批量修改TsFiles表结构
// if (dataset.size() > 0) {
// QueryWrapper<TsFiles> updateWrapper = new QueryWrapper<>();
// updateWrapper.in("id", dataset);
// // 创建 TsFiles 实体对象设置要更新的字段
// TsFiles tsFiles1 = new TsFiles();
// tsFiles1.setWorkPath(""); // work_path 更新为 ""
// tsFilesMapper.update(tsFiles1, updateWrapper);
// LOGGER.info("tsFiles一共删除 {}跳", dataset.size());
// }
//
//// // 递归删除子节点
// deleteChildren(tsNodes.getNodeId(), tsNodes.getTaskId()); // deleteChildren(tsNodes.getNodeId(), tsNodes.getTaskId());
@ -520,6 +549,29 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
} }
} }
private List<TsNodes> selectChildrentsNodes(String parentId, String taskId) {
List<TsNodes> nodesList = new ArrayList<>();
TsNodes tsNodes = tsNodesMapper.selectById(parentId);
// 查询当前节点的所有子节点
QueryWrapper<TsNodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id", parentId); // parent_id = #{parentId}
queryWrapper.eq("task_id", taskId); // parent_id = #{parentId}
List<TsNodes> children = tsNodesMapper.selectList(queryWrapper);
// 将子节点添加到 nodesList
nodesList.addAll(children);
nodesList.add(tsNodes);
// 递归删除每个子节点
for (TsNodes child : children) {
// 递归查询子节点的子节点
List<TsNodes> childNodes = selectChildrentsNodes(child.getNodeId(), taskId);
// 将子节点的所有子节点添加到 nodesList
nodesList.addAll(childNodes);
}
return nodesList;
}
/** /**
* 递归删除子节点 * 递归删除子节点
* *
@ -646,6 +698,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
String asyncKey = taskStatusHolder.testDatascanKey(id); String asyncKey = taskStatusHolder.testDatascanKey(id);
// 无论成功失败都标记完成 // 无论成功失败都标记完成
taskStatusHolder.finishTask(asyncKey); taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("试验数据扫描接口完成", "taskId_" + id);
} }
} }
@ -653,23 +706,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
//查询试验任务信息 //查询试验任务信息
TsTask tsTask = tsTaskMapper.selectById(id); TsTask tsTask = tsTaskMapper.selectById(id);
//文件的第一层是节点 下面的层级是文件夹 //文件的第一层是节点 下面的层级是文件夹
//获取文件列表 //获取文件列表
String absolutePath = "/" + tsTask.getTaskName() + "/"; String absolutePath = "/" + tsTask.getTaskName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath); FileListRequest fileListRequest = buildFileRequest(absolutePath);
@ -687,7 +724,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
if (fileItemList.size() == 0) { if (fileItemList.size() == 0) {
throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。"); throw new Exception("该试验任务管理项目目录不存在或没有项目文档,请先建立项目目录和文档。");
} }
firstLayerData(fileItemList, id); firstLayerData(fileItemList, id);
return "扫描完成"; return "扫描完成";
} }
@ -749,7 +786,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//获取文件列表 这个地方path+name //获取文件列表 这个地方path+name
File projectDir = new File(storageSourceConfig.getValue()+path+nodeName); File projectDir = new File(storageSourceConfig.getValue() + path + nodeName);
// 获取所有子目录 // 获取所有子目录
List<File> allSubDirs = new ArrayList<>(); List<File> allSubDirs = new ArrayList<>();
@ -855,7 +892,7 @@ public class TsNodesServiceImpl extends ServiceImpl<TsNodesMapper, TsNodes> impl
// 记录开始时间 // 记录开始时间
long startTimeFiles = System.currentTimeMillis(); long startTimeFiles = System.currentTimeMillis();
// 执行更新操作 taskId, String nodeId // 执行更新操作 taskId, String nodeId
int affectedLevelFilesRows = tsFilesMapper.updateParentIdByPathHierarchy(taskId,nodeId); int affectedLevelFilesRows = tsFilesMapper.updateParentIdByPathHierarchy(taskId, nodeId);
// 记录结束时间 // 记录结束时间
long endTimeFiles = System.currentTimeMillis(); long endTimeFiles = System.currentTimeMillis();
// 计算耗时 // 计算耗时

View File

@ -3,8 +3,11 @@ package com.yfd.platform.modules.specialDocument.controller;
import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.yfd.platform.annotation.Log; import com.yfd.platform.annotation.Log;
import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.yfd.platform.modules.specialDocument.service.INodesService; import com.yfd.platform.modules.specialDocument.service.INodesService;
@ -99,11 +102,11 @@ public class NodesController {
@PostMapping("/deleteNodesById") @PostMapping("/deleteNodesById")
@ApiOperation("根据ID删除专项文档节点") @ApiOperation("根据ID删除专项文档节点")
@PreAuthorize("@el.check('del:nodes')") @PreAuthorize("@el.check('del:nodes')")
public ResponseResult deleteNodesById(@RequestParam String id, String path) { public ResponseResult deleteNodesById(@RequestParam String id, String path) {
if (StrUtil.isBlank(id)) { if (StrUtil.isBlank(id)) {
return ResponseResult.error("参数为空"); return ResponseResult.error("参数为空");
} }
boolean isOk = nodesService.deleteNodesById(id,path); boolean isOk = nodesService.deleteNodesById(id, path);
if (isOk) { if (isOk) {
return ResponseResult.success(); return ResponseResult.success();
} else { } else {
@ -144,60 +147,66 @@ public class NodesController {
} }
} }
/********************************** /**********************************
* 用途说明: 获取异步信息 * 用途说明: 获取异步信息
* 参数说明 id 所属项目ID * 参数说明 id 所属项目ID
* 参数说明 type 要查询的信息类型 0扫描 1上传扫描 * 参数说明 type 要查询的信息类型 0扫描 1上传扫描
* 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败 * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
* 没有 1
* 0
***********************************/ ***********************************/
@Log(module = "获取异步信息", value = "获取异步信息!") @Log(module = "获取异步信息", value = "获取异步信息!")
@PostMapping("/obtainInformationAsync") @PostMapping("/obtainInformationAsync")
@ApiOperation("获取异步信息") @ApiOperation("获取异步信息")
public ResponseResult obtainInformationAsync(String id, String type) throws Exception { public ResponseResult obtainInformationAsync(String id) throws Exception {
if (StrUtil.isEmpty(id)) { if (StrUtil.isEmpty(id)) {
return ResponseResult.error("id为空"); return ResponseResult.error("id为空");
} }
if (StrUtil.isEmpty(type)) { JSONObject jsonObject1 = new JSONObject();
return ResponseResult.error("类型为空"); // 生成唯一Key
String asyncKey = taskStatusHolder.specialGenerateKey(id);
// 检查任务是否已存在
String existingStatus = taskStatusHolder.getStatus(asyncKey);
if ("TASK_NOT_FOUND".equals(existingStatus)) {
jsonObject1.putOpt("status", "1");
jsonObject1.putOpt("name", "扫描");
return ResponseResult.successData(jsonObject1);
} }
if ("0".equals(type)) { if ("IN_PROGRESS".equals(existingStatus)) {
jsonObject1.putOpt("status", "0");
jsonObject1.putOpt("name", "扫描");
// 生成唯一Key return ResponseResult.successData(jsonObject1);
String asyncKey = taskStatusHolder.specialGenerateKey(id); } else if ("COMPLETED".equals(existingStatus)) {
jsonObject1.putOpt("status", "1");
// 检查任务是否已存在 jsonObject1.putOpt("name", "扫描");
String existingStatus = taskStatusHolder.getStatus(asyncKey); return ResponseResult.successData(jsonObject1);
if ("TASK_NOT_FOUND".equals(existingStatus)) {
return ResponseResult.success("1");
}
if ("IN_PROGRESS".equals(existingStatus)) {
return ResponseResult.success("0");
} else if ("COMPLETED".equals(existingStatus)) {
return ResponseResult.success("专项文档扫描任务已完成!");
}
} else {
// 生成唯一Key
String asyncKey = taskStatusHolder.documentUploadKey(id);
// 检查任务是否已存在
String existingStatus = taskStatusHolder.getStatus(asyncKey);
if ("TASK_NOT_FOUND".equals(existingStatus)) {
return ResponseResult.success("1");
}
if ("IN_PROGRESS".equals(existingStatus)) {
return ResponseResult.success("0");
} else if ("COMPLETED".equals(existingStatus)) {
return ResponseResult.success("专项文档扫描任务已完成!");
}
} }
// 上传生成唯一Key
String asyncKeySc = taskStatusHolder.documentUploadKey(id);
// 检查任务是否已存在
String existingStatusSc = taskStatusHolder.getStatus(asyncKeySc);
if ("TASK_NOT_FOUND".equals(existingStatusSc)) {
jsonObject1.putOpt("status", "1");
jsonObject1.putOpt("name", "上传");
return ResponseResult.successData(jsonObject1);
}
if ("IN_PROGRESS".equals(existingStatusSc)) {
jsonObject1.putOpt("status", "0");
jsonObject1.putOpt("name", "上传");
return ResponseResult.successData(jsonObject1);
} else if ("COMPLETED".equals(existingStatusSc)) {
jsonObject1.putOpt("status", "1");
jsonObject1.putOpt("name", "上传");
return ResponseResult.successData(jsonObject1);
}
return null; return null;
} }
/********************************** /**********************************
* 用途说明: 专项文档管理文档上传接口 * 用途说明: 专项文档管理文档上传接口
* 参数说明 id 所属项目ID * 参数说明 id 所属项目ID
@ -222,43 +231,19 @@ public class NodesController {
// 检查任务是否已存在 // 检查任务是否已存在
String existingStatus = taskStatusHolder.getStatus(asyncKey); String existingStatus = taskStatusHolder.getStatus(asyncKey);
if ("IN_PROGRESS".equals(existingStatus)) { if ("IN_PROGRESS".equals(existingStatus)) {
return ResponseResult.success("专项文档扫描任务正在处理中!"); return ResponseResult.success("专项文档上传任务正在处理中!");
} else if ("COMPLETED".equals(existingStatus)) { } else if ("COMPLETED".equals(existingStatus)) {
return ResponseResult.success("专项文档扫描任务已完成!"); return ResponseResult.success("专项文档上传任务已完成!");
} }
// 原子性启动新任务 // 原子性启动新任务
if (taskStatusHolder.startTaskIfAbsent(asyncKey)) { if (taskStatusHolder.startTaskIfAbsent(asyncKey)) {
// 直接异步执行并推送结果 // 直接异步执行并推送结果
nodesService.documentUploadByIdAsync(id, fileName); nodesService.documentUploadByIdAsync(id, fileName);
return ResponseResult.success("专项文档扫描任务开始处理!"); return ResponseResult.success("专项文档上传任务开始处理!");
} else { } else {
return ResponseResult.success("专项文档扫描任务已由其他请求启动"); return ResponseResult.success("专项文档上传任务已由其他请求启动");
} }
} }
// /**********************************
// * 用途说明: 批量删除专项文档节点
// * 参数说明 ids 专项文档节点id数组
// * 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败
// ***********************************/
// @Log(module = "专项文档管理", value = "批量删除专项文档节点",type = "1")
// @PostMapping("/deleteNodesByIds")
// @ApiOperation("批量删除专项文档节点")
// @PreAuthorize("@el.check('del:nodes')")
// public ResponseResult deleteSdprojectByIds(@RequestParam String ids) {
// if (StrUtil.isBlank(ids)) {
// return ResponseResult.error("参数为空");
// }
// String[] splitIds = ids.split(",");
// // 数组转集合
// List<String> dataset = Arrays.asList(splitIds);
// boolean isOk = nodesService.removeByIds(dataset);
// if (isOk) {
// return ResponseResult.success();
// } else {
// return ResponseResult.error();
// }
// }
} }

View File

@ -4,6 +4,7 @@ import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.specialDocument.domain.Nodes;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -61,5 +62,5 @@ public interface INodesService extends IService<Nodes> {
* 参数说明 id 所属项目ID * 参数说明 id 所属项目ID
* 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败 * 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
***********************************/ ***********************************/
void documentUploadByIdAsync(String id,String fileName); void documentUploadByIdAsync(String id,String fileName) throws IOException;
} }

View File

@ -46,6 +46,7 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -208,28 +209,32 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
String redisKeyff = "sdfiles_" + projectId + "_" + nodeId + "_page_" + currentPage; String redisKeyff = "sdfiles_" + projectId + "_" + nodeId + "_page_" + currentPage;
Object data = redisTemplate.opsForValue().get(redisKeyff); Object data = redisTemplate.opsForValue().get(redisKeyff);
try {
if (data instanceof IPage<?>) {
@SuppressWarnings("unchecked")
IPage<Files> page = (IPage<Files>) data;
// if (data != null) { // 类型校验
// ObjectMapper mapper = new ObjectMapper(); if (isValidPage(page)) {
// // 明确指定目标类型为 Page<Files> return page;
// return mapper.convertValue(data, new TypeReference<Page<Files>>() {}); }
// }
if (data instanceof IPage<?>) {
// 由于启用了类型信息可以直接强制转换
@SuppressWarnings("unchecked")
IPage<Files> page = (IPage<Files>) data;
// 检查 records 是否已正确反序列化
if (page.getRecords() != null && !page.getRecords().isEmpty()
&& page.getRecords().get(0) instanceof Files) {
return page;
} else {
// 处理可能的反序列化异常
throw new IllegalStateException("反序列化失败records 类型不正确");
} }
} catch (Exception e) {
// 记录异常日志关键
LOGGER.error("反序列化失败,删除缓存: {}", redisKeyff, e);
// 异步删除缓存避免阻塞主流程
CompletableFuture.runAsync(() -> redisTemplate.delete(redisKeyff));
} }
return null;
return null; // 或返回空分页对象 new Page<>(0)
} }
private boolean isValidPage(IPage<Files> page) {
return page.getRecords() != null
&& !page.getRecords().isEmpty()
&& page.getRecords().get(0) instanceof Files;
}
/*********************************** /***********************************
* 用途说明新增专项文档管理-文档内容 * 用途说明新增专项文档管理-文档内容

View File

@ -8,6 +8,7 @@ import com.amazonaws.util.IOUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.TaskStatusHolder;
import com.yfd.platform.component.WebSocketServer;
import com.yfd.platform.config.ResponseResult; import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.exception.file.InvalidStorageSourceException; import com.yfd.platform.exception.file.InvalidStorageSourceException;
import com.yfd.platform.modules.config.model.request.FileListRequest; import com.yfd.platform.modules.config.model.request.FileListRequest;
@ -544,19 +545,26 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
if (nodes == null) { if (nodes == null) {
return false; // 节点不存在 return false; // 节点不存在
} }
//递归获取当前节点和它下面的所有节点
List<Nodes> nodesList = selectChildrenNodes(id, nodes.getProjectId());
// 提取所有节点的 ID
List<String> nodeIds = nodesList.stream()
.map(Nodes::getId) // 获取每个节点的 ID
.collect(Collectors.toList());
// 构建节点路径 // 执行批量删除节点操作
List<String> pathNodes = new ArrayList<>(); if (!nodeIds.isEmpty()) {
Nodes nodesData = nodesMapper.selectById(nodes.getParentId()); QueryWrapper<Nodes> deleteWrapper = new QueryWrapper<>();
while (nodesData != null) { deleteWrapper.in("id", nodeIds); // 根据节点 ID 批量删除
pathNodes.add(nodesData.getNodeName()); nodesMapper.delete(deleteWrapper);
if ("00".equals(nodesData.getParentId())) { }
break; //执行批量删除文件操作
} if (!nodeIds.isEmpty()) {
nodesData = nodesMapper.selectById(nodesData.getParentId()); QueryWrapper<Files> deleteWrapper = new QueryWrapper<>();
deleteWrapper.in("node_id", nodeIds); // 根据节点 ID 批量删除
deleteWrapper.eq("project_id",nodes.getProjectId());
filesMapper.delete(deleteWrapper);
} }
Collections.reverse(pathNodes);
// 删除 sdlocal 中的文件夹 // 删除 sdlocal 中的文件夹
List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>(); List<BatchDeleteRequest.DeleteItem> deleteItemList = new ArrayList<>();
@ -594,19 +602,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
if (deleteSuccessCount >= 1) { if (deleteSuccessCount >= 1) {
// 递归删除子节点 value = true;
deleteChildren(nodes.getId(), nodes.getProjectId());
// 删除当前节点的文件
filesMapper.delete(
new QueryWrapper<Files>()
.eq("node_id", nodes.getId())
.eq("project_id", nodes.getProjectId())
);
// 删除当前节点
int deleteCount = nodesMapper.deleteById(id);
value = deleteCount > 0;
} else { } else {
value = false; value = false;
} }
@ -614,6 +610,32 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
return value; return value;
} }
/**
* 递归删除子节点
* parentId 父节点ID
* projectId 项目ID
*/
private List<Nodes> selectChildrenNodes(String parentId, String projectId) {
List<Nodes> nodesList = new ArrayList<>();
Nodes nodes = nodesMapper.selectById(parentId);
// 查询当前节点的所有子节点
QueryWrapper<Nodes> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("parent_id", parentId);
queryWrapper.eq("project_id", projectId);
List<Nodes> children = nodesMapper.selectList(queryWrapper);
// 将子节点添加到 nodesList
nodesList.addAll(children);
nodesList.add(nodes);
// 递归删除每个子节点
for (Nodes child : children) {
// 递归查询子节点的子节点
List<Nodes> childNodes = selectChildrenNodes(child.getId(), projectId);
// 将子节点的所有子节点添加到 nodesList
nodesList.addAll(childNodes);
}
return nodesList;
}
/** /**
* 递归删除子节点 * 递归删除子节点
@ -658,6 +680,8 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
String asyncKey = taskStatusHolder.specialGenerateKey(id); String asyncKey = taskStatusHolder.specialGenerateKey(id);
// 无论成功失败都标记完成 // 无论成功失败都标记完成
taskStatusHolder.finishTask(asyncKey); taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("专项文档扫描任务处理完成!", "projectId_"+id);
} }
} }
@ -1115,7 +1139,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
@Override @Override
@Async("asyncExecutor") @Async("asyncExecutor")
public void documentUploadByIdAsync(String id, String fileName) { public void documentUploadByIdAsync(String id, String fileName) throws IOException {
try { try {
// 查询本地文件路径根目录 E:\yun // 查询本地文件路径根目录 E:\yun
@ -1176,9 +1200,10 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
String asyncKey = taskStatusHolder.documentUploadKey(id); String asyncKey = taskStatusHolder.documentUploadKey(id);
// 无论成功失败都标记完成 // 无论成功失败都标记完成
taskStatusHolder.finishTask(asyncKey); taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("专项文档上传任务处理完成!", "projectId_"+id);
} }
} }
//todo 首先得上传到一个临时目录 然后找到这个目录我去解压缩到当前文件夹 解压缩以后 然后开始循环 我通过第一层去查询 如果没有就新增 如果有就循环 看看需不需要覆盖
public static void deleteDirectory(File directory) throws Exception { public static void deleteDirectory(File directory) throws Exception {
@ -1281,11 +1306,8 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
//将源目录文件 复制到 目标目录文件 todo这个地方是覆盖 //将源目录文件 复制到 目标目录文件 todo这个地方是覆盖
copyWithOverride(sourcePath, targetPath); copyWithOverride(sourcePath, targetPath);
} }
} }
} }
} else { } else {
//如果为空对象不存在 则直接拷贝 //如果为空对象不存在 则直接拷贝
String sourcePath = value + sourceFolderPath; String sourcePath = value + sourceFolderPath;
@ -1350,31 +1372,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); boolean flag = fileService.newFolder(newFolderRequest.getPath(), newFolderRequest.getName());
} }
} }
specialScanById(project.getId());
//获取文件列表
String absolutePath = "/" + project.getProjectName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath);
String storageKey = fileListRequest.getStorageKey();
Integer storageId = storageSourceService.findIdByKey(storageKey);
if (storageId == null) {
throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey);
}
// 处理请求参数默认值
fileListRequest.handleDefaultValue();
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
// //获取数据库父节点为0的文件夹数据 通过所属项目ID和父节点查询
// List<Nodes> nodesList = nodesMapper.selectList(new LambdaQueryWrapper<Nodes>().eq(Nodes::getParentId, "00").eq(Nodes::getProjectId, project.getId()));
//
// // 步骤 1提取现有的 nodeName
// Set<String> existingNodeNames = nodesList.stream().map(Nodes::getNodeName).collect(Collectors.toSet());
//
// // 步骤 2筛选新增数据 找到需要新增到数据库的文件夹
// List<FileItemResult> fileItemNewList = fileItemList.stream().filter(fileItem -> !existingNodeNames.contains(fileItem.getName())).collect(Collectors.toList());
firstLayerData(fileItemList, project.getId());
return "扫描完成"; return "扫描完成";
} }