From d4a44f3bf508134d568050487222a886c0a882af Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sun, 1 Feb 2026 21:18:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(data-management):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E7=9F=A5=E8=AF=86=E9=A1=B9=E7=9B=AE=E9=A2=84=E8=A7=88=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E7=9A=84=E6=96=87=E4=BB=B6=E8=BD=AC=E6=8D=A2=E9=80=BB?= =?UTF-8?q?=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除 docx4j 相关依赖和转换方法 - 统一 office 文件转换为 pdf 的处理方式,全部使用 libreoffice - 删除单独的 docx 到 pdf 转换方法 - 重命名转换方法为 convertOfficeToPdfByLibreOffice - 增强路径解析逻辑,添加多种候选路径处理 - 添加路径安全性验证和规范化处理 - 新增 extractRelativePathFromSegment 和 normalizeRelativePathValue 辅助方法 - 改进文件存在性检查和路径构建逻辑 --- .../KnowledgeItemPreviewAsyncService.java | 112 +++++++++++++++--- 1 file changed, 95 insertions(+), 17 deletions(-) diff --git a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewAsyncService.java b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewAsyncService.java index 94eb0fa..1ef33d8 100644 --- a/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewAsyncService.java +++ b/backend/services/data-management-service/src/main/java/com/datamate/datamanagement/application/KnowledgeItemPreviewAsyncService.java @@ -8,14 +8,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.docx4j.Docx4J; -import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -82,11 +79,7 @@ public class KnowledgeItemPreviewAsyncService { ensureParentDirectory(targetPath); try { - if ("docx".equals(extension)) { - convertDocxToPdf(sourcePath, targetPath); - } else { - convertDocToPdfByLibreOffice(sourcePath, targetPath); - } + convertOfficeToPdfByLibreOffice(sourcePath, targetPath); updatePreviewStatus(item, KnowledgeItemPreviewStatus.READY, previewRelativePath, null); } catch (Exception e) { log.error("preview convert failed, itemId: {}", item.getId(), e); @@ -94,14 +87,7 @@ public class KnowledgeItemPreviewAsyncService { } } - private void convertDocxToPdf(Path sourcePath, Path targetPath) throws Exception { - WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(sourcePath.toFile()); - try (OutputStream outputStream = Files.newOutputStream(targetPath)) { - Docx4J.toPDF(wordMLPackage, outputStream); - } - } - - private void convertDocToPdfByLibreOffice(Path sourcePath, Path targetPath) throws Exception { + private void convertOfficeToPdfByLibreOffice(Path sourcePath, Path targetPath) throws Exception { Path outputDir = targetPath.getParent(); ensureParentDirectory(targetPath); List command = List.of( @@ -234,8 +220,70 @@ public class KnowledgeItemPreviewAsyncService { } private Path resolveKnowledgeItemStoragePath(String relativePath) { - String normalizedRelativePath = StringUtils.defaultString(relativePath).replace("/", java.io.File.separator); + if (StringUtils.isBlank(relativePath)) { + throw new IllegalArgumentException("invalid knowledge item path"); + } + String normalizedInput = relativePath.replace("\\", PATH_SEPARATOR).trim(); Path root = resolveUploadRootPath(); + java.util.LinkedHashSet candidates = new java.util.LinkedHashSet<>(); + + Path inputPath = Paths.get(normalizedInput.replace(PATH_SEPARATOR, java.io.File.separator)); + if (inputPath.isAbsolute()) { + Path normalizedAbsolute = inputPath.toAbsolutePath().normalize(); + if (normalizedAbsolute.startsWith(root)) { + candidates.add(normalizedAbsolute); + } + String segmentRelativePath = extractRelativePathFromSegment(normalizedInput, KNOWLEDGE_ITEM_UPLOAD_DIR); + if (StringUtils.isNotBlank(segmentRelativePath)) { + candidates.add(buildKnowledgeItemStoragePath(root, segmentRelativePath)); + } + if (candidates.isEmpty()) { + throw new IllegalArgumentException("invalid knowledge item path"); + } + } else { + String normalizedRelative = normalizeRelativePathValue(normalizedInput); + if (StringUtils.isNotBlank(normalizedRelative)) { + candidates.add(buildKnowledgeItemStoragePath(root, normalizedRelative)); + } + String segmentRelativePath = extractRelativePathFromSegment(normalizedInput, KNOWLEDGE_ITEM_UPLOAD_DIR); + if (StringUtils.isNotBlank(segmentRelativePath)) { + candidates.add(buildKnowledgeItemStoragePath(root, segmentRelativePath)); + } + if (StringUtils.isNotBlank(normalizedRelative) + && !normalizedRelative.startsWith(KNOWLEDGE_ITEM_UPLOAD_DIR + PATH_SEPARATOR) + && !normalizedRelative.equals(KNOWLEDGE_ITEM_UPLOAD_DIR)) { + candidates.add(buildKnowledgeItemStoragePath(root, KNOWLEDGE_ITEM_UPLOAD_DIR + PATH_SEPARATOR + normalizedRelative)); + } + } + + if (root.getFileName() != null && KNOWLEDGE_ITEM_UPLOAD_DIR.equals(root.getFileName().toString())) { + String normalizedRelative = normalizeRelativePathValue(normalizedInput); + if (StringUtils.isNotBlank(normalizedRelative) + && normalizedRelative.startsWith(KNOWLEDGE_ITEM_UPLOAD_DIR + PATH_SEPARATOR)) { + String withoutPrefix = normalizedRelative.substring(KNOWLEDGE_ITEM_UPLOAD_DIR.length() + PATH_SEPARATOR.length()); + if (StringUtils.isNotBlank(withoutPrefix)) { + candidates.add(buildKnowledgeItemStoragePath(root, withoutPrefix)); + } + } + } + + Path fallback = null; + for (Path candidate : candidates) { + if (fallback == null) { + fallback = candidate; + } + if (Files.exists(candidate) && Files.isRegularFile(candidate)) { + return candidate; + } + } + if (fallback == null) { + throw new IllegalArgumentException("invalid knowledge item path"); + } + return fallback; + } + + private Path buildKnowledgeItemStoragePath(Path root, String relativePath) { + String normalizedRelativePath = StringUtils.defaultString(relativePath).replace(PATH_SEPARATOR, java.io.File.separator); Path target = root.resolve(normalizedRelativePath).toAbsolutePath().normalize(); if (!target.startsWith(root)) { throw new IllegalArgumentException("invalid knowledge item path"); @@ -243,6 +291,36 @@ public class KnowledgeItemPreviewAsyncService { return target; } + private String extractRelativePathFromSegment(String rawPath, String segment) { + if (StringUtils.isBlank(rawPath) || StringUtils.isBlank(segment)) { + return null; + } + String normalized = rawPath.replace("\\", PATH_SEPARATOR).trim(); + while (normalized.startsWith(PATH_SEPARATOR)) { + normalized = normalized.substring(1); + } + String segmentPrefix = segment + PATH_SEPARATOR; + int index = normalized.indexOf(segmentPrefix); + if (index < 0) { + return segment.equals(normalized) ? segment : null; + } + return normalizeRelativePathValue(normalized.substring(index)); + } + + private String normalizeRelativePathValue(String relativePath) { + if (StringUtils.isBlank(relativePath)) { + return ""; + } + String normalized = relativePath.replace("\\", PATH_SEPARATOR).trim(); + while (normalized.startsWith(PATH_SEPARATOR)) { + normalized = normalized.substring(1); + } + while (normalized.endsWith(PATH_SEPARATOR)) { + normalized = normalized.substring(0, normalized.length() - 1); + } + return normalized; + } + private Path resolveUploadRootPath() { String uploadDir = dataManagementProperties.getFileStorage().getUploadDir(); return Paths.get(uploadDir).toAbsolutePath().normalize();