提交代码
This commit is contained in:
parent
4b08b3f7a9
commit
2b30e30fda
@ -61,6 +61,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 专项文档节点表 服务实现类
|
||||
@ -114,7 +115,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
***********************************/
|
||||
@Override
|
||||
public List<Map<String, Object>> getNodesTree(String nodeName, String projectId) {
|
||||
Project project = projectMapper.selectById(projectId);
|
||||
Project project = projectMapper.selectById(projectId);
|
||||
|
||||
// 查询所有节点数据
|
||||
List<Map<String, Object>> allNodes = getAllNodes(projectId);
|
||||
@ -132,14 +133,14 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
// 如果 nodeName 为空,返回所有根节点的完整树形结构
|
||||
if (StringUtils.isEmpty(nodeName)) {
|
||||
for (Map<String, Object> rootNode : rootNodes) {
|
||||
rootNode.put("path",basePath);
|
||||
rootNode.put("path", basePath);
|
||||
result.addAll(buildFullTree(rootNode, allNodes));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// 否则,返回从根节点到目标节点的树形结构
|
||||
for (Map<String, Object> rootNode : rootNodes) {
|
||||
rootNode.put("path",basePath);
|
||||
rootNode.put("path", basePath);
|
||||
List<Map<String, Object>> tree = buildTreeToTargetNode(rootNode, allNodes, nodeName);
|
||||
if (!tree.isEmpty()) {
|
||||
result.addAll(tree);
|
||||
@ -530,7 +531,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
***********************************/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class) // 启用事务
|
||||
public boolean deleteNodesById(String id,String path) {
|
||||
public boolean deleteNodesById(String id, String path) {
|
||||
Boolean value = false;
|
||||
|
||||
|
||||
@ -682,6 +683,10 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
AbstractBaseFileService<?> fileService = storageSourceContext.getByStorageId(storageId);
|
||||
//todo 首先获取两个集合 对比出数据库中没有的文件夹以及文件,递归增加
|
||||
List<FileItemResult> fileItemList = fileService.fileList(fileListRequest.getPath());
|
||||
if (fileItemList.size() == 0) {
|
||||
throw new Exception("该项目目录不存在或没有项目文档,请先建立项目目录和文档。");
|
||||
}
|
||||
|
||||
|
||||
//获取数据库父节点为0的文件夹数据 通过所属项目ID和父节点查询
|
||||
List<Nodes> nodesList = nodesMapper.selectList(new LambdaQueryWrapper<Nodes>().eq(Nodes::getParentId, "00").eq(Nodes::getProjectId, id));
|
||||
@ -718,38 +723,40 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
// queryWrapper.eq(Nodes::getNodeOrder, obtainNodeType(index));
|
||||
Nodes nodeData = nodesMapper.selectOne(queryWrapper);
|
||||
//如果没有 新增 并且递归
|
||||
if (nodeData == null){
|
||||
if (nodeData == null) {
|
||||
Nodes node = saveNodes(projectId, TOP_LEVEL_PARENT_NODE, item.getName(), obtainNodeType(index));
|
||||
otherLevelsData(projectId, node.getId(), item.getName(), item.getPath(), index);
|
||||
}else{
|
||||
} else {
|
||||
otherLevelsData(projectId, nodeData.getId(), item.getName(), item.getPath(), index);
|
||||
}
|
||||
|
||||
} else {
|
||||
//获取节点名称
|
||||
String nodeName = getLastPathSegment(item.getPath());
|
||||
//获取节点信息 主要用到ID
|
||||
QueryWrapper<Nodes> queryWrapper = new 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());
|
||||
queryWrapper1.eq(Files::getFilePath, item.getPath());
|
||||
queryWrapper1.eq(Files::getFileName, item.getName());
|
||||
Files files = filesMapper.selectOne(queryWrapper1);
|
||||
if (files == null){
|
||||
// 获取文件大小(字节)
|
||||
long fileSizeInBytes = item.getSize();
|
||||
// 转换为 MB 并保留两位小数
|
||||
double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
|
||||
String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
|
||||
//保存文件信息
|
||||
saveFiles(projectId, node.getId(), item.getPath(), item.getName(), fileSizeFormatted);
|
||||
}
|
||||
//第一层属于节点,同级别的文件不做处理
|
||||
continue;
|
||||
// //获取节点名称
|
||||
// String nodeName = getLastPathSegment(item.getPath());
|
||||
// //获取节点信息 主要用到ID
|
||||
// QueryWrapper<Nodes> queryWrapper = new 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());
|
||||
// queryWrapper1.eq(Files::getFilePath, item.getPath());
|
||||
// queryWrapper1.eq(Files::getFileName, item.getName());
|
||||
// Files files = filesMapper.selectOne(queryWrapper1);
|
||||
// if (files == null) {
|
||||
// // 获取文件大小(字节)
|
||||
// long fileSizeInBytes = item.getSize();
|
||||
// // 转换为 MB 并保留两位小数
|
||||
// double fileSizeInMB = fileSizeInBytes / (1024.0 * 1024.0);
|
||||
// String fileSizeFormatted = String.format("%.2f", fileSizeInMB); // 保留两位小数
|
||||
// //保存文件信息
|
||||
// saveFiles(projectId, node.getId(), item.getPath(), item.getName(), fileSizeFormatted);
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,11 +798,11 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
// queryWrapper.eq(Nodes::getNodeOrder, obtainNodeType(index));
|
||||
Nodes nodeData = nodesMapper.selectOne(queryWrapper);
|
||||
//如果没有 新增 并且递归
|
||||
if (nodeData == null){
|
||||
if (nodeData == null) {
|
||||
//保存节点
|
||||
Nodes node = saveNodes(projectId, parentId, item.getName(), obtainNodeType(index));
|
||||
otherLevelsData(projectId, node.getId(), item.getName(), item.getPath(), index);
|
||||
}else{
|
||||
} else {
|
||||
otherLevelsData(projectId, nodeData.getId(), item.getName(), item.getPath(), index);
|
||||
}
|
||||
} else {
|
||||
@ -809,7 +816,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
queryWrapper1.eq(Files::getFilePath, item.getPath());
|
||||
queryWrapper1.eq(Files::getFileName, item.getName());
|
||||
Files files = filesMapper.selectOne(queryWrapper1);
|
||||
if (files == null){
|
||||
if (files == null) {
|
||||
// 获取文件大小(字节)
|
||||
long fileSizeInBytes = item.getSize();
|
||||
// 转换为 MB 并保留两位小数
|
||||
@ -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) {
|
||||
//获取当前登录用户 上传人是当前登录人
|
||||
// UsernamePasswordAuthenticationToken authentication =
|
||||
// (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
||||
// LoginUser loginuser = (LoginUser) authentication.getPrincipal();
|
||||
UsernamePasswordAuthenticationToken authentication =
|
||||
(UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
|
||||
LoginUser loginuser = null;
|
||||
if (authentication != null) {
|
||||
loginuser = (LoginUser) authentication.getPrincipal();
|
||||
}
|
||||
|
||||
// 设置当前时间
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
// 转换为 Timestamp
|
||||
@ -897,8 +908,11 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
files.setNodeId(nodeId);
|
||||
files.setFilePath(filePath);
|
||||
files.setUploadTime(currentTime);
|
||||
files.setUploader("admin");
|
||||
//files.setUploader(loginuser.getUsername());
|
||||
if (loginuser == null) {
|
||||
files.setUploader(null);
|
||||
} else {
|
||||
files.setUploader(loginuser.getUsername());
|
||||
}
|
||||
files.setFileName(fileName);
|
||||
files.setFileSize(fileSize);
|
||||
filesMapper.insert(files);
|
||||
@ -941,15 +955,20 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
//解压以后的文件夹名称
|
||||
String zipName = getFileNameWithoutExtension(fileName); // 示例:222
|
||||
|
||||
//查询项目信息
|
||||
Project project = projectMapper.selectById(id);
|
||||
|
||||
if(!project.getProjectName().equals(zipName)){
|
||||
throw new RuntimeException("压缩包名称需要和项目名称保持一致");
|
||||
}
|
||||
|
||||
String decompressionPath = "/" + "temporary";
|
||||
//构建要解压的zip文件路径 例如 D:\yun\temporary\111.zip
|
||||
Path zipFilePath = Paths.get(storageSourceConfig.getValue(), decompressionPath, fileName);
|
||||
|
||||
// 4. 构建解压目标路径 例如 D:\yun\temporary\111
|
||||
Path destRoot = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
|
||||
|
||||
//查询项目信息
|
||||
Project project = projectMapper.selectById(id);
|
||||
|
||||
//todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描
|
||||
|
||||
//源文件夹路径
|
||||
@ -960,11 +979,15 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
//首先执行解压缩
|
||||
unzipToTemp(zipFilePath, String.valueOf(destRoot));
|
||||
// 执行上传并且插入数据库
|
||||
this.documentUploadById(id,sourceFolderPath,targetFolderPath,storageSourceConfig.getValue());
|
||||
this.documentUploadById(id, sourceFolderPath, targetFolderPath, storageSourceConfig.getValue());
|
||||
|
||||
//开始执行更新表数据 名称是去掉后缀以后的
|
||||
uploadProject(zipName);
|
||||
|
||||
//获取文件路径
|
||||
String path = storageSourceConfig.getValue() + decompressionPath; // 替换为实际路径
|
||||
File target = new File(path);
|
||||
deleteDirectory(target);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (Exception e) {
|
||||
@ -979,6 +1002,29 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
//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
|
||||
@ -986,12 +1032,12 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
* 参数说明 zipName 解压以后的文件夹名称
|
||||
* 返回值说明: com.yfd.platform.config.ResponseResult 返回成功或者失败
|
||||
***********************************/
|
||||
public String documentUploadById(String id, String sourceFolderPath, String targetFolderPath,String value) throws Exception {
|
||||
public String documentUploadById(String id, String sourceFolderPath, String targetFolderPath, String value) throws Exception {
|
||||
|
||||
//源目录
|
||||
File sourceDir = new File(value + sourceFolderPath);
|
||||
//目标目录
|
||||
File targetDir = new File( value + targetFolderPath);
|
||||
File targetDir = new File(value + targetFolderPath);
|
||||
|
||||
if (!targetDir.exists()) {
|
||||
FileUtils.copyDirectory(sourceDir, targetDir);
|
||||
@ -1021,11 +1067,11 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
//如果存在 判断是文件夹还是文件 如果是文件夹 则继续递归
|
||||
if (fileItemResult.getType() == FileTypeEnum.FOLDER) {
|
||||
try {
|
||||
documentUploadById(id, fileItemResult.getPath() + "/" + fileItemResult.getName(), targetFileItem.getPath()+ "/" + targetFileItem.getName(),value);
|
||||
documentUploadById(id, fileItemResult.getPath() + "/" + fileItemResult.getName(), targetFileItem.getPath() + "/" + targetFileItem.getName(), value);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
if (fileItemResult.getType() == FileTypeEnum.FILE) {
|
||||
//源路径
|
||||
String sourcePath = value + sourceFolderPath + "/" + fileItemResult.getName();
|
||||
@ -1048,24 +1094,24 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
//更改目标路径下的文件名称
|
||||
renameFile(targetPath);
|
||||
//将源目录文件 复制到 目标目录文件
|
||||
copyWithOverride(sourcePath,targetPath);
|
||||
copyWithOverride(sourcePath, targetPath);
|
||||
|
||||
}else {
|
||||
} else {
|
||||
//将源目录文件 复制到 目标目录文件 todo这个地方是覆盖
|
||||
copyWithOverride(sourcePath,targetPath);
|
||||
copyWithOverride(sourcePath, targetPath);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}else{
|
||||
} else {
|
||||
//如果为空对象不存在 则直接拷贝
|
||||
String sourcePath = value + sourceFolderPath;
|
||||
//目标路径 就是源路径去掉/temporary的部分
|
||||
String targetPath = sourcePath.replace("/" + "temporary", "");
|
||||
String targetPath = sourcePath.replace("/" + "temporary", "");
|
||||
//将源目录文件 复制到 目标目录文件
|
||||
copyFolderWithOverride(sourcePath,targetPath);
|
||||
copyFolderWithOverride(sourcePath, targetPath);
|
||||
|
||||
}
|
||||
}
|
||||
@ -1082,7 +1128,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
projectLambdaQueryWrapper.eq(Project::getProjectName, projectName);
|
||||
Project project = projectMapper.selectOne(projectLambdaQueryWrapper);
|
||||
//如果项目不存在
|
||||
if(project == null){
|
||||
if (project == null) {
|
||||
String projectCode = this.generateNextProjectCode();
|
||||
project.setProjectCode("1");
|
||||
|
||||
@ -1108,8 +1154,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//获取文件列表
|
||||
String absolutePath = "/" + project.getProjectName() + "/";
|
||||
FileListRequest fileListRequest = buildFileRequest(absolutePath);
|
||||
@ -1138,8 +1182,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 编号生成工具方法
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public synchronized String generateNextProjectCode() {
|
||||
@ -1236,9 +1278,6 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//获取路径下的所有文件和文件夹
|
||||
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(
|
||||
java.nio.file.Files.newInputStream(sourcePath), StandardCharsets.UTF_8)) {
|
||||
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
ZipEntry entry = null;
|
||||
|
||||
while (true) { // 循环结构改为无限循环
|
||||
try {
|
||||
entry = zis.getNextEntry(); // 尝试获取下一个条目
|
||||
if (entry == null) {
|
||||
break; // 没有更多条目,退出循环
|
||||
}
|
||||
|
||||
// 打印当前处理的条目名称
|
||||
LOGGER.info("Processing ZIP entry: {}", entry.getName());
|
||||
|
||||
// 跳过 macOS 系统文件
|
||||
if (entry.getName().startsWith("__MACOSX")) {
|
||||
continue;
|
||||
@ -1347,7 +1395,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
// 标准化路径并处理目录标识
|
||||
String entryName = entry.getName()
|
||||
.replace("\\", "/")
|
||||
.replaceFirst("^/+", ""); // 去除开头的斜杠
|
||||
.replaceFirst("^/+", ""); // 去除开头的斜杠
|
||||
|
||||
// 检测是否为目录(兼容以'/'结尾的条目)
|
||||
boolean isDirectory = entry.isDirectory() || entry.getName().endsWith("/");
|
||||
@ -1364,16 +1412,15 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
}
|
||||
|
||||
Path targetPath = destRoot.resolve(entryName).normalize();
|
||||
validatePathSafetya(targetPath, destRoot);
|
||||
validatePathSafetya(targetPath, destRoot); // 确保路径安全
|
||||
|
||||
// 处理目录
|
||||
if (isDirectory) {
|
||||
java.nio.file.Files.createDirectories(targetPath);
|
||||
}
|
||||
// 处理文件
|
||||
else {
|
||||
} else {
|
||||
// 处理文件
|
||||
if (java.nio.file.Files.exists(targetPath)) {
|
||||
LOGGER.warn("文件已存在,跳过覆盖: {}", targetPath);
|
||||
LOGGER.warn("File already exists, skip overwriting: {}", targetPath);
|
||||
continue;
|
||||
}
|
||||
// 确保父目录存在
|
||||
@ -1382,8 +1429,17 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
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 {
|
||||
zis.closeEntry(); // 确保每个条目只关闭一次
|
||||
|
||||
if (entry != null) {
|
||||
zis.closeEntry(); // 关闭当前条目
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1391,6 +1447,7 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
|
||||
return destRoot.toFile();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 路径安全验证(增强版)
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user