This commit is contained in:
2025-10-27 13:47:03 +08:00
parent 8e5774955d
commit 135cc18c4e
5 changed files with 514 additions and 475 deletions

View File

@@ -0,0 +1,51 @@
package com.point.strategy.common;
import java.io.File;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class FileNameComparator implements Comparator<String> {
private static final Pattern NUMBER_PATTERN = Pattern.compile("(\\d+)");
@Override
public int compare(String s1, String s2) {
String name1 = new File(s1).getName();
String name2 = new File(s2).getName();
Matcher m1 = NUMBER_PATTERN.matcher(name1);
Matcher m2 = NUMBER_PATTERN.matcher(name2);
int pos1 = 0, pos2 = 0;
while (m1.find() && m2.find()) {
// 比较数字前的字符串部分
String prefix1 = name1.substring(pos1, m1.start());
String prefix2 = name2.substring(pos2, m2.start());
int prefixCompare = prefix1.compareTo(prefix2);
if (prefixCompare != 0) {
return prefixCompare;
}
// 比较数字部分(按数值比较)
Long num1 = Long.parseLong(m1.group());
Long num2 = Long.parseLong(m2.group());
int numCompare = num1.compareTo(num2);
if (numCompare != 0) {
return numCompare;
}
pos1 = m1.end();
pos2 = m2.end();
}
// 比较剩余部分
String suffix1 = name1.substring(pos1);
String suffix2 = name2.substring(pos2);
return suffix1.compareTo(suffix2);
}
}

View File

@@ -1,5 +1,6 @@
package com.point.strategy.common;
import org.ofdrw.converter.ConvertHelper;
import org.ofdrw.converter.export.PDFExporterPDFBox;
import java.nio.file.Paths;
@@ -16,12 +17,10 @@ public class OfdToPdfUtil {
public static void ofdToPdf(String resourceFilePath, String targetFilePath){
try {
// 按照OFD导出器的标准模式使用
PDFExporterPDFBox exporter = new PDFExporterPDFBox(
Paths.get(resourceFilePath),
Paths.get(targetFilePath)
ConvertHelper.toPdf(
Paths.get(resourceFilePath),
Paths.get(targetFilePath)
);
exporter.export();
exporter.close();
} catch (Exception e) {
throw new RuntimeException("OFD转PDF失败: " + e.getMessage(), e);
}

View File

@@ -20,9 +20,11 @@ import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;
@Slf4j
public class PdfFileHelper {
@@ -390,7 +392,17 @@ public class PdfFileHelper {
return false;
}
}
Arrays.sort(fileArray);
// 按文件名中的数字片段正序排序(如 xxx.001.pdf, xxx.002.pdf
try {
log.info("mergePdf 接收到 {} 个PDF按文件名数字片段正序合并。", (fileArray == null ? 0 : fileArray.length));
if (fileArray != null) {
Arrays.sort(fileArray, new FileNameComparator());
for (int idx = 0; idx < fileArray.length; idx++) {
log.info("排序后合并顺序 {} -> {}", idx + 1, fileArray[idx]);
}
}
} catch (Exception ignore) {
}
Document document = null;
PdfCopy pdfCopy = null;
try {
@@ -768,6 +780,172 @@ public class PdfFileHelper {
mergePdf(fileArray, tarFile);
}
public static boolean mergeOfdAndPdf(String[] sourceFiles, String targetFile, String tempDir) {
if (sourceFiles == null || sourceFiles.length == 0) {
log.warn("输入文件数组为空");
return true;
}
Path tempPath = Paths.get(tempDir);
try {
if (!Files.exists(tempPath)) {
Files.createDirectories(tempPath);
}
} catch (Exception e) {
log.error("创建临时目录失败: {}", tempDir, e);
return false;
}
List<String> pdfFiles = new ArrayList<>();
List<String> tempFilesToDelete = new ArrayList<>();
try {
// 不在此处改变顺序,保持调用方传入顺序(调用方如需排序,请在外部完成)
try {
log.info("mergeOfdAndPdf 接收到 {} 个源文件(保持传入顺序)", (sourceFiles == null ? 0 : sourceFiles.length));
if (sourceFiles != null) {
for (int i = 0; i < sourceFiles.length; i++) {
log.info("顺序 {} -> {}", i + 1, sourceFiles[i]);
}
}
} catch (Exception ignore) {}
for (String filePath : sourceFiles) {
if (filePath == null || filePath.trim().isEmpty()) {
continue;
}
String lowerPath = filePath.toLowerCase();
if (lowerPath.endsWith(".pdf")) {
pdfFiles.add(filePath);
} else if (lowerPath.endsWith(".ofd")) {
// 将 OFD 转换后的 PDF 命名为原始文件名.pdf而非 UUID保证排序与可读性
String originalName = new File(filePath).getName();
String baseName = originalName.endsWith(".ofd") ? originalName.substring(0, originalName.length() - 4) : originalName;
// 简单清洗,防止异常字符
// 仅保留字母、数字、下划线、点和连字符,其他替换为下划线
String sanitized = baseName.replaceAll("[^\\w.-]+", "_");
Path outPath = Paths.get(tempDir, sanitized + ".pdf");
int suffix = 1;
while (Files.exists(outPath)) {
outPath = Paths.get(tempDir, sanitized + "(" + (suffix++) + ").pdf");
}
String tempPdfPath = outPath.toString();
try {
OfdToPdfUtil.ofdToPdf(filePath, tempPdfPath);
pdfFiles.add(tempPdfPath);
tempFilesToDelete.add(tempPdfPath);
log.info("OFD转换成功: {} -> {}", filePath, tempPdfPath);
} catch (Exception e) {
log.error("OFD转换失败: {}", filePath, e);
}
} else {
log.warn("不支持的文件格式: {}", filePath);
}
}
if (pdfFiles.isEmpty()) {
log.warn("没有可合并的PDF文件");
return false;
}
try {
log.info("最终参与合并的PDF顺序已按源文件名排序共 {} 个:", pdfFiles.size());
for (int i = 0; i < pdfFiles.size(); i++) {
log.info("合并顺序 {} -> {}", i + 1, pdfFiles.get(i));
}
} catch (Exception ignore) {}
boolean mergeSuccess = mergePdfFiles(
pdfFiles.toArray(new String[0]),
targetFile
);
return mergeSuccess;
} finally {
cleanupTempFiles(tempFilesToDelete);
}
}
/**
* 合并PDF文件(改进版)
*/
private static boolean mergePdfFiles(String[] fileArray, String targetFile) {
// 删除已存在的目标文件
File target = new File(targetFile);
if (target.exists() && !target.delete()) {
log.error("无法删除已存在的目标文件: {}", targetFile);
return false;
}
Document document = null;
PdfCopy pdfCopy = null;
try {
document = new Document();
pdfCopy = new PdfCopy(document, new FileOutputStream(targetFile));
document.open();
int successCount = 0;
int totalPages = 0;
try {
log.info("mergePdfFiles 将合并 {} 个PDF按如下顺序", (fileArray == null ? 0 : fileArray.length));
if (fileArray != null) {
for (int i = 0; i < fileArray.length; i++) {
log.info("合并顺序 {} -> {}", i + 1, fileArray[i]);
}
}
} catch (Exception ignore) {}
for (String filePath : fileArray) {
PdfReader reader = null;
try {
reader = new PdfReader(filePath);
int pages = reader.getNumberOfPages();
// 逐页添加
for (int i = 1; i <= pages; i++) {
pdfCopy.addPage(pdfCopy.getImportedPage(reader, i));
}
totalPages += pages;
successCount++;
log.info("已合并文件: {} ({}页)", filePath, pages);
} catch (Exception e) {
log.error("处理文件失败: {}", filePath, e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
log.warn("关闭reader失败", e);
}
}
}
}
log.info("合并完成: {}/{} 个文件, 共{}页",
successCount, fileArray.length, totalPages);
return successCount > 0;
} catch (Exception e) {
log.error("合并PDF失败", e);
return false;
} finally {
if (document != null && document.isOpen()) {
document.close();
}
}
}
/**
* 清理临时文件
*/
private static void cleanupTempFiles(List<String> tempFiles) {
for (String tempFile : tempFiles) {
try {
Files.deleteIfExists(Paths.get(tempFile));
log.debug("删除临时文件: {}", tempFile);
} catch (Exception e) {
log.warn("删除临时文件失败: {}", tempFile, e);
}
}
}
}

View File

@@ -202,6 +202,7 @@ public class UreportService {
String tarFile = pathName + File.separator+ currentName + ".pdf";
PdfFileHelper.mergePdf(arr, tarFile);
}
}else{
//不是封面pdf