提交代码

This commit is contained in:
lilin 2025-05-24 11:43:44 +08:00
parent 4b08b3f7a9
commit 2b30e30fda

View File

@ -61,6 +61,7 @@ import java.util.stream.Collectors;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
/** /**
* <p> * <p>
* 专项文档节点表 服务实现类 * 专项文档节点表 服务实现类
@ -682,6 +683,10 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId); AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加 //todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件递归增加
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath()); List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
if (fileItemList.size() == 0) {
throw new Exception("该项目目录不存在或没有项目文档,请先建立项目目录和文档。");
}
//获取数据库父节点为0的文件夹数据 通过所属项目ID和父节点查询 //获取数据库父节点为0的文件夹数据 通过所属项目ID和父节点查询
List<Nodes> nodesList = nodesMapper.selectList(new LambdaQueryWrapper<Nodes>().eq(Nodes::getParentId, "00").eq(Nodes::getProjectId, id)); List<Nodes> nodesList = nodesMapper.selectList(new LambdaQueryWrapper<Nodes>().eq(Nodes::getParentId, "00").eq(Nodes::getProjectId, id));
@ -726,30 +731,32 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
} else { } else {
//获取节点名称 //第一层属于节点同级别的文件不做处理
String nodeName = getLastPathSegment(item.getPath()); continue;
//获取节点信息 主要用到ID // //获取节点名称
QueryWrapper<Nodes> queryWrapper = new QueryWrapper<>(); // String nodeName = getLastPathSegment(item.getPath());
queryWrapper.eq("node_name", nodeName); // //获取节点信息 主要用到ID
queryWrapper.eq("parent_id", TOP_LEVEL_PARENT_NODE); // QueryWrapper<Nodes> queryWrapper = new QueryWrapper<>();
Nodes node = nodesMapper.selectOne(queryWrapper); // queryWrapper.eq("node_name", nodeName);
// queryWrapper.eq("parent_id", TOP_LEVEL_PARENT_NODE);
//新增之前先查询 // Nodes node = nodesMapper.selectOne(queryWrapper);
LambdaQueryWrapper<Files> queryWrapper1 = new LambdaQueryWrapper<>(); //
queryWrapper1.eq(Files::getProjectId, projectId); // //新增之前先查询
queryWrapper1.eq(Files::getNodeId, node.getId()); // LambdaQueryWrapper<Files> queryWrapper1 = new LambdaQueryWrapper<>();
queryWrapper1.eq(Files::getFilePath, item.getPath()); // queryWrapper1.eq(Files::getProjectId, projectId);
queryWrapper1.eq(Files::getFileName, item.getName()); // queryWrapper1.eq(Files::getNodeId, node.getId());
Files files = filesMapper.selectOne(queryWrapper1); // queryWrapper1.eq(Files::getFilePath, item.getPath());
if (files == null){ // queryWrapper1.eq(Files::getFileName, item.getName());
// 获取文件大小字节 // Files files = filesMapper.selectOne(queryWrapper1);
long fileSizeInBytes = item.getSize(); // if (files == null) {
// 转换为 MB 并保留两位小数 // // 获取文件大小字节
double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0); // long fileSizeInBytes = item.getSize();
String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数 // // 转换为 MB 并保留两位小数
//保存文件信息 // double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
saveFiles(projectId, node.getId(), item.getPath(), item.getName(), fileSizeFormatted); // String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
} // //保存文件信息
// saveFiles(projectId, node.getId(), item.getPath(), item.getName(), fileSizeFormatted);
// }
} }
} }
} }
@ -884,9 +891,13 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
*/ */
private void saveFiles(String projectId, String nodeId, String filePath, String fileName, String fileSize) { private void saveFiles(String projectId, String nodeId, String filePath, String fileName, String fileSize) {
//获取当前登录用户 上传人是当前登录人 //获取当前登录用户 上传人是当前登录人
// UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken authentication =
// (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
// LoginUser loginuser = (LoginUser) authentication.getPrincipal(); LoginUser loginuser = null;
if (authentication != null) {
loginuser = (LoginUser) authentication.getPrincipal();
}
// 设置当前时间 // 设置当前时间
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
// 转换为 Timestamp // 转换为 Timestamp
@ -897,8 +908,11 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
files.setNodeId(nodeId); files.setNodeId(nodeId);
files.setFilePath(filePath); files.setFilePath(filePath);
files.setUploadTime(currentTime); files.setUploadTime(currentTime);
files.setUploader("admin"); if (loginuser == null) {
//files.setUploader(loginuser.getUsername()); files.setUploader(null);
} else {
files.setUploader(loginuser.getUsername());
}
files.setFileName(fileName); files.setFileName(fileName);
files.setFileSize(fileSize); files.setFileSize(fileSize);
filesMapper.insert(files); filesMapper.insert(files);
@ -941,15 +955,20 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
//解压以后的文件夹名称 //解压以后的文件夹名称
String zipName = getFileNameWithoutExtension(fileName); // 示例222 String zipName = getFileNameWithoutExtension(fileName); // 示例222
//查询项目信息
Project project = projectMapper.selectById(id);
if(!project.getProjectName().equals(zipName)){
throw new RuntimeException("压缩包名称需要和项目名称保持一致");
}
String decompressionPath = "/" + "temporary"; String decompressionPath = "/" + "temporary";
//构建要解压的zip文件路径 例如 D:\yun\temporary\111.zip //构建要解压的zip文件路径 例如 D:\yun\temporary\111.zip
Path zipFilePath = Paths.get(storageSourceConfig.getValue(), decompressionPath, fileName); Path zipFilePath = Paths.get(storageSourceConfig.getValue(), decompressionPath, fileName);
// 4. 构建解压目标路径 例如 D:\yun\temporary\111 // 4. 构建解压目标路径 例如 D:\yun\temporary\111
Path destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName); Path destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
//查询项目信息
Project project = projectMapper.selectById(id);
//todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描 //todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描
//源文件夹路径 //源文件夹路径
@ -965,6 +984,10 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
//开始执行更新表数据 名称是去掉后缀以后的 //开始执行更新表数据 名称是去掉后缀以后的
uploadProject(zipName); uploadProject(zipName);
//获取文件路径
String path = storageSourceConfig.getValue() + decompressionPath; // 替换为实际路径
File target = new File(path);
deleteDirectory(target);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (Exception e) { } catch (Exception e) {
@ -979,6 +1002,29 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
//todo 首先得上传到一个临时目录 然后找到这个目录我去解压缩到当前文件夹 解压缩以后 然后开始循环 我通过第一层去查询 如果没有就新增 如果有就循环 看看需不需要覆盖 //todo 首先得上传到一个临时目录 然后找到这个目录我去解压缩到当前文件夹 解压缩以后 然后开始循环 我通过第一层去查询 如果没有就新增 如果有就循环 看看需不需要覆盖
public static void deleteDirectory(File directory) throws Exception {
if (!directory.exists()) {
return; // 路径不存在直接返回
}
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
deleteDirectory(file); // 递归删除子目录
} else {
if (!file.delete()) { // 删除文件
throw new Exception("无法删除文件: " + file.getAbsolutePath());
}
}
}
}
if (!directory.delete()) { // 删除空目录
throw new Exception("无法删除目录: " + directory.getAbsolutePath());
}
}
/********************************** /**********************************
* 用途说明: 专项文档管理扫描接口实际接口 * 用途说明: 专项文档管理扫描接口实际接口
* 参数说明 id 所属项目ID * 参数说明 id 所属项目ID
@ -1108,8 +1154,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
//获取文件列表 //获取文件列表
String absolutePath = "/" + project.getProjectName() + "/"; String absolutePath = "/" + project.getProjectName() + "/";
FileListRequest fileListRequest = buildFileRequest(absolutePath); FileListRequest fileListRequest = buildFileRequest(absolutePath);
@ -1138,8 +1182,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
// 编号生成工具方法 // 编号生成工具方法
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public synchronized String generateNextProjectCode() { public synchronized String generateNextProjectCode() {
@ -1236,9 +1278,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
//获取路径下的所有文件和文件夹 //获取路径下的所有文件和文件夹
private List<FileItemResult> obtainFileItemResultData(FileListRequest fileListRequest) throws Exception { private List<FileItemResult> obtainFileItemResultData(FileListRequest fileListRequest) throws Exception {
@ -1336,9 +1375,18 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
try (ZipInputStream zis = new ZipInputStream( try (ZipInputStream zis = new ZipInputStream(
java.nio.file.Files.newInputStream(sourcePath), StandardCharsets.UTF_8)) { java.nio.file.Files.newInputStream(sourcePath), StandardCharsets.UTF_8)) {
ZipEntry entry; ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
while (true) { // 循环结构改为无限循环
try { try {
entry = zis.getNextEntry(); // 尝试获取下一个条目
if (entry == null) {
break; // 没有更多条目退出循环
}
// 打印当前处理的条目名称
LOGGER.info("Processing ZIP entry: {}", entry.getName());
// 跳过 macOS 系统文件 // 跳过 macOS 系统文件
if (entry.getName().startsWith("__MACOSX")) { if (entry.getName().startsWith("__MACOSX")) {
continue; continue;
@ -1364,16 +1412,15 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
} }
Path targetPath = destRoot.resolve(entryName).normalize(); Path targetPath = destRoot.resolve(entryName).normalize();
validatePathSafetya(targetPath, destRoot); validatePathSafetya(targetPath, destRoot); // 确保路径安全
// 处理目录 // 处理目录
if (isDirectory) { if (isDirectory) {
java.nio.file.Files.createDirectories(targetPath); java.nio.file.Files.createDirectories(targetPath);
} } else {
// 处理文件 // 处理文件
else {
if (java.nio.file.Files.exists(targetPath)) { if (java.nio.file.Files.exists(targetPath)) {
LOGGER.warn("文件已存在,跳过覆盖: {}", targetPath); LOGGER.warn("File already exists, skip overwriting: {}", targetPath);
continue; continue;
} }
// 确保父目录存在 // 确保父目录存在
@ -1382,8 +1429,17 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
IOUtils.copy(zis, os); IOUtils.copy(zis, os);
} }
} }
} catch (IllegalArgumentException e) {
// 捕获 MALFORMED 异常并记录条目名称
String errorEntry = (entry != null) ? entry.getName() : "Unknown Entry";
LOGGER.error("MALFORMED ZIP Entry Detected! Entry Name: {}", errorEntry, e);
} finally { } finally {
zis.closeEntry(); // 确保每个条目只关闭一次
if (entry != null) {
zis.closeEntry(); // 关闭当前条目
}
} }
} }
} }
@ -1391,6 +1447,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
return destRoot.toFile(); return destRoot.toFile();
} }
/** /**
* 路径安全验证增强版 * 路径安全验证增强版
*/ */