From aed54f863fb0dcc8688eb6f83de9322a8d4abcad Mon Sep 17 00:00:00 2001 From: lilin Date: Tue, 27 May 2025 17:31:58 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../platform/component/TaskStatusHolder.java | 4 - .../controller/TsFilesController.java | 6 +- .../controller/TsNodesController.java | 25 ++ .../service/ITsFilesService.java | 2 +- .../service/impl/TsFilesServiceImpl.java | 59 +++-- .../service/impl/TsNodesServiceImpl.java | 90 +------ .../controller/FilesController.java | 12 +- .../controller/NodesController.java | 23 ++ .../service/IFilesService.java | 4 +- .../service/impl/FilesServiceImpl.java | 237 +++++++++++++++++- 10 files changed, 338 insertions(+), 124 deletions(-) diff --git a/java/src/main/java/com/yfd/platform/component/TaskStatusHolder.java b/java/src/main/java/com/yfd/platform/component/TaskStatusHolder.java index a063616..a78bf19 100644 --- a/java/src/main/java/com/yfd/platform/component/TaskStatusHolder.java +++ b/java/src/main/java/com/yfd/platform/component/TaskStatusHolder.java @@ -35,18 +35,14 @@ public class TaskStatusHolder { - - // 原子性检查并标记任务开始 public boolean startTaskIfAbsent(String key) { return taskStatusMap.putIfAbsent(key, "IN_PROGRESS") == null; } - // 标记任务结束 public void finishTask(String key) { taskStatusMap.remove(key); } - // 获取任务状态 public String getStatus(String key) { return taskStatusMap.getOrDefault(key, "TASK_NOT_FOUND"); 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 0232dbc..de0dd04 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 @@ -619,14 +619,14 @@ public class TsFilesController { @Log(module = "实验数据管理", value = "文件自动备份!") @PostMapping("/automaticFileBackupByIds") @ApiOperation("自动备份本地文件到备份空间通过ID") - public ResponseResult automaticFileBackupByIds(String id) throws IOException { + public ResponseResult automaticFileBackupByIds(String id,String taskId, String nodeId) throws IOException { if (StrUtil.isEmpty(id)) { return ResponseResult.error("参数为空"); } List dataset = StrUtil.split(id, ","); // 生成唯一Key - String asyncKey = taskStatusHolder.generateKeybyId(dataset); + String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); // 检查任务是否已存在 String existingStatus = taskStatusHolder.getStatus(asyncKey); @@ -638,7 +638,7 @@ public class TsFilesController { // 原子性启动新任务 if (taskStatusHolder.startTaskIfAbsent(asyncKey)) { // 直接异步执行并推送结果 - tsFilesService.automaticFileBackupAsyncByIds(dataset); + tsFilesService.automaticFileBackupAsyncByIds(dataset,taskId,nodeId); return ResponseResult.success("任务开始处理!"); } else { return ResponseResult.success("任务已由其他请求启动"); diff --git a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java index 2b26c4a..c3396be 100644 --- a/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java +++ b/java/src/main/java/com/yfd/platform/modules/experimentalData/controller/TsNodesController.java @@ -4,6 +4,7 @@ package com.yfd.platform.modules.experimentalData.controller; import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.annotation.Log; import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.config.ResponseResult; @@ -183,4 +184,28 @@ public class TsNodesController { return null; } + + + /********************************** + * 用途说明: 查询可不可以初始化试验任务扫描 + * 参数说明 taskId 试验任务ID + * 返回值说明: com.yfd.platform.config.ResponseResult + ***********************************/ + @Log(module = "查询可不可以初始化试验任务扫描", value = "查询可不可以初始化试验任务扫描!") + @PostMapping("/selectTsNodesByTskeId") + @ApiOperation("查询可不可以初始化试验任务扫描") + @PreAuthorize("@el.check('del:tsnodes')") + public ResponseResult selectTsNodesByTskeId( String taskId) { + if (StrUtil.isBlank(taskId)) { + return ResponseResult.error("参数为空"); + } + List tsNodesList = tsNodesService.list(new QueryWrapper().eq("task_id", taskId)); + //如果节点不为空 就不能初始化了 + if (tsNodesList.size()>0) { + return ResponseResult.success("该项目已经初始化完成,局部更新请选择节点上传文件!"); + } else { + return ResponseResult.success("可以初始化!"); + } + } + } 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 95d8b66..0a7023a 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 @@ -247,7 +247,7 @@ public interface ITsFilesService extends IService { Object compareMd5List(List dataset, String nodeId, String taskId); - void automaticFileBackupAsyncByIds(List dataset) throws IOException; + void automaticFileBackupAsyncByIds(List dataset,String taskId, String nodeId) throws IOException; IPage getCachedTsFilesPage(String taskId, String nodeId, int currentPage,String id); } 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 00880b8..fcefb6c 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 @@ -292,27 +292,50 @@ public class TsFilesServiceImpl extends ServiceImpl impl @Override public IPage getCachedTsFilesPage(String taskId, String nodeId, int currentPage, String id) { String redisKey = "tsfiles_" + taskId + "_" + nodeId + "_parentId" + id + "_page_" + currentPage; - - Object data = redisTemplate.opsForValue().get(redisKey); + try { + if (data instanceof IPage) { + @SuppressWarnings("unchecked") + IPage page = (IPage) data; - if (data instanceof IPage) { - // 由于启用了类型信息,可以直接强制转换 - @SuppressWarnings("unchecked") - IPage page = (IPage) data; - // 检查 records 是否已正确反序列化 - if (page.getRecords() != null && !page.getRecords().isEmpty() - && page.getRecords().get(0) instanceof TsFiles) { - return page; - } else { - // 处理可能的反序列化异常 - throw new IllegalStateException("反序列化失败,records 类型不正确"); + // 类型校验 + if (isValidPage(page)) { + return page; + } } + } catch (Exception e) { + // 记录异常日志(关键!) + LOGGER.error("反序列化失败,删除缓存: {}", redisKey, e); + + // 异步删除缓存,避免阻塞主流程 + CompletableFuture.runAsync(() -> redisTemplate.delete(redisKey)); } - return null; + + return null; // 或返回空分页对象 new Page<>(0) + +// if (data instanceof IPage) { +// // 由于启用了类型信息,可以直接强制转换 +// @SuppressWarnings("unchecked") +// IPage page = (IPage) data; +// // 检查 records 是否已正确反序列化 +// if (page.getRecords() != null && !page.getRecords().isEmpty() +// && page.getRecords().get(0) instanceof TsFiles) { +// return page; +// } else { +// // 处理可能的反序列化异常 +// throw new IllegalStateException("反序列化失败,records 类型不正确"); +// } +// } +// return null; } + private boolean isValidPage(IPage page) { + return page.getRecords() != null + && !page.getRecords().isEmpty() + && page.getRecords().get(0) instanceof TsFiles; + } + public boolean hasValidExtension(String name, List sysDictionaryItems) { // 如果传入的文件名为空,返回 false if (name == null) { @@ -3375,22 +3398,22 @@ public class TsFilesServiceImpl extends ServiceImpl impl String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); // 无论成功失败都标记完成 taskStatusHolder.finishTask(asyncKey); - WebSocketServer.sendMessageTo("文件自动备份完成", "backups"); + WebSocketServer.sendMessageTo("文件自动备份完成", "taskId_"+taskId+"_"+"nodeId_"+nodeId); } } @Override @Async("asyncExecutor") - public void automaticFileBackupAsyncByIds(List dataset) throws IOException { + public void automaticFileBackupAsyncByIds(List dataset,String taskId,String nodeId) throws IOException { try { // 执行实际备份逻辑 this.automaticFileBackupByIds(dataset); } finally { // 生成唯一Key - String asyncKey = taskStatusHolder.generateKeybyId(dataset); + String asyncKey = taskStatusHolder.generateKey(taskId, nodeId); // 无论成功失败都标记完成 taskStatusHolder.finishTask(asyncKey); - WebSocketServer.sendMessageTo("文件自动备份完成", "backups"); + WebSocketServer.sendMessageTo("文件自动备份完成", "taskId_"+taskId+"_"+"nodeId_"+nodeId); } } 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 2e7346c..37aa366 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 @@ -477,11 +477,11 @@ public class TsNodesServiceImpl extends ServiceImpl impl //批量修改 LambdaUpdateWrapper updateWrapper1 = new LambdaUpdateWrapper<>(); - updateWrapper1.in(TsFiles::getId,dataset).isNotNull(TsFiles::getBackupPath).ne(TsFiles::getBackupPath,"").set(TsFiles::getWorkPath, ""); + updateWrapper1.in(TsFiles::getId, dataset).isNotNull(TsFiles::getBackupPath).ne(TsFiles::getBackupPath, "").set(TsFiles::getWorkPath, ""); tsFilesMapper.update(null, updateWrapper1); //批量删除 LambdaQueryWrapper deleteWrapper = new LambdaQueryWrapper<>(); - deleteWrapper.in(TsFiles::getId,dataset).isNull(TsFiles::getBackupPath).eq(TsFiles::getBackupPath,"").isNull(TsFiles::getWorkPath).eq(TsFiles::getWorkPath,""); + deleteWrapper.in(TsFiles::getId, dataset).isNull(TsFiles::getBackupPath).eq(TsFiles::getBackupPath, "").isNull(TsFiles::getWorkPath).eq(TsFiles::getWorkPath, ""); tsFilesMapper.delete(deleteWrapper); // //批量修改TsFiles表结构 @@ -777,17 +777,13 @@ public class TsNodesServiceImpl extends ServiceImpl impl LocalDateTime now = LocalDateTime.now(); // 转换为 Timestamp Timestamp currentTime = Timestamp.valueOf(now); - - // 查询本地文件路径根目录(如 E:\yun) QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name", "filePath"); queryWrapper.eq("type", "local"); StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); - //获取文件列表 这个地方path+name File projectDir = new File(storageSourceConfig.getValue() + path + nodeName); - // 获取所有子目录 List allSubDirs = new ArrayList<>(); getAllSubDirectories(projectDir, allSubDirs); @@ -899,88 +895,6 @@ public class TsNodesServiceImpl extends ServiceImpl impl long costTimeFiles = endTimeFiles - startTimeFiles; // 打印日志 LOGGER.info("文件表中的节点ID更新完成,影响 {} 行,总耗时 {} 毫秒", affectedLevelFilesRows, costTimeFiles); - - -// //获取文件列表 -// String absolutePath =path + "/" + nodeName + "/"; -// //获取当前登录用户 上传人是当前登录人 -// UsernamePasswordAuthenticationToken authentication = -// (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); -// LoginUser loginuser = null; -// if (authentication != null) { -// loginuser = (LoginUser) authentication.getPrincipal(); -// } -// //登录人 -// String uploader = null; -// if (loginuser != null) { -// uploader = loginuser.getUsername(); -// } -// // 设置当前时间 -// LocalDateTime now = LocalDateTime.now(); -// // 转换为 Timestamp -// Timestamp currentTime = Timestamp.valueOf(now); -// -// -// -// -// -// //获取文件列表 -// FileListRequest fileListRequest = buildFileRequest(absolutePath); -// String storageKey = fileListRequest.getStorageKey(); -// Integer storageId = storageSourceService.findIdByKey(storageKey); -// if (storageId == null) { -// throw new InvalidStorageSourceException("通过存储源 key 未找到存储源, key: " + storageKey); -// } -// // 处理请求参数默认值 -// fileListRequest.handleDefaultValue(); -// AbstractBaseFileService fileService = storageSourceContext.getByStorageId(storageId); -// //todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件,递归增加 -// List fileItemList = fileService.fileList(fileListRequest.getPath()); -// -// for (FileItemResult item : fileItemList) { -// //思路就是 如果是文件夹 就查询一下 没有就新增, 新的的时候递归往下走 -// if (item.getType() == FileTypeEnum.FOLDER) { -// //先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称 -// LambdaQueryWrapper queryWrapper1 = new LambdaQueryWrapper<>(); -// queryWrapper1.eq(TsFiles::getTaskId, taskId); -// queryWrapper1.eq(TsFiles::getNodeId, nodeId); -// queryWrapper1.eq(TsFiles::getParentId, parentId); -// queryWrapper1.eq(TsFiles::getFileName, item.getName()); -// queryWrapper1.eq(TsFiles::getWorkPath, item.getPath()); -// TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper1); -// //如果没有 新增 并且递归 -// if (tsFiles == null) { -// //保存文件 -// TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FOLDER", String.valueOf(item.getSize())); -// otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFilesData.getId()); -// -// } else { -// otherLevelsData(taskId, nodeId, item.getName(), item.getPath(), tsFiles.getId()); -// } -// } else { -// //todo 如果是文件 直接新增就可以了 不需要其他的操作 -// //先查询有没有 如果没有就新增 条件 节点ID 任务ID 上级ID 工作空间路径 文件名称 -// LambdaQueryWrapper queryWrapper2 = new LambdaQueryWrapper<>(); -// queryWrapper2.eq(TsFiles::getTaskId, taskId); -// queryWrapper2.eq(TsFiles::getNodeId, nodeId); -// queryWrapper2.eq(TsFiles::getParentId, parentId); -// queryWrapper2.eq(TsFiles::getFileName, item.getName()); -// queryWrapper2.eq(TsFiles::getWorkPath, item.getPath()); -// TsFiles tsFiles = tsFilesMapper.selectOne(queryWrapper2); -// if (tsFiles == null) { -// -// // 获取文件大小(字节) -// long fileSizeInBytes = item.getSize(); -// // 转换为 MB 并保留两位小数 -// double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0); -// String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数 -// -// //保存文件信息 -// TsFiles tsFilesData = savetsFiles(taskId, nodeId, item.getName(), item.getPath(), parentId, "FILE", fileSizeFormatted); -// LOGGER.info("保存文件信息:{}", item.getPath() + item.getName()); -// } -// } -// } } /** diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/FilesController.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/FilesController.java index 639b1fa..48248df 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/FilesController.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/FilesController.java @@ -71,6 +71,8 @@ public class FilesController { * 用途说明:新增专项文档管理-文档内容 * 参数说明 * Files 文档内容 + * sourcePath 源路径 + * targetPath 目标路径 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ @Log(module = "专项文档管理", value = "新增专项文档管理文档内容!") @@ -78,12 +80,18 @@ public class FilesController { @ApiOperation("新增专项文档管理文档内容") @ResponseBody @PreAuthorize("@el.check('add:files')") - public ResponseResult addFiles(@RequestBody Files files) { + public ResponseResult addFiles(@RequestBody Files files,String sourcePath,String targetPath) throws Exception { //对象不能为空 if (ObjUtil.isEmpty(files)) { return ResponseResult.error("参数为空"); } - return filesService.addFiles(files); + if (StrUtil.isEmpty(sourcePath)) { + return ResponseResult.error("源路径参数为空"); + } + if (StrUtil.isEmpty(targetPath)) { + return ResponseResult.error("目标路径参数为空"); + } + return filesService.addFiles(files,sourcePath,targetPath); } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java index 26aa56a..df721c2 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/controller/NodesController.java @@ -5,10 +5,12 @@ import cn.hutool.core.util.ObjUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.yfd.platform.annotation.Log; import com.yfd.platform.component.TaskStatusHolder; import com.yfd.platform.component.WebSocketServer; import com.yfd.platform.config.ResponseResult; +import com.yfd.platform.modules.experimentalData.domain.TsNodes; import com.yfd.platform.modules.specialDocument.domain.Nodes; import com.yfd.platform.modules.specialDocument.service.INodesService; import io.swagger.annotations.ApiOperation; @@ -246,4 +248,25 @@ public class NodesController { } + /********************************** + * 用途说明: 查询可不可以初始化专项文档扫描 + * 参数说明 projectId 所属项目ID + * 返回值说明: com.yfd.platform.config.ResponseResult + ***********************************/ + @Log(module = "查询可不可以初始化专项文档扫描", value = "查询可不可以初始化专项文档扫描!") + @PostMapping("/selectNodesByProjectId") + @ApiOperation("查询可不可以初始化专项文档扫描") + public ResponseResult selectNodesByProjectId( String projectId) { + if (StrUtil.isBlank(projectId)) { + return ResponseResult.error("参数为空"); + } + List nodesList = nodesService.list(new QueryWrapper().eq("project_id", projectId)); + //如果节点不为空 就不能初始化了 + if (nodesList.size()>0) { + return ResponseResult.success("该项目已经初始化完成,局部更新请选择节点上传文件!"); + } else { + return ResponseResult.success("可以初始化!"); + } + } + } diff --git a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IFilesService.java b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IFilesService.java index c149bc8..a0c37ff 100644 --- a/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IFilesService.java +++ b/java/src/main/java/com/yfd/platform/modules/specialDocument/service/IFilesService.java @@ -39,9 +39,11 @@ public interface IFilesService extends IService { * 用途说明:新增专项文档管理-文档内容 * 参数说明 * Files 文档内容 + * sourcePath 源路径 + * targetPath 目标路径 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ - ResponseResult addFiles(Files files); + ResponseResult addFiles(Files files,String sourcePath,String targetPath) throws Exception; /********************************** * 用途说明: 修改专项文档管理-文档内容 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 830fe24..e245420 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 @@ -20,6 +20,8 @@ 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.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.RenameFileRequest; @@ -30,6 +32,9 @@ import com.yfd.platform.modules.storage.service.base.AbstractBaseFileService; import com.yfd.platform.system.domain.LoginUser; import com.yfd.platform.utils.StringUtils; import io.netty.channel.ChannelInboundHandlerAdapter; +import org.apache.commons.codec.binary.Hex; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -41,8 +46,16 @@ import org.springframework.transaction.annotation.Transactional; import com.fasterxml.jackson.core.type.TypeReference; import javax.annotation.Resource; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.sql.Timestamp; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -82,6 +95,9 @@ public class FilesServiceImpl extends ServiceImpl implements @Autowired private RedisTemplate redisTemplate; + @Resource + private StorageSourceConfigMapper storageSourceConfigMapper; + /********************************** * 用途说明: 分页查询专项文档管理-文档内容 @@ -240,12 +256,33 @@ public class FilesServiceImpl extends ServiceImpl implements * 用途说明:新增专项文档管理-文档内容 * 参数说明 * Files 文档内容 + * sourcePath 源路径 + * targetPath 目标路径 * 返回值说明: com.yfd.platform.config.ResponseResult 返回新增成功或者失败 ***********************************/ @Override - public ResponseResult addFiles(Files files) { + public ResponseResult addFiles(Files files,String sourcePath,String targetPath) throws Exception { Boolean value = false; + //新增之前从处理一下源路径的数据 + // 查询本地文件路径根目录(如 E:\yun) + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("name", "filePath"); + queryWrapper.eq("type", "sdlocal"); + StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); + //源路径 临时路径 + String sourceFilePath = storageSourceConfig.getValue()+sourcePath; + //目标路径 + String targetFilePath = storageSourceConfig.getValue()+targetPath; + + this.documentUploadById(files,sourceFilePath,targetFilePath,storageSourceConfig.getValue()); + + + + + + + List names = Arrays.asList(files.getFileName().split(",")); List sizes = Arrays.asList(files.getFileSize().split(",")); @@ -330,12 +367,198 @@ public class FilesServiceImpl extends ServiceImpl implements } } - /********************************** - * 用途说明: 修改专项文档管理-文档内容 - * 参数说明 - * Files 文档内容 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 - ***********************************/ + public String documentUploadById(Files files, String sourceFilePath, String targetFilePath, String value) throws Exception { + return null; + } +// List filesList = new ArrayList<>(); +// +// +// //源目录 +// File sourceDir = new File(sourceFilePath); +// //目标目录 +// File targetDir = new File(targetFilePath); +// +// if (!targetDir.exists()) { +// FileUtils.copyDirectory(sourceDir, targetDir); +// LOGGER.info("目标文件没有,全部更新过去"); +// return null; +// } +// +// FileListRequest sourcefileListRequest = buildFileRequest(sourceFilePath); +// FileListRequest targetfileListRequest = buildFileRequest(targetFilePath); +// +// //获取源文件列表 包含文件和文件夹 +// List sourceFileItemList = obtainFileItemResultData(sourcefileListRequest); +// //获取目标文件列表 包含文件和文件夹 +// List targetFileItemList = obtainFileItemResultData(targetfileListRequest); +// for (FileItemResult fileItemResult : sourceFileItemList) { +// +// String a1 = fileItemResult.getType() + fileItemResult.getName(); +// FileItemResult targetFileItem = targetFileItemList.stream() +// .filter(t -> (t.getType() + t.getName()).equals(a1)) +// .findFirst() // 获取第一个匹配项(返回 Optional) +// .orElse(null); +// +// // 检查对象存在 +// if (targetFileItem != null) { +// // 循环处理文件 对比文件的MD5值 +// if (fileItemResult.getType() == FileTypeEnum.FILE) { +// //源路径 +// String sourcePath = sourceFilePath + "/" + fileItemResult.getName(); +// +// //目标路径 +// String targetPath = targetFilePath + "/" + fileItemResult.getName(); +// +// //根据路径获取MD5值比较 如果相同则不进行操作 如果不同则重命名目标路径下的文件名称以及表结构 把现在源路径下的文件拷贝到目标路径下 新增数据库文件记录 +// // 计算源文件MD5 +// File sourceLocalFile = new File(sourcePath); +// String sourceLocalMD5 = calculateMD5Data(new FileInputStream(sourceLocalFile)); +// +// // 计算源文件MD5 +// File targetLocalFile = new File(targetPath); +// String targetLocalMD5 = calculateMD5Data(new FileInputStream(targetLocalFile)); +// +// // 如果MD5值不相同则进行操作 //如果一致 则直接复制源文件到目标文件 +// if (StringUtils.isNoneEmpty(sourceLocalMD5, targetLocalMD5) && !sourceLocalMD5.equals(targetLocalMD5)) { +// LOGGER.info("MD5值不一样的路径" + sourcePath); +// LOGGER.info("MD5值不一样的替换路径" + targetPath); +// //拷贝文件到目标目录 将原来的文件名更改以及将数据库表结构更改 +// //更改目标路径下的文件名称 +// String newTargetPath = renameFile(sourcePath); +// //将源目录文件 复制到 目标目录文件 +// copyToDirectoryFile(newTargetPath, value + targetFolderPath + "/"); +// +// } else { +// //将源目录文件 复制到 目标目录文件 todo这个地方是覆盖 +// copyWithOverride(sourcePath, targetPath); +// } +// } +// } else { +// //如果为空对象不存在 则直接拷贝 +// String sourcePath = value + sourceFilePath; +// //目标路径 就是源路径去掉/temporary的部分 +// String targetPath = sourcePath.replace("/" + "temporary", ""); +// //将源目录文件 复制到 目标目录文件 +// copyFolderWithOverride(sourcePath, targetPath); +// +// } +// } +// +// +// +// +// +// return null; +// } + + // 优化后的 MD5 计算方法(线程安全) + public String calculateMD5Data(InputStream inputStream) throws IOException, NoSuchAlgorithmException { + try (InputStream is = inputStream) { // 确保流关闭 + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = is.read(buffer)) != -1) { + md.update(buffer, 0, bytesRead); + } + return Hex.encodeHexString(md.digest()); + } + } + + public static String renameFile(String originalPath) throws IOException { + File originalFile = new File(originalPath); + if (!originalFile.exists()) { + throw new IOException("原文件不存在: " + originalPath); + } + + // 生成新文件名(保留扩展名) + String baseName = FilenameUtils.getBaseName(originalPath); + String extension = FilenameUtils.getExtension(originalPath); + String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")); + String newFileName = baseName + "_" + timestamp + "." + extension; + + Path originalFilePath = originalFile.toPath(); + Path newFilePath = Paths.get(originalFile.getParent(), newFileName); + + // 处理目标文件已存在的情况 + if (java.nio.file.Files.exists(newFilePath)) { + java.nio.file.Files.delete(newFilePath); // 删除已存在的目标文件 + } + + // 移动文件 + java.nio.file.Files.move(originalFilePath, newFilePath); + System.out.println("重命名成功: " + originalPath + " → " + newFilePath.toString()); + return newFilePath.toString(); + } + + private static void copyWithOverride(String source, String target) throws IOException { + File srcFile = new File(source); + File destFile = new File(target); + + // 强制覆盖已存在的文件 + FileUtils.copyFile(srcFile, destFile, true); + System.out.println("成功覆盖文件: " + target); + } + + private static void copyToDirectoryFile(String source, String targetDirectory) throws IOException { + File srcFile = new File(source); + File destDir = new File(targetDirectory); + + // 确保目标目录存在,如果不存在则创建 + if (!destDir.exists()) { + destDir.mkdirs(); + } + + // 创建目标文件对象(在目标目录下使用源文件名) + File destFile = new File(destDir, srcFile.getName()); + + // 复制文件到目标目录 + FileUtils.copyFile(srcFile, destFile); + System.out.println("成功复制文件到: " + destFile.getAbsolutePath()); + } + + private static void copyFolderWithOverride(String source, String target) throws IOException { + File srcDir = new File(source); + File destDir = new File(target); + + + // 递归拷贝文件夹及内容 + FileUtils.copyDirectory(srcDir, destDir); + System.out.println("成功覆盖文件夹: " + target); + } + + + private List obtainFileItemResultData(FileListRequest fileListRequest) throws Exception { + + 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()); + return fileItemList; + } + + private FileListRequest buildFileRequest(String path) { + FileListRequest fileListRequest = new FileListRequest(); + fileListRequest.setOrderBy("time"); + fileListRequest.setOrderDirection("desc"); + fileListRequest.setPassword(""); + fileListRequest.setPath(path); + fileListRequest.setStorageKey("sdlocal"); + + return fileListRequest; + } + + /********************************** + * 用途说明: 修改专项文档管理-文档内容 + * 参数说明 + * Files 文档内容 + * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 + ***********************************/ @Override @Transactional(rollbackFor = Exception.class)// 添加事务注解,遇到异常时回滚 public boolean updateFiles(Files files) {