提交代码压缩解压缩到指定目录代码提交
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