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();