提交代码压缩解压缩到指定目录代码提交
This commit is contained in:
parent
76b5faf473
commit
5dae66f63e
@ -521,28 +521,6 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
return ResponseResult.error("文件夹名称已存在!");
|
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 newFolderRequest = new NewFolderRequest();
|
||||||
newFolderRequest.setStorageKey("local");
|
newFolderRequest.setStorageKey("local");
|
||||||
@ -1120,6 +1098,9 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("name", "filePath");
|
queryWrapper.eq("name", "filePath");
|
||||||
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
|
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
|
||||||
|
compressedPath = normalizePath(compressedPath);
|
||||||
|
|
||||||
|
|
||||||
String returnResult = "";
|
String returnResult = "";
|
||||||
// 创建要压缩的文件夹列表
|
// 创建要压缩的文件夹列表
|
||||||
List<Path> sourceDirs = new ArrayList<>(); // 修复:使用 ArrayList
|
List<Path> sourceDirs = new ArrayList<>(); // 修复:使用 ArrayList
|
||||||
@ -1147,6 +1128,16 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
// 添加到压缩列表
|
// 添加到压缩列表
|
||||||
sourceDirs.add(path); // 修复:使用可变集合
|
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 是根目录,使用当前工作目录
|
// 如果 compressedPath 是根目录,使用当前工作目录
|
||||||
@ -1163,7 +1154,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
// 设置压缩级别,可以选择调整
|
// 设置压缩级别,可以选择调整
|
||||||
// zipOut.setLevel(ZipArchiveOutputStream.STORED); // 或者使用其他的压缩级别
|
// zipOut.setLevel(ZipArchiveOutputStream.STORED); // 或者使用其他的压缩级别
|
||||||
// 调用压缩方法
|
// 调用压缩方法
|
||||||
Boolean value = compressToSameDirectory(sourceDirs, compressedFormat);
|
Boolean value = compressToSameDirectory(sourceDirs, compressedFormat, zipFilePath);
|
||||||
if (value) {
|
if (value) {
|
||||||
//表结构增加 nodeId, String TaskId
|
//表结构增加 nodeId, String TaskId
|
||||||
TsFiles tsFiles = new TsFiles();
|
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 {
|
try {
|
||||||
switch (compressedFormat.toUpperCase()) {
|
switch (compressedFormat.toUpperCase()) {
|
||||||
case "ZIP":
|
case "ZIP":
|
||||||
return compressToZip(sourcePaths);
|
return compressToZip(sourcePaths, outputPath);
|
||||||
case "TAR.GZ":
|
case "TAR.GZ":
|
||||||
return compressToTarGz(sourcePaths);
|
return compressToTarGz(sourcePaths);
|
||||||
// case "7Z":
|
// 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()) {
|
if (sourcePaths.isEmpty()) {
|
||||||
LOGGER.warn("源路径列表为空,无法压缩");
|
LOGGER.warn("源路径列表为空,无法压缩");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Path zipPath = generateZipPath(sourcePaths.get(0));
|
// 生成最终 ZIP 路径
|
||||||
addedEntries.clear(); // 清空历史记录
|
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);
|
zipOut.setLevel(Deflater.DEFAULT_COMPRESSION);
|
||||||
|
|
||||||
for (Path sourcePath : sourcePaths) {
|
for (Path sourcePath : sourcePaths) {
|
||||||
if (Files.isDirectory(sourcePath)) {
|
if (Files.isDirectory(sourcePath)) {
|
||||||
// 使用唯一化的 baseDir(例如目录名)
|
|
||||||
String baseDir = sourcePath.getFileName().toString();
|
String baseDir = sourcePath.getFileName().toString();
|
||||||
addDirectoryToZip(sourcePath, zipOut, baseDir);
|
addDirectoryToZip(sourcePath, zipOut, baseDir);
|
||||||
} else {
|
} else {
|
||||||
// 文件直接添加到根目录,或指定唯一子目录
|
|
||||||
addFileToZip(sourcePath, zipOut, "");
|
addFileToZip(sourcePath, zipOut, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zipOut.finish();
|
zipOut.finish();
|
||||||
return validateZip(zipPath);
|
return validateZip(finalZipPath);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error("压缩失败", e);
|
LOGGER.error("压缩失败", e);
|
||||||
deleteQuietly(zipPath);
|
deleteQuietly(finalZipPath);
|
||||||
return false;
|
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 {
|
private void addDirectoryToZip(Path dir, ZipOutputStream zipOut, String baseDir) throws IOException {
|
||||||
final Path sourceDir = dir;
|
final Path sourceDir = dir;
|
||||||
|
|
||||||
@ -1555,9 +1655,18 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
|
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
|
||||||
queryWrapper.eq("name", "filePath");
|
queryWrapper.eq("name", "filePath");
|
||||||
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
|
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
|
||||||
|
decompressionPath = normalizePath(decompressionPath);
|
||||||
// 1. 获取压缩包记录
|
// 1. 获取压缩包记录
|
||||||
TsFiles zipFileRecord = tsFilesMapper.selectById(id);
|
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
|
String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例:222
|
||||||
try {
|
try {
|
||||||
// 2. 判断压缩包类型(单文件还是文件夹)
|
// 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 {
|
private void processFileLists(TsFiles tsFile, List<FileItemResult> minioList, List<FileItemResult> localList) throws Exception {
|
||||||
processFileList(tsFile.getBackupPath(), tsFile.getFileName(), "minio", minioList, tsFile.getIsFile());
|
processFileList(tsFile.getBackupPath(), tsFile.getFileName(), "minio", minioList, tsFile.getIsFile(), tsFile.getNodeId(), tsFile.getTaskId());
|
||||||
processFileList(tsFile.getWorkPath(), tsFile.getFileName(), "local", localList, tsFile.getIsFile());
|
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)) {
|
if (StringUtils.isNotEmpty(path)) {
|
||||||
AbstractBaseFileService<?> service = storageSourceContext.getByStorageKey(storageKey);
|
AbstractBaseFileService<?> service = storageSourceContext.getByStorageKey(storageKey);
|
||||||
if (isFile.equals("FOLDER") && storageKey.equals("minio")) {
|
if (isFile.equals("FOLDER") && storageKey.equals("minio")) {
|
||||||
List<FileItemResult> files = service.fileListData(path, fileName + "/");
|
List<FileItemResult> files = service.fileListData(path, fileName + "/");
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
// 对每个文件的路径进行规范化
|
// 对每个文件的路径进行规范化
|
||||||
files.forEach(file -> {
|
for (FileItemResult file : files) {
|
||||||
String normalizedPath = ensurePathFormat(file.getPath());
|
String normalizedPath = ensurePathFormat(file.getPath());
|
||||||
file.setPath(normalizedPath);
|
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) {
|
synchronized (targetList) {
|
||||||
targetList.addAll(files);
|
targetList.addAll(files);
|
||||||
@ -2206,10 +2329,19 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
|||||||
List<FileItemResult> files = service.fileListData(path, fileName);
|
List<FileItemResult> files = service.fileListData(path, fileName);
|
||||||
if (files != null) {
|
if (files != null) {
|
||||||
// 对每个文件的路径进行规范化
|
// 对每个文件的路径进行规范化
|
||||||
files.forEach(file -> {
|
for (FileItemResult file : files) {
|
||||||
String normalizedPath = ensurePathFormat(file.getPath());
|
String normalizedPath = ensurePathFormat(file.getPath());
|
||||||
file.setPath(normalizedPath);
|
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) {
|
synchronized (targetList) {
|
||||||
targetList.addAll(files);
|
targetList.addAll(files);
|
||||||
|
@ -43,7 +43,7 @@ public class FileItemResult implements Serializable {
|
|||||||
private String minioMd5;
|
private String minioMd5;
|
||||||
private String id;
|
private String id;
|
||||||
private String formattedTime;
|
private String formattedTime;
|
||||||
|
private String parentId;
|
||||||
/**
|
/**
|
||||||
* 获取路径和名称的组合, 并移除重复的路径分隔符 /.
|
* 获取路径和名称的组合, 并移除重复的路径分隔符 /.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user