提交代码

This commit is contained in:
lilin 2025-03-24 10:05:42 +08:00
parent 5525ca35c1
commit 52b7c71fca

View File

@ -43,28 +43,15 @@ import com.yfd.platform.system.domain.SysDictionaryItems;
import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; import com.yfd.platform.system.mapper.SysDictionaryItemsMapper;
import com.yfd.platform.utils.StringUtils; import com.yfd.platform.utils.StringUtils;
import io.netty.channel.ChannelInboundHandlerAdapter; import io.netty.channel.ChannelInboundHandlerAdapter;
import com.github.junrar.Archive;
import com.github.junrar.rarfile.FileHeader;
import com.github.junrar.exception.RarException;
import io.netty.handler.codec.compression.CompressionException;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveOutputStream;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry; import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZFile; import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.compress.compressors.xz.XZCompressorOutputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@ -115,6 +102,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
// 从数据库获取的压缩类型列表 // 从数据库获取的压缩类型列表
private List<String> compressSuffixes; private List<String> compressSuffixes;
private final Set<String> addedEntries = new HashSet<>();
/********************************** /**********************************
* 用途说明: 分页查询试验数据管理-文档内容 * 用途说明: 分页查询试验数据管理-文档内容
@ -1167,13 +1155,18 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
Path zipPath = generateZipPath(sourcePaths.get(0)); Path zipPath = generateZipPath(sourcePaths.get(0));
addedEntries.clear(); // 清空历史记录
try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipPath))) { try (ZipOutputStream zipOut = new ZipOutputStream(Files.newOutputStream(zipPath))) {
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)) {
addDirectoryToZip(sourcePath, zipOut, sourcePath.getFileName().toString()); // 使用唯一化的 baseDir例如目录名
String baseDir = sourcePath.getFileName().toString();
addDirectoryToZip(sourcePath, zipOut, baseDir);
} else { } else {
// 文件直接添加到根目录或指定唯一子目录
addFileToZip(sourcePath, zipOut, ""); addFileToZip(sourcePath, zipOut, "");
} }
} }
@ -1188,23 +1181,46 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
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;
Files.walkFileTree(dir, new SimpleFileVisitor<Path>() { Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
@Override @Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { public FileVisitResult preVisitDirectory(Path currentDir, BasicFileAttributes attrs) throws IOException {
String entryName = baseDir + "/" + dir.relativize(dir).toString().replace("\\", "/") + "/"; // 跳过源目录自身由外部显式添加
ZipEntry entry = new ZipEntry(entryName); if (currentDir.equals(sourceDir)) {
zipOut.putNextEntry(entry); return FileVisitResult.CONTINUE;
zipOut.closeEntry(); }
// 生成相对路径的条目名称
Path relativePath = sourceDir.relativize(currentDir);
String entryName = baseDir + "/" + relativePath.toString().replace("\\", "/") + "/";
// 确保条目唯一性
addUniqueDirectoryEntry(entryName, zipOut);
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
@Override @Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
String entryName = baseDir + "/" + dir.relativize(file).toString().replace("\\", "/"); Path relativePath = sourceDir.relativize(file);
String entryName = baseDir + "/" + relativePath.toString().replace("\\", "/");
addFileEntry(file, entryName, zipOut); addFileEntry(file, entryName, zipOut);
return FileVisitResult.CONTINUE; return FileVisitResult.CONTINUE;
} }
}); });
// 显式添加根目录条目确保至少存在一个目录条目
String rootEntry = baseDir + "/";
addUniqueDirectoryEntry(rootEntry, zipOut);
}
private void addUniqueDirectoryEntry(String entryName, ZipOutputStream zipOut) throws IOException {
if (!addedEntries.contains(entryName)) {
ZipEntry entry = new ZipEntry(entryName);
zipOut.putNextEntry(entry);
zipOut.closeEntry();
addedEntries.add(entryName);
}
} }
private void addFileToZip(Path file, ZipOutputStream zipOut, String baseDir) throws IOException { private void addFileToZip(Path file, ZipOutputStream zipOut, String baseDir) throws IOException {
@ -1213,6 +1229,11 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
private void addFileEntry(Path file, String entryName, ZipOutputStream zipOut) throws IOException { private void addFileEntry(Path file, String entryName, ZipOutputStream zipOut) throws IOException {
if (addedEntries.contains(entryName)) {
LOGGER.warn("跳过重复条目: {}", entryName);
return;
}
LOGGER.debug("添加文件条目: {} (大小: {} 字节)", entryName, Files.size(file)); LOGGER.debug("添加文件条目: {} (大小: {} 字节)", entryName, Files.size(file));
ZipEntry entry = new ZipEntry(entryName); ZipEntry entry = new ZipEntry(entryName);
entry.setSize(Files.size(file)); entry.setSize(Files.size(file));
@ -1228,6 +1249,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
zipOut.closeEntry(); zipOut.closeEntry();
addedEntries.add(entryName);
} }
private Path generateZipPath(Path sourcePath) { private Path generateZipPath(Path sourcePath) {
@ -1247,7 +1269,8 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
ZipEntry entry = entries.nextElement(); ZipEntry entry = entries.nextElement();
try (InputStream is = zipFile.getInputStream(entry)) { try (InputStream is = zipFile.getInputStream(entry)) {
byte[] buffer = new byte[1024]; byte[] buffer = new byte[1024];
while (is.read(buffer) != -1) {} // 读取条目内容 while (is.read(buffer) != -1) {
} // 读取条目内容
} }
} }
@ -1262,7 +1285,8 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
private void deleteQuietly(Path path) { private void deleteQuietly(Path path) {
try { try {
Files.deleteIfExists(path); Files.deleteIfExists(path);
} catch (IOException ignored) {} } catch (IOException ignored) {
}
} }
/** /**
@ -1277,13 +1301,6 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
} }
// ================== TAR.GZ格式压缩实现 ================== // ================== TAR.GZ格式压缩实现 ==================
private boolean compressToTarGz(List<Path> sourcePaths) throws IOException { private boolean compressToTarGz(List<Path> sourcePaths) throws IOException {
boolean success = true; boolean success = true;
@ -1420,7 +1437,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
// 1. 获取压缩包记录 // 1. 获取压缩包记录
TsFiles zipFileRecord = tsFilesMapper.selectById(id); TsFiles zipFileRecord = tsFilesMapper.selectById(id);
String zipName = zipFileRecord.getFileName(); // 示例222 String zipName = getFileNameWithoutExtension(zipFileRecord.getFileName()); // 示例222
try { try {
// 2. 判断压缩包类型单文件还是文件夹 // 2. 判断压缩包类型单文件还是文件夹
Path zipFilePath = Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName()); Path zipFilePath = Paths.get(storageSourceConfig.getValue(), zipFileRecord.getWorkPath(), zipFileRecord.getFileName());
@ -1429,12 +1446,8 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
// // 4. 构建解压目标路径 // // 4. 构建解压目标路径
Path destRoot; Path destRoot;
if (hasFolder) { if (hasFolder) {
// 动态去掉 .zip 后缀仅用于路径构建
String folderName = zipName.toLowerCase().endsWith(".zip")
? zipName.substring(0, zipName.length() - 4)
: zipName;
// 如果有文件夹创建子目录 E:/yun/333/222/ // 如果有文件夹创建子目录 E:/yun/333/222/
destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, folderName); destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
} else { } else {
// 如果只有文件直接解压到目标目录 E:/yun/333/ // 如果只有文件直接解压到目标目录 E:/yun/333/
destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath); destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath);
@ -1460,7 +1473,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
); );
String rootFolderId = rootFolder.getId(); String rootFolderId = rootFolder.getId();
// 7. 处理子内容路径从/333/222/开始 // 7. 处理子内容路径从/333/222/开始 关键点 所有的文件夹都是上级路径 文件是上级路径加名称
processFolderContents( processFolderContents(
unzippedRoot, unzippedRoot,
rootFolderId, rootFolderId,
@ -1577,7 +1590,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
folderRecord.setTaskId(taskId); folderRecord.setTaskId(taskId);
folderRecord.setParentId(parentId); // 父ID是222的ID folderRecord.setParentId(parentId); // 父ID是222的ID
folderRecord.setFileName(child.getName()); folderRecord.setFileName(child.getName());
folderRecord.setWorkPath(childWorkPath); // /333/222/555/ folderRecord.setWorkPath(folderWorkPath); // /333/222/555/
folderRecord.setIsFile("FOLDER"); folderRecord.setIsFile("FOLDER");
folderRecord.setFileSize("0"); folderRecord.setFileSize("0");
folderRecord.setUploadTime(new Timestamp(System.currentTimeMillis())); folderRecord.setUploadTime(new Timestamp(System.currentTimeMillis()));
@ -1587,7 +1600,7 @@ public class TsFilesServiceImpl extends ServiceImpl<TsFilesMapper, TsFiles> impl
processFolderContents( processFolderContents(
child, child,
folderRecord.getId(), folderRecord.getId(),
folderWorkPath, childWorkPath,
taskId, taskId,
nodeId, nodeId,
uploader uploader