提交代码压缩解压缩到指定目录代码提交
This commit is contained in:
		
							parent
							
								
									76b5faf473
								
							
						
					
					
						commit
						5dae66f63e
					
				| @ -521,28 +521,6 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|             if (count > 0) { | ||||
|                 return ResponseResult.error("文件夹名称已存在!"); | ||||
|             } | ||||
| 
 | ||||
| //        //判断文件夹是否创建 | ||||
| //        AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageKey("local"); | ||||
| //        boolean flag = fileService.isFolderCreated(File.separator + tsFiles.getNodeId()); | ||||
| //        //如果是false 说明没有创建  那就新建一个文件夹 | ||||
| //        if(!flag){ | ||||
| //            //本地创建文件夹 | ||||
| //            NewFolderRequest newFolderRequest = new NewFolderRequest(); | ||||
| //            newFolderRequest.setStorageKey("local"); | ||||
| //            newFolderRequest.setPath(tsFiles.getWorkPath()); | ||||
| //            newFolderRequest.setPassword(null); | ||||
| //            newFolderRequest.setName(tsFiles.getFileName()); | ||||
| // | ||||
| //            AbstractBaseFileService<?> fileServiceData = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); | ||||
| //            boolean flagData = fileServiceData.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); | ||||
| //            if(!flagData){ | ||||
| //                LOGGER.error("创建节点文件夹失败!"); | ||||
| //                return ResponseResult.error("新增文件夹失败!"); | ||||
| //            } | ||||
| //        } | ||||
| 
 | ||||
| 
 | ||||
|             //本地创建文件夹 | ||||
|             NewFolderRequest newFolderRequest = new NewFolderRequest(); | ||||
|             newFolderRequest.setStorageKey("local"); | ||||
| @ -1120,6 +1098,9 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|         QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>(); | ||||
|         queryWrapper.eq("name", "filePath"); | ||||
|         StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); | ||||
|         compressedPath = normalizePath(compressedPath); | ||||
| 
 | ||||
| 
 | ||||
|         String returnResult = ""; | ||||
|         // 创建要压缩的文件夹列表 | ||||
|         List<Path> sourceDirs = new ArrayList<>(); // 修复:使用 ArrayList | ||||
| @ -1147,6 +1128,16 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|             // 添加到压缩列表 | ||||
|             sourceDirs.add(path); // 修复:使用可变集合 | ||||
|         } | ||||
|         try { | ||||
|             String finalParentId = ensureFullPathExists(compressedPath, filesList.get(0).getNodeId(), filesList.get(0).getTaskId()); | ||||
|             parentId = finalParentId; | ||||
|             LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); | ||||
|         } catch (RuntimeException e) { | ||||
|             LOGGER.error("路径创建失败: {}", e.getMessage()); | ||||
|             returnResult = "路径创建失败!"; | ||||
|             return returnResult; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         // 规范化压缩包存放路径 | ||||
|         // 如果 compressedPath 是根目录,使用当前工作目录 | ||||
| @ -1163,7 +1154,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|         // 设置压缩级别,可以选择调整 | ||||
| //            zipOut.setLevel(ZipArchiveOutputStream.STORED); // 或者使用其他的压缩级别 | ||||
|         // 调用压缩方法 | ||||
|         Boolean value = compressToSameDirectory(sourceDirs, compressedFormat); | ||||
|         Boolean value = compressToSameDirectory(sourceDirs, compressedFormat, zipFilePath); | ||||
|         if (value) { | ||||
|             //表结构增加    nodeId, String TaskId | ||||
|             TsFiles tsFiles = new TsFiles(); | ||||
| @ -1244,12 +1235,104 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
| 
 | ||||
|     // ================== 核心方法改造 ================== | ||||
| 
 | ||||
|     /** | ||||
|      * 确保完整路径存在,不存在则逐层创建 | ||||
|      * | ||||
|      * @param compressedPath 输入的完整路径(如 /38240bbb160450e03de33df911937d59/1/1/2/3/4/) | ||||
|      * @param nodeId         当前节点ID(如 38240bbb160450e03de33df911937d59) | ||||
|      * @return 最终目录的数据库ID(即最后一级目录的ID) | ||||
|      */ | ||||
|     public String ensureFullPathExists(String compressedPath, String nodeId, String taskId) { | ||||
|         // 1. 解析路径,提取有效层级目录名(跳过nodeId部分) | ||||
|         List<String> pathSegments = Arrays.stream(compressedPath.split("/")) | ||||
|                 .filter(s -> !s.isEmpty()) | ||||
|                 .collect(Collectors.toList()); | ||||
| 
 | ||||
|     private Boolean compressToSameDirectory(List<Path> sourcePaths, String compressedFormat) { | ||||
|         // 校验路径是否以nodeId开头 | ||||
|         if (pathSegments.isEmpty() || !pathSegments.get(0).equals(nodeId)) { | ||||
|             throw new RuntimeException("路径必须包含当前节点ID"); | ||||
|         } | ||||
| 
 | ||||
|         // 提取实际要处理的目录层级(去掉开头的nodeId) | ||||
|         List<String> dirSegments = pathSegments.subList(1, pathSegments.size()); | ||||
|         if (dirSegments.isEmpty()) { | ||||
|             throw new RuntimeException("路径缺少有效目录层级"); | ||||
|         } | ||||
| 
 | ||||
|         // 2. 初始化根目录信息(基于nodeId) | ||||
|         String parentId = "00"; // 根目录的父ID为0 | ||||
|         String baseFsPath = "/" + nodeId + "/"; // 本地存储基础路径 | ||||
|         // 设置当前时间 | ||||
|         LocalDateTime now = LocalDateTime.now(); | ||||
|         // 转换为 Timestamp | ||||
|         Timestamp currentTime = Timestamp.valueOf(now); | ||||
| 
 | ||||
|         //上传人是当前登录人 | ||||
|         UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); | ||||
|         LoginUser loginuser = (LoginUser) authentication.getPrincipal(); | ||||
| 
 | ||||
|         // 3. 逐层处理目录(从第一个有效目录开始) | ||||
|         String currentPath = baseFsPath; | ||||
|         for (String dirName : dirSegments) { | ||||
|             // 检查当前层级目录是否存在 | ||||
|             TsFiles dir = tsFilesMapper.selectOne(new QueryWrapper<TsFiles>() | ||||
|                     .eq("node_id", nodeId) | ||||
|                     .eq("task_id", taskId) | ||||
|                     .eq("parent_id", parentId) | ||||
|                     .eq("work_path", currentPath) | ||||
|                     .eq("file_name", dirName)); | ||||
| 
 | ||||
|             if (dir == null) { | ||||
|                 // 创建本地文件夹(如 /38240bbb.../1/2/) | ||||
| 
 | ||||
|                 //        //本地创建文件夹 | ||||
|                 NewFolderRequest newFolderRequest = new NewFolderRequest(); | ||||
|                 newFolderRequest.setStorageKey("local"); | ||||
|                 newFolderRequest.setPath(currentPath); | ||||
|                 newFolderRequest.setPassword(null); | ||||
|                 newFolderRequest.setName(dirName); | ||||
| 
 | ||||
|                 AbstractBaseFileService<?> fileServicefolder = storageSourceContext.getByStorageKey(newFolderRequest.getStorageKey()); | ||||
|                 boolean flagfolder = fileServicefolder.newFolder(newFolderRequest.getPath(), newFolderRequest.getName()); | ||||
|                 if (!flagfolder) { | ||||
|                     throw new RuntimeException("目录创建失败: " + dirName); | ||||
|                 } | ||||
| 
 | ||||
|                 // 插入数据库记录 | ||||
|                 TsFiles tsFiles1 = new TsFiles(); | ||||
|                 tsFiles1.setNodeId(nodeId); | ||||
|                 tsFiles1.setTaskId(taskId); | ||||
|                 tsFiles1.setIsFile("FOLDER"); | ||||
|                 tsFiles1.setParentId(parentId); | ||||
|                 tsFiles1.setFileName(dirName); | ||||
|                 tsFiles1.setFileSize("0"); | ||||
|                 tsFiles1.setWorkPath(currentPath); | ||||
|                 tsFiles1.setBackupPath(""); | ||||
|                 tsFiles1.setKeywords(""); | ||||
|                 tsFiles1.setDescription(""); | ||||
|                 tsFiles1.setUploadTime(currentTime); | ||||
|                 tsFiles1.setUploader(loginuser.getUsername()); | ||||
|                 //如果为空就新增 | ||||
|                 int valueAdded = tsFilesMapper.insert(tsFiles1); | ||||
|                 if (valueAdded == 1) { | ||||
|                     parentId = tsFiles1.getId(); | ||||
|                     currentPath = tsFiles1.getWorkPath() + tsFiles1.getFileName() + "/"; | ||||
|                 } | ||||
|             } else { | ||||
|                 parentId = dir.getId(); | ||||
|                 currentPath = dir.getWorkPath() + dir.getFileName() + "/"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return parentId; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private Boolean compressToSameDirectory(List<Path> sourcePaths, String compressedFormat, Path outputPath) { | ||||
|         try { | ||||
|             switch (compressedFormat.toUpperCase()) { | ||||
|                 case "ZIP": | ||||
|                     return compressToZip(sourcePaths); | ||||
|                     return compressToZip(sourcePaths, outputPath); | ||||
|                 case "TAR.GZ": | ||||
|                     return compressToTarGz(sourcePaths); | ||||
| //                case "7Z": | ||||
| @ -1267,40 +1350,57 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 压缩多个文件/目录到单个ZIP | ||||
|      * 压缩文件/目录到指定路径 | ||||
|      * | ||||
|      * @param sourcePaths 源文件/目录列表 | ||||
|      * @param outputPath  指定的输出路径(可以是目录或完整文件路径) | ||||
|      */ | ||||
|     public boolean compressToZip(List<Path> sourcePaths) { | ||||
|     public boolean compressToZip(List<Path> sourcePaths, Path outputPath) { | ||||
|         if (sourcePaths.isEmpty()) { | ||||
|             LOGGER.warn("源路径列表为空,无法压缩"); | ||||
|             return false; | ||||
|         } | ||||
| 
 | ||||
|         Path zipPath = generateZipPath(sourcePaths.get(0)); | ||||
|         addedEntries.clear(); // 清空历史记录 | ||||
|         // 生成最终 ZIP 路径 | ||||
|         Path finalZipPath = generateFinalZipPath(sourcePaths.get(0), outputPath); | ||||
|         addedEntries.clear(); | ||||
| 
 | ||||
|         try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipPath))) { | ||||
|         try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(finalZipPath))) { | ||||
|             zipOut.setLevel(Deflater.DEFAULT_COMPRESSION); | ||||
| 
 | ||||
|             for (Path sourcePath : sourcePaths) { | ||||
|                 if (Files.isDirectory(sourcePath)) { | ||||
|                     // 使用唯一化的 baseDir(例如目录名) | ||||
|                     String baseDir = sourcePath.getFileName().toString(); | ||||
|                     addDirectoryToZip(sourcePath, zipOut, baseDir); | ||||
|                 } else { | ||||
|                     // 文件直接添加到根目录,或指定唯一子目录 | ||||
|                     addFileToZip(sourcePath, zipOut, ""); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             zipOut.finish(); | ||||
|             return validateZip(zipPath); | ||||
|             return validateZip(finalZipPath); | ||||
|         } catch (Exception e) { | ||||
|             LOGGER.error("压缩失败", e); | ||||
|             deleteQuietly(zipPath); | ||||
|             deleteQuietly(finalZipPath); | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 生成最终 ZIP 路径 | ||||
|      */ | ||||
|     private Path generateFinalZipPath(Path sourcePath, Path outputPath) { | ||||
|         // 如果输出路径是目录,则在目录中生成默认名称的 ZIP | ||||
|         if (Files.isDirectory(outputPath)) { | ||||
|             String baseName = sourcePath.getFileName().toString().replaceFirst("[.][^.]+$", ""); | ||||
|             return outputPath.resolve(baseName + ".zip"); | ||||
|         } | ||||
|         // 否则直接使用指定路径 | ||||
|         return outputPath; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private void addDirectoryToZip(Path dir, ZipOutputStream zipOut, String baseDir) throws IOException { | ||||
|         final Path sourceDir = dir; | ||||
| 
 | ||||
| @ -1555,9 +1655,18 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|         QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>(); | ||||
|         queryWrapper.eq("name", "filePath"); | ||||
|         StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper); | ||||
| 
 | ||||
|         decompressionPath = normalizePath(decompressionPath); | ||||
|         // 1. 获取压缩包记录 | ||||
|         TsFiles zipFileRecord = tsFilesMapper.selectById(id); | ||||
|         try { | ||||
|             String finalParentId = ensureFullPathExists(decompressionPath, zipFileRecord.getNodeId(), zipFileRecord.getTaskId()); | ||||
|             parentId = finalParentId; | ||||
|             LOGGER.info("路径已全部存在,最终目录ID: {}", finalParentId); | ||||
|         } catch (RuntimeException e) { | ||||
|             LOGGER.error("路径创建失败: {}", e.getMessage()); | ||||
|             return "路径创建失败!"; | ||||
|         } | ||||
| 
 | ||||
|         String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例:222 | ||||
|         try { | ||||
|             // 2. 判断压缩包类型(单文件还是文件夹) | ||||
| @ -2181,22 +2290,36 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
| 
 | ||||
|     // 辅助方法:处理文件列表(并行安全) | ||||
|     private void processFileLists(TsFiles tsFile, List<FileItemResult> minioList, List<FileItemResult> localList) throws Exception { | ||||
|         processFileList(tsFile.getBackupPath(), tsFile.getFileName(), "minio", minioList, tsFile.getIsFile()); | ||||
|         processFileList(tsFile.getWorkPath(), tsFile.getFileName(), "local", localList, tsFile.getIsFile()); | ||||
|         processFileList(tsFile.getBackupPath(), tsFile.getFileName(), "minio", minioList, tsFile.getIsFile(), tsFile.getNodeId(), tsFile.getTaskId()); | ||||
|         processFileList(tsFile.getWorkPath(), tsFile.getFileName(), "local", localList, tsFile.getIsFile(), tsFile.getNodeId(), tsFile.getTaskId()); | ||||
|     } | ||||
| 
 | ||||
|     // 辅助方法:获取文件列表并添加到集合 | ||||
|     private void processFileList(String path, String fileName, String storageKey, List<FileItemResult> targetList, String isFile) throws Exception { | ||||
|     private void processFileList(String path, String fileName, String storageKey, List<FileItemResult> targetList, String isFile, String nodeId, String taskId) throws Exception { | ||||
|         if (StringUtils.isNotEmpty(path)) { | ||||
|             AbstractBaseFileService<?> service = storageSourceContext.getByStorageKey(storageKey); | ||||
|             if (isFile.equals("FOLDER") && storageKey.equals("minio")) { | ||||
|                 List<FileItemResult> files = service.fileListData(path, fileName + "/"); | ||||
|                 if (files != null) { | ||||
|                     // 对每个文件的路径进行规范化 | ||||
|                     files.forEach(file -> { | ||||
|                     for (FileItemResult file : files) { | ||||
|                         String normalizedPath = ensurePathFormat(file.getPath()); | ||||
|                         file.setPath(normalizedPath); | ||||
|                     }); | ||||
|                         QueryWrapper<TsFiles> queryWrapper = new QueryWrapper<>(); | ||||
|                         queryWrapper.eq("node_id", nodeId); | ||||
|                         queryWrapper.eq("task_id", taskId); | ||||
|                         queryWrapper.eq("backup_path", normalizedPath); | ||||
|                         queryWrapper.eq("file_name", file.getName()); | ||||
|                         TsFiles tsFiles1 = tsFilesMapper.selectOne(queryWrapper); | ||||
|                         if (tsFiles1 != null) { | ||||
|                             file.setParentId(tsFiles1.getParentId()); | ||||
|                         } | ||||
|                     } | ||||
| 
 | ||||
| 
 | ||||
| //                    files.forEach(file -> { | ||||
| // | ||||
| //                    }); | ||||
|                     // 同步添加(线程安全) | ||||
|                     synchronized (targetList) { | ||||
|                         targetList.addAll(files); | ||||
| @ -2206,10 +2329,19 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl | ||||
|                 List<FileItemResult> files = service.fileListData(path, fileName); | ||||
|                 if (files != null) { | ||||
|                     // 对每个文件的路径进行规范化 | ||||
|                     files.forEach(file -> { | ||||
|                     for (FileItemResult file : files) { | ||||
|                         String normalizedPath = ensurePathFormat(file.getPath()); | ||||
|                         file.setPath(normalizedPath); | ||||
|                     }); | ||||
|                         QueryWrapper<TsFiles> queryWrapper = new QueryWrapper<>(); | ||||
|                         queryWrapper.eq("node_id", nodeId); | ||||
|                         queryWrapper.eq("task_id", taskId); | ||||
|                         queryWrapper.eq("work_path", normalizedPath); | ||||
|                         queryWrapper.eq("file_name", file.getName()); | ||||
|                         TsFiles tsFiles1 = tsFilesMapper.selectOne(queryWrapper); | ||||
|                         if (tsFiles1 != null) { | ||||
|                             file.setParentId(tsFiles1.getParentId()); | ||||
|                         } | ||||
|                     } | ||||
|                     // 同步添加(线程安全) | ||||
|                     synchronized (targetList) { | ||||
|                         targetList.addAll(files); | ||||
|  | ||||
| @ -43,7 +43,7 @@ public class FileItemResult implements Serializable { | ||||
|     private String minioMd5; | ||||
|     private String id; | ||||
|     private String formattedTime; | ||||
| 
 | ||||
|     private String parentId; | ||||
|     /** | ||||
|      * 获取路径和名称的组合, 并移除重复的路径分隔符 /. | ||||
|      * | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 lilin
						lilin