优化专项文档上传

This commit is contained in:
lilin 2025-06-10 10:38:20 +08:00
parent 7eccb66643
commit 338fbee1ff

View File

@ -1110,71 +1110,165 @@ public class NodesServiceImpl extends ServiceImpl<NodesMapper, Nodes> implements
@Override
@Async("asyncExecutor")
public void documentUploadByIdAsync(String id, String fileName, LoginUser loginuser) throws IOException {
// 生成唯一Key提前到方法开头确保异常时也能标记完成
final String asyncKey = taskStatusHolder.documentUploadKey(id);
Path destRootPath = null;
File targetZip = null;
File targetDir = null;
try {
// 1. 优化合并重复的异常捕获
//------------------------------------------
// 查询存储配置
StorageSourceConfig config = getStorageConfig();
if (config == null) throw new RuntimeException("未找到本地存储路径配置");
// 查询本地文件路径根目录 E:\yun
QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("name", "filePath");
queryWrapper.eq("type", "sdlocal");
StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//解压以后的文件夹名称
String zipName = getFileNameWithoutExtension(fileName); // 示例222
//查询项目信息
// 优化提前验证项目存在性避免后续无效操作
Project project = projectMapper.selectById(id);
if (project == null) throw new RuntimeException("项目不存在: " + id);
// 优化解压路径统一构建逻辑
final String tempDir = "temporary";
final String zipName = getFileNameWithoutExtension(fileName);
// 验证压缩包名称匹配
if (!project.getProjectName().equals(zipName)) {
throw new RuntimeException("压缩包名称需要和项目名称保持一致");
throw new RuntimeException("压缩包名称[" + zipName + "]需与项目名称[" + project.getProjectName() + "]保持一致");
}
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);
// 2. 优化路径构建使用统一变量
//------------------------------------------
Path zipFilePath = Paths.get(config.getValue(), tempDir, fileName);
Path destRoot = Paths.get(config.getValue(), tempDir);
destRootPath = Paths.get(config.getValue(), tempDir, zipName); // 记录后续清理路径
targetZip = zipFilePath.toFile();
targetDir = destRootPath.toFile();
LOGGER.info("要解压文件路径:{}", zipFilePath);
LOGGER.info("解压以后文件路径:{}", destRoot);
LOGGER.info("解压源文件: {} => 目标目录: {}", zipFilePath, destRoot);
//todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描
//源文件夹路径
String sourceFolderPath = "/" + "temporary" + "/" + zipName + "/";
//目标文件夹路径
String targetFolderPath = "/" + project.getProjectName() + "/";
//首先执行解压缩
unzipToTemp(zipFilePath, String.valueOf(destRoot));
// 执行上传并且插入数据库
this.documentUploadById(id, sourceFolderPath, targetFolderPath, storageSourceConfig.getValue());
//开始执行更新表数据 名称是去掉后缀以后的
// 3. 优化解压和文件操作分离
//------------------------------------------
unzipToTemp(zipFilePath, destRoot.toString());
transferProjectFiles(id, config.getValue(), zipName, project.getProjectName());
uploadProject(zipName, loginuser);
LOGGER.info("开始更新表数据:{}", zipName);
LOGGER.info("项目数据更新完成: {}", zipName);
//获取文件路径
Path destRootPath = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
File targetZip = new File(String.valueOf(zipFilePath));
File target = new File(String.valueOf(destRootPath));
//删除临时文件ZIP
deleteDirectory(targetZip);
//删除临时文件
deleteDirectory(target);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (Exception e) {
// 优化统一异常处理原有两个catch合并
LOGGER.error("文档上传失败: {}", e.getMessage(), e);
throw new RuntimeException(e);
} finally {
// 生成唯一Key
String asyncKey = taskStatusHolder.documentUploadKey(id);
// 无论成功失败都标记完成
// 4. 关键优化确保资源清理无论成功失败都执行
//------------------------------------------
cleanupTempResources(targetZip, targetDir);
// 标记任务完成确保任何情况下都会执行
taskStatusHolder.finishTask(asyncKey);
WebSocketServer.sendMessageTo("专项文档上传任务处理完成!", "projectId_" + id);
}
}
// 新增辅助方法解耦核心逻辑 --------------------------------------------------
private StorageSourceConfig getStorageConfig() {
QueryWrapper<StorageSourceConfig> wrapper = new QueryWrapper<>();
wrapper.eq("name", "filePath").eq("type", "sdlocal");
return storageSourceConfigMapper.selectOne(wrapper);
}
private void transferProjectFiles(String projectId, String basePath, String sourceDir, String targetDir) throws Exception {
String sourcePath = "/temporary/" + sourceDir + "/";
String targetPath = "/" + targetDir + "/";
documentUploadById(projectId, sourcePath, targetPath, basePath);
}
// 关键优化独立的资源清理方法确保异常时仍能执行清理
private void cleanupTempResources(File zipFile, File tempDir) {
try {
if (zipFile != null && zipFile.exists()) {
deleteDirectory(zipFile); // 删除临时ZIP
LOGGER.debug("清理临时ZIP: {}", zipFile.getAbsolutePath());
}
if (tempDir != null && tempDir.exists()) {
deleteDirectory(tempDir); // 删除解压目录
LOGGER.debug("清理临时目录: {}", tempDir.getAbsolutePath());
}
} catch (Exception e) {
LOGGER.warn("临时资源清理失败", e); // 不阻断主流程
}
}
// public void documentUploadByIdAsync(String id, String fileName, LoginUser loginuser) throws IOException {
// try {
//
// // 查询本地文件路径根目录 E:\yun
// QueryWrapper<StorageSourceConfig> queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("name", "filePath");
// queryWrapper.eq("type", "sdlocal");
// StorageSourceConfig storageSourceConfig = storageSourceConfigMapper.selectOne(queryWrapper);
//
// if (storageSourceConfig == null) {
// throw new RuntimeException("未找到本地存储路径配置");
// }
//
// //解压以后的文件夹名称
// String zipName = getFileNameWithoutExtension(fileName); // 示例222
//
// //查询项目信息
// Project project = projectMapper.selectById(id);
// if (project == null) {
// throw new RuntimeException("项目不存在");
// }
//
// 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);
//
// LOGGER.info("要解压文件路径:{}", zipFilePath);
// LOGGER.info("解压以后文件路径:{}", destRoot);
//
//
// //todo 如果项目不存在 直接拷贝到目标路径下 拷贝完成以后 然后新增一个项目结构 然后走一遍扫描
//
// //源文件夹路径
// String sourceFolderPath = "/" + "temporary" + "/" + zipName + "/";
// //目标文件夹路径
// String targetFolderPath = "/" + project.getProjectName() + "/";
//
// //首先执行解压缩
// unzipToTemp(zipFilePath, String.valueOf(destRoot));
// // 执行上传并且插入数据库
// this.documentUploadById(id, sourceFolderPath, targetFolderPath, storageSourceConfig.getValue());
// //开始执行更新表数据 名称是去掉后缀以后的
// uploadProject(zipName, loginuser);
// LOGGER.info("开始更新表数据:{}", zipName);
//
// //获取文件路径
// Path destRootPath = Paths.get(storageSourceConfig.getValue(), decompressionPath, zipName);
// File targetZip = new File(String.valueOf(zipFilePath));
// File target = new File(String.valueOf(destRootPath));
// //删除临时文件ZIP
// deleteDirectory(targetZip);
// //删除临时文件
// deleteDirectory(target);
// } catch (IOException e) {
// throw new RuntimeException(e);
// } catch (Exception e) {
// throw new RuntimeException(e);
// } finally {
// // 生成唯一Key
// String asyncKey = taskStatusHolder.documentUploadKey(id);
// // 无论成功失败都标记完成
// taskStatusHolder.finishTask(asyncKey);
// WebSocketServer.sendMessageTo("专项文档上传任务处理完成!", "projectId_" + id);
//
// }
// }
public static void deleteDirectory(File directory) throws Exception {
if (!directory.exists()) {