解决报错
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
--- # 项目相关配置
|
||||
qingyun:
|
||||
# 项目根目录
|
||||
profile: ${root.directory}
|
||||
profile: /application/data/localUpload/carUpload
|
||||
# projectUrl: http://192.168.3.16:8081
|
||||
projectUrl: http://localhost:8099
|
||||
--- # 监控中心配置
|
||||
@@ -145,10 +144,10 @@ security:
|
||||
# - /actuator/**
|
||||
# 验证码
|
||||
- /**/captcha/**
|
||||
- /system/oss/uploadLocal
|
||||
- /api/service/reviewTask/**
|
||||
- /api/pdf/**
|
||||
- /api/service/compareTask/**
|
||||
- /application/data/system/oss/uploadLocal
|
||||
- /application/data/api/service/reviewTask/**
|
||||
- /application/data/api/pdf/**
|
||||
- /application/data/api/service/compareTask/**
|
||||
|
||||
# orc识别服务
|
||||
ocr:
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
--- # 项目相关配置
|
||||
qingyun:
|
||||
profile: /opt/workspace/localUpload/carUpload
|
||||
profile: /application/data/localUpload/carUpload
|
||||
# projectUrl: http://192.168.3.16:8081
|
||||
projectUrl: http://localhost:8099
|
||||
# projectUrl:
|
||||
--- # 临时文件存储位置 避免临时文件被系统清理报错
|
||||
spring.servlet.multipart.location: /qingyun/server/temp
|
||||
--- # 监控中心配置
|
||||
spring.boot.admin.client:
|
||||
# 增加客户端开关
|
||||
enabled: false
|
||||
url: http://localhost:9090/admin
|
||||
instance:
|
||||
service-host-type: IP
|
||||
username: qingyun
|
||||
password: 123456
|
||||
|
||||
|
||||
|
||||
--- # 数据源配置
|
||||
spring:
|
||||
@@ -13,7 +22,7 @@ spring:
|
||||
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
|
||||
dynamic:
|
||||
# 性能分析插件(有性能损耗 不建议生产环境使用)
|
||||
p6spy: false
|
||||
p6spy: true
|
||||
# 设置默认的数据源或者数据源组,默认值即为 master
|
||||
primary: master
|
||||
# 严格模式 匹配不到数据源则报错
|
||||
@@ -74,17 +83,17 @@ redisson:
|
||||
# redis key前缀
|
||||
keyPrefix:
|
||||
# 线程池数量
|
||||
threads: 16
|
||||
threads: 4
|
||||
# Netty线程池数量
|
||||
nettyThreads: 32
|
||||
nettyThreads: 8
|
||||
# 单节点配置
|
||||
singleServerConfig:
|
||||
# 客户端名称
|
||||
clientName: ${qingyun.name}
|
||||
# 最小空闲连接数
|
||||
connectionMinimumIdleSize: 32
|
||||
connectionMinimumIdleSize: 8
|
||||
# 连接池大小
|
||||
connectionPoolSize: 64
|
||||
connectionPoolSize: 32
|
||||
# 连接空闲超时,单位:毫秒
|
||||
idleConnectionTimeout: 10000
|
||||
# 命令等待超时,单位:毫秒
|
||||
@@ -95,7 +104,7 @@ redisson:
|
||||
springdoc:
|
||||
api-docs:
|
||||
# 是否开启接口文档
|
||||
enabled: false
|
||||
enabled: true
|
||||
swagger-ui:
|
||||
path: /doc.html
|
||||
# 持久化认证数据
|
||||
@@ -114,6 +123,7 @@ springdoc:
|
||||
- group: 4.合同业务管理
|
||||
packages-to-scan: com.qingyun.web.controller.api.contract
|
||||
|
||||
|
||||
# security配置
|
||||
security:
|
||||
# 排除路径
|
||||
@@ -126,13 +136,19 @@ security:
|
||||
# 公共路径
|
||||
- /favicon.ico
|
||||
- /error
|
||||
# swagger 文档配置
|
||||
- /*/api-docs
|
||||
- /*/api-docs/**
|
||||
# # actuator 监控配置
|
||||
# - /actuator
|
||||
# - /actuator/**
|
||||
# 验证码
|
||||
- /**/captcha/**
|
||||
- /system/oss/uploadLocal
|
||||
- /api/service/reviewTask/**
|
||||
- /api/pdf/**
|
||||
- /api/service/compareTask/**
|
||||
- /application/data/system/oss/uploadLocal
|
||||
- /application/data/api/service/reviewTask/**
|
||||
- /application/data/api/pdf/**
|
||||
- /application/data/api/service/compareTask/**
|
||||
|
||||
# orc识别服务
|
||||
ocr:
|
||||
url: http://10.77.149.156:8188/layout-parsing
|
||||
url: http://10.78.113.249:8080/layout-parsing
|
||||
|
||||
@@ -131,7 +131,7 @@ public class FileUploadUtils
|
||||
*/
|
||||
public static String extractFilename(MultipartFile file)
|
||||
{
|
||||
String fileName = file.getOriginalFilename();
|
||||
String fileName = FilenameUtils.getName(file.getOriginalFilename());
|
||||
String extension = getExtension(file);
|
||||
fileName = DateUtils.datePath() + "/" + IdUtil.fastUUID() + "/" + fileName;
|
||||
return fileName;
|
||||
|
||||
@@ -10,10 +10,12 @@ import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
/**
|
||||
* 策略工厂(根据文件类型选择策略)
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class FileComparisonStrategyFactory {
|
||||
|
||||
private final List<FileComparisonStrategy> strategies;
|
||||
@@ -36,12 +38,14 @@ public class FileComparisonStrategyFactory {
|
||||
String ext1 = getFileExtension(task.getFirstContractUrl());
|
||||
String ext2 = getFileExtension(task.getSecondContractUrl());
|
||||
|
||||
log.info("选择比对策略,扩展名: first={}, second={}", ext1, ext2);
|
||||
if (!ext1.equalsIgnoreCase(ext2)) {
|
||||
throw new ServiceException("两份文件类型不一致,无法对比");
|
||||
}
|
||||
|
||||
for (FileComparisonStrategy strategy : strategies) {
|
||||
if (strategy.supports(ext1)) {
|
||||
log.info("匹配到策略: {}", strategy.getClass().getSimpleName());
|
||||
return strategy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +212,14 @@ public class WordComparisonStrategy extends AbstractFileComparisonStrategy imple
|
||||
pdfFile = targetFile;
|
||||
}
|
||||
}
|
||||
// 校验目标PDF是否可读,提前捕获异常并提升错误可见性
|
||||
try (PDDocument doc = Loader.loadPDF(pdfFile)) {
|
||||
if (doc == null || doc.getNumberOfPages() <= 0) {
|
||||
throw new ServiceException("生成的PDF无法解析或页数为0");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("生成的PDF无法被PDFBox加载: " + e.getMessage());
|
||||
}
|
||||
// 更新合同URL为新的PDF文件路径
|
||||
String newUrl = "/profile/upload/" + needUploadName;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import com.documents4j.api.IConverter;
|
||||
import com.documents4j.job.LocalConverter;
|
||||
import com.qingyun.common.config.QingYunConfig;
|
||||
import com.qingyun.common.utils.file.FileUploadUtils;
|
||||
import com.qingyun.common.constant.Constants;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.pdfbox.Loader;
|
||||
@@ -19,6 +20,8 @@ import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -99,9 +102,37 @@ public class PdfUtil {
|
||||
String newName = name.substring(0, name.lastIndexOf("."));
|
||||
String projectUrl = QingYunConfig.getProjectUrl();
|
||||
File tempFile = File.createTempFile(newName + System.currentTimeMillis(), getFileExtension(name));
|
||||
long file = HttpUtil.downloadFile(projectUrl + pdfUrl, tempFile);
|
||||
if (file <= 0) {
|
||||
throw new IOException("无法下载 PDF 文件");
|
||||
|
||||
/**
|
||||
* 下载或本地复制文件到临时目录
|
||||
* - 当路径以 /profile 开头时,直接从容器本地文件系统复制,避免网关/反代造成的HTML错误页
|
||||
* - 否则通过 HTTP 下载
|
||||
*/
|
||||
if (pdfUrl != null && pdfUrl.startsWith(Constants.RESOURCE_PREFIX)) {
|
||||
String localPath = pdfUrl.replaceFirst(Constants.RESOURCE_PREFIX, QingYunConfig.getProfile());
|
||||
File source = new File(localPath);
|
||||
if (!source.exists() || !source.isFile()) {
|
||||
throw new IOException("本地文件不存在或无效: " + localPath);
|
||||
}
|
||||
Files.copy(source.toPath(), tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
} else {
|
||||
long size = HttpUtil.downloadFile(projectUrl + pdfUrl, tempFile);
|
||||
if (size <= 0) {
|
||||
throw new IOException("无法下载文件: " + projectUrl + pdfUrl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 若为PDF后缀,进行签名与解析预检测
|
||||
*/
|
||||
if (".pdf".equalsIgnoreCase(getFileExtension(name))) {
|
||||
try (PDDocument doc = Loader.loadPDF(tempFile)) {
|
||||
if (doc == null || doc.getNumberOfPages() <= 0) {
|
||||
throw new IOException("下载的PDF无法解析或页数为0");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("下载的PDF无法被PDFBox加载: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return tempFile;
|
||||
}
|
||||
@@ -126,6 +157,16 @@ public class PdfUtil {
|
||||
File outputFile = new File(wordFile.getParent(),
|
||||
FilenameUtils.getBaseName(wordFile.getName()) + ".pdf");
|
||||
|
||||
/**
|
||||
* 将 Word 文件转换为 PDF(Windows)
|
||||
* - 使用 documents4j 本地转换器进行格式转换
|
||||
* - 转换完成后进行健全性校验:文件存在、非空、可被 PDFBox 正常加载
|
||||
* - 若校验失败则抛出 IOException,避免后续流程在解析阶段失败
|
||||
*
|
||||
* @param wordFile 待转换的 Word 临时文件
|
||||
* @return 转换后的 PDF 文件对象
|
||||
* @throws IOException 当转换或校验失败时抛出
|
||||
*/
|
||||
try {
|
||||
IConverter converter = LocalConverter.builder().build();
|
||||
|
||||
@@ -134,7 +175,20 @@ public class PdfUtil {
|
||||
.to(outputFile).as(DocumentType.PDF)
|
||||
.prioritizeWith(1000) // optional
|
||||
.schedule();
|
||||
conversion.get(); // 这里会阻塞直到转换完成
|
||||
conversion.get(); // 阻塞直到转换完成
|
||||
|
||||
// 基础校验:文件存在且非空
|
||||
if (!outputFile.exists() || outputFile.length() == 0) {
|
||||
throw new IOException("PDF文件未生成或为空");
|
||||
}
|
||||
// 尝试用 PDFBox 打开以验证文件有效性
|
||||
try (PDDocument doc = Loader.loadPDF(outputFile)) {
|
||||
if (doc == null || doc.getNumberOfPages() <= 0) {
|
||||
throw new IOException("生成的PDF无法解析或页数为0");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOException("生成的PDF无法被PDFBox加载: " + e.getMessage(), e);
|
||||
}
|
||||
return outputFile;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user