提交代码
This commit is contained in:
parent
bdac9db39a
commit
2520417014
@ -21,6 +21,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.amazonaws.services.s3.model.ObjectMetadata;
|
||||
import com.amazonaws.services.s3.model.S3Object;
|
||||
import com.amazonaws.services.s3.model.S3ObjectInputStream;
|
||||
import com.amazonaws.util.IOUtils;
|
||||
@ -412,7 +413,13 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
files1.setUploadTime(tsFiles.getUploadTime());
|
||||
files1.setUploader(loginuser.getUsername());
|
||||
files1.setFileName(name);
|
||||
if ("0.000".equals(sizeStr)) {
|
||||
files1.setFileSize("0.001");
|
||||
|
||||
} else {
|
||||
files1.setFileSize(sizeStr);
|
||||
}
|
||||
|
||||
filesToSave.add(files1);
|
||||
} catch (NumberFormatException e) {
|
||||
LOGGER.error("文件大小必须是有效的数字");
|
||||
@ -2235,6 +2242,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
}
|
||||
return destRoot.toFile();
|
||||
}
|
||||
|
||||
// 转换Unix权限位
|
||||
private String getPosixMode(int mode) {
|
||||
return String.format("%s%s%s %s%s%s %s%s%s",
|
||||
@ -2242,6 +2250,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
(mode & 0040) != 0 ? "r" : "-", (mode & 0020) != 0 ? "w" : "-", (mode & 0010) != 0 ? "x" : "-",
|
||||
(mode & 0004) != 0 ? "r" : "-", (mode & 0002) != 0 ? "w" : "-", (mode & 0001) != 0 ? "x" : "-");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证目标路径安全性(防止路径穿越攻击)
|
||||
*/
|
||||
@ -2286,6 +2295,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
/**
|
||||
* 智能规范化压缩包内路径
|
||||
*
|
||||
* @param entryPath 压缩包内原始路径
|
||||
* @param archiveFilename 压缩包文件名(如"111.tar.gz")
|
||||
* @return 处理后的路径
|
||||
@ -2308,6 +2318,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
/**
|
||||
* 安全规范化压缩包内路径
|
||||
*
|
||||
* @param entryPath 原始路径(如 "111/222/3.txt")
|
||||
* @param archiveName 压缩包文件名(如 "111.7z")
|
||||
* @return 规范化后的路径(如 "222/3.txt")
|
||||
@ -2382,6 +2393,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
/**
|
||||
* 智能路径规范化(修复7z/tar.gz多层级问题)
|
||||
*
|
||||
* @param entryPath 压缩包内原始路径(如 "111/222/3.txt")
|
||||
* @param archiveName 压缩包文件名(如 "111.7z")
|
||||
* @return 规范化后的路径(如 "222/3.txt")
|
||||
@ -2413,7 +2425,6 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 设置文件权限(兼容Unix系统)
|
||||
*
|
||||
@ -2561,7 +2572,41 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
List<FileItemResult> files = service.fileListData(path, fileName + "/");
|
||||
if (files != null) {
|
||||
// 对每个文件的路径进行规范化
|
||||
for (FileItemResult file : files) {
|
||||
// for (FileItemResult file : files) {
|
||||
// String normalizedPath = ensurePathFormat(file.getPath());
|
||||
// String ProcessingPath = processingPath(normalizedPath, nodeId);
|
||||
// file.setPath(ProcessingPath);
|
||||
// if (file.getSize() == null) {
|
||||
// file.setSize((long) 0);
|
||||
// } else {
|
||||
// // 获取文件大小(字节)
|
||||
// long fileSizeInBytes = file.getSize();
|
||||
// // 转换为 MB 并保留两位小数
|
||||
// double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
|
||||
// String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
|
||||
// // 判断是否为 "0.00",如果是,则直接设置为 0
|
||||
// if ("0.00".equals(fileSizeFormatted)) {
|
||||
// file.setSize((long) 0); // 如果文件大小为 0.00,直接设置为 0
|
||||
// } else {
|
||||
// // 否则,将文件大小转换为 long(去掉小数部分)
|
||||
// file.setSize((long) Double.parseDouble(fileSizeFormatted));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// 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());
|
||||
// file.setId(tsFiles1.getId());
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
files.forEach(file -> {
|
||||
String normalizedPath = ensurePathFormat(file.getPath());
|
||||
String ProcessingPath = processingPath(normalizedPath, nodeId);
|
||||
file.setPath(ProcessingPath);
|
||||
@ -2575,7 +2620,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
|
||||
// 判断是否为 "0.00",如果是,则直接设置为 0
|
||||
if ("0.00".equals(fileSizeFormatted)) {
|
||||
file.setSize((long) 0); // 如果文件大小为 0.00,直接设置为 0
|
||||
file.setSize((long) 0.001); // 如果文件大小为 0.00,直接设置为 0
|
||||
} else {
|
||||
// 否则,将文件大小转换为 long(去掉小数部分)
|
||||
file.setSize((long) Double.parseDouble(fileSizeFormatted));
|
||||
@ -2592,22 +2637,17 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
file.setParentId(tsFiles1.getParentId());
|
||||
file.setId(tsFiles1.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// files.forEach(file -> {
|
||||
//
|
||||
// });
|
||||
});
|
||||
// 同步添加(线程安全)
|
||||
synchronized (targetList) {
|
||||
|
||||
targetList.addAll(files);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
List<FileItemResult> files = service.fileListData(path, fileName);
|
||||
if (files != null) {
|
||||
// 对每个文件的路径进行规范化
|
||||
for (FileItemResult file : files) {
|
||||
files.forEach(file -> {
|
||||
String normalizedPath = ensurePathFormat(file.getPath());
|
||||
|
||||
String ProcessingPath = processingPath(normalizedPath, nodeId);
|
||||
@ -2622,7 +2662,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
|
||||
// 判断是否为 "0.00",如果是,则直接设置为 0
|
||||
if ("0.00".equals(fileSizeFormatted)) {
|
||||
file.setSize((long) 0); // 如果文件大小为 0.00,直接设置为 0
|
||||
file.setSize((long) 0.001); // 如果文件大小为 0.00,直接设置为 0
|
||||
} else {
|
||||
// 否则,将文件大小转换为 long(去掉小数部分)
|
||||
file.setSize((long) Double.parseDouble(fileSizeFormatted));
|
||||
@ -2639,11 +2679,11 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
file.setParentId(tsFiles1.getParentId());
|
||||
file.setId(tsFiles1.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
// 同步添加(线程安全)
|
||||
synchronized (targetList) {
|
||||
|
||||
targetList.addAll(files);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2673,11 +2713,19 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
// 辅助方法:去重文件列表(并行安全)
|
||||
private void deduplicateFileList(List<FileItemResult> fileList) {
|
||||
ConcurrentMap<String, Boolean> seenKeys = new ConcurrentHashMap<>();
|
||||
fileList.removeIf(file -> {
|
||||
String key = normalizePath(file.getPath()) + file.getName();
|
||||
return seenKeys.putIfAbsent(key, Boolean.TRUE) != null;
|
||||
});
|
||||
// ConcurrentMap<String, Boolean> seenKeys = new ConcurrentHashMap<>();
|
||||
// fileList.removeIf(file -> {
|
||||
// String key = normalizePath(file.getPath()) + file.getName();
|
||||
// return seenKeys.putIfAbsent(key, Boolean.TRUE) != null;
|
||||
// });
|
||||
|
||||
ConcurrentHashMap<String, Boolean> seenKeys = new ConcurrentHashMap<>();
|
||||
List<FileItemResult> uniqueFiles = fileList.parallelStream()
|
||||
.filter(file -> seenKeys.putIfAbsent(generateMapKey(file), true) == null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
fileList.clear();
|
||||
fileList.addAll(uniqueFiles);
|
||||
}
|
||||
|
||||
public TsFiles compareFiles(List<FileItemResult> minioFiles,
|
||||
@ -2820,19 +2868,39 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
// 辅助方法:获取 MinIO 文件 MD5
|
||||
private String getMinioMD5(FileItemResult file, String bucketName) {
|
||||
// AbstractBaseFileService<?> minioService = storageSourceContext.getByStorageKey("minio");
|
||||
// String key = StringUtils.concat(file.getPath(), file.getName());
|
||||
//
|
||||
// try {
|
||||
// if (file.getSize() <= 5L * 1024 * 1024 * 1024) {
|
||||
// return minioService.getObjectMetadata(bucketName, key).getETag().replace("\"", "");
|
||||
// } else {
|
||||
// try (S3Object s3Object = minioService.getObject(bucketName, key)) {
|
||||
// return calculateMD5(s3Object.getObjectContent());
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception e) {
|
||||
// LOGGER.error("MinIO MD5获取失败: {}", key, e);
|
||||
// return null;
|
||||
// }
|
||||
AbstractBaseFileService<?> minioService = storageSourceContext.getByStorageKey("minio");
|
||||
String key = StringUtils.concat(file.getPath(), file.getName());
|
||||
String key = normalizePath(file.getPath()) + file.getName();
|
||||
|
||||
try {
|
||||
if (file.getSize() <= 5L * 1024 * 1024 * 1024) {
|
||||
return minioService.getObjectMetadata(bucketName, key).getETag().replace("\"", "");
|
||||
ObjectMetadata metadata = minioService.getObjectMetadata(bucketName, key);
|
||||
String eTag = metadata.getETag();
|
||||
|
||||
// 单部分上传的 ETag 是完整 MD5,可直接使用
|
||||
if (eTag != null && !eTag.contains("-")) {
|
||||
return eTag.replace("\"", "");
|
||||
} else {
|
||||
try (S3Object s3Object = minioService.getObject(bucketName, key)) {
|
||||
return calculateMD5(s3Object.getObjectContent());
|
||||
// 多部分上传需重新计算
|
||||
try (InputStream stream = minioService.getObject(bucketName, key).getObjectContent()) {
|
||||
return calculateMD5(stream);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("MinIO MD5获取失败: {}", key, e);
|
||||
LOGGER.error("Failed to get MinIO MD5: {}", key, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -4002,15 +4070,14 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
FileItemResult fileItemResult = fileService.getFileItem(path);
|
||||
if (fileItemResult != null || fileItemResult.getName() != null) {
|
||||
dto.setUrl(fileItemResult.getUrl());
|
||||
String ProcessingPath = processingPath(fileItemResult.getPath(), node.getNodeId());
|
||||
dto.setPath(ProcessingPath);
|
||||
//如果是压缩文件 类型就给zip
|
||||
boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems);
|
||||
if (isValid) {
|
||||
dto.setType("ZIP");
|
||||
} else {
|
||||
dto.setType(fileItemResult.getType().getValue());
|
||||
}
|
||||
// //如果是压缩文件 类型就给zip
|
||||
// boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems);
|
||||
// if (isValid) {
|
||||
// dto.setType("ZIP");
|
||||
// } else {
|
||||
// dto.setType(fileItemResult.getType().getValue());
|
||||
// }
|
||||
} else {
|
||||
dto.setUrl(null);
|
||||
dto.setType(null);
|
||||
@ -4037,13 +4104,14 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
} else {
|
||||
|
||||
dto.setUrl(fileItemResult.getUrl());
|
||||
//如果是压缩文件 类型就给zip
|
||||
boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems);
|
||||
if (isValid) {
|
||||
dto.setType("ZIP");
|
||||
} else {
|
||||
dto.setType(fileItemResult.getType().getValue());
|
||||
}
|
||||
// //如果是压缩文件 类型就给zip
|
||||
// boolean isValid = hasValidExtension(fileItemResult.getName(), sysDictionaryItems);
|
||||
// if (isValid) {
|
||||
// dto.setType("ZIP");
|
||||
// } else {
|
||||
// dto.setType(fileItemResult.getType().getValue());
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4206,11 +4274,13 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
*/
|
||||
@Override
|
||||
public String readFileContent(String id) throws IOException {
|
||||
|
||||
StorageSourceConfig config = storageSourceConfigMapper.selectOne(new QueryWrapper<StorageSourceConfig>().eq("name", "filePath"));
|
||||
TsFiles tsFiles = tsFilesMapper.selectById(id);
|
||||
// 1. 路径标准化与安全校验
|
||||
Path targetPath = validateAndNormalizePath(config.getValue() + tsFiles.getWorkPath() + tsFiles.getFileName());
|
||||
|
||||
|
||||
StringBuilder content = new StringBuilder();
|
||||
|
||||
// 使用缓冲流读取大文件(减少内存占用)
|
||||
@ -4276,7 +4346,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
* 返回值说明: com.yfd.platform.config.ResponseResult操作结果
|
||||
***********************************/
|
||||
@Override
|
||||
public void batchUpdateFile(String id, List<ModifyCommand> modifications)throws IOException {
|
||||
public void batchUpdateFile(String id, List<ModifyCommand> modifications) throws IOException {
|
||||
StorageSourceConfig config = storageSourceConfigMapper.selectOne(new QueryWrapper<StorageSourceConfig>().eq("name", "filePath"));
|
||||
TsFiles tsFile = tsFilesMapper.selectById(id);
|
||||
if (tsFile == null) {
|
||||
@ -4334,6 +4404,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
|
||||
|
||||
/**
|
||||
* 应用所有修改到文件内容
|
||||
*
|
||||
* @param lines 文件每一行的内容
|
||||
* @param modifications 修改指令集合
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user