org.springframework.web.multipart.MultipartException: Current request is not a multipart request 报错 @PostMapping(value = "/validate", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public List<ValidationResult> validateDocument(
@RequestPart("file") MultipartFile file, @RequestPart("expectedConfig") JsonNode expectedConfig) {
return param.validateImagePrecisely(file, expectedConfig);
}
我的接口 private final ObjectMapper objectMapper = new ObjectMapper();
private static final String BASE_URL = "http://10.191.39.243:8000/v1";
private static final String API_KEY = "Luxsan20250701";
private static final String MODEL_NAME = "/models/Qwen2.5-VL-72B-Instruct";
// 主验证方法
public List<ValidationResult> validateImagePrecisely(MultipartFile file, JsonNode expectedConfig) {
try {
String imageUrl = convertToBase64(file);
// 1. 调用大模型API获取OCR结果
String modelResponse =recognizeTextFromImage(imageUrl);
// 2. 解析API响应
JsonNode responseNode = objectMapper.readTree(modelResponse);
if (!responseNode.path("success").asBoolean()) {
String errorMsg = responseNode.path("message").asText();
log.error("OCR API调用失败: {}", errorMsg);
return Collections.singletonList(
new ValidationResult("SYSTEM", "API_ERROR", "API调用成功", "API调用失败: " + errorMsg, false)
);
}
// 3. 提取OCR结果
JsonNode actualData = responseNode.path("data").path("ocr_result");
log.info("OCR识别结果: {}", actualData.toPrettyString());
// 4. 执行精准比较
return preciseCompare(actualData, expectedConfig);
} catch (Exception e) {
log.error("验证过程异常: {}", e.getMessage(), e);
return Collections.singletonList(
new ValidationResult("SYSTEM", "EXCEPTION", "正常处理", "系统错误: " + e.getMessage(), false)
);
}
}
private String convertToBase64(MultipartFile file) throws IOException {
try (InputStream inputStream = file.getInputStream()) {
// 使用缓冲流提高读取效率
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, bytesRead);
}
buffer.flush();
return Base64.getEncoder().encodeToString(buffer.toByteArray());
}
}
// 精准字段比较
private List<ValidationResult> preciseCompare(JsonNode actualData, JsonNode expectedConfig) {
List<ValidationResult> results = new ArrayList<>();
// 遍历所有预期字段
expectedConfig.fields().forEachRemaining(entry -> {
String field = entry.getKey();
String expectedValue = entry.getValue().asText();
JsonNode actualNode = actualData.path(field);
if (actualNode.isMissingNode()) {
results.add(new ValidationResult("FIELD", field, expectedValue, "字段不存在", false));
return;
}
String actualValue = actualNode.asText();
boolean isValid = actualValue.equals(expectedValue);
results.add(new ValidationResult(
"FIELD", field, expectedValue,
actualValue,
isValid
));
});
return results;
}
public String recognizeTextFromImage(String imageUrl) throws IOException {
URL url = new URL(BASE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", "Bearer " + API_KEY);
connection.setRequestProperty("Content-Type", "application/json");
connection.setDoOutput(true);
// 2. 构建请求体
JSONObject requestBody = new JSONObject();
requestBody.put("model", MODEL_NAME);
JSONArray messages = new JSONArray();
JSONObject message = new JSONObject();
message.put("role", "user");
JSONArray content = new JSONArray();
// 文本指令
JSONObject textContent = new JSONObject();
textContent.put("type", "text");
textContent.put("text", "提取图片中的所有文本内容,并按照json格式输出");
content.put(textContent);
// 图像URL
JSONObject imageContent = new JSONObject();
imageContent.put("type", "image_url");
JSONObject imageUrlObj = new JSONObject();
imageUrlObj.put("url", imageUrl);
imageContent.put("image_url", imageUrlObj);
content.put(imageContent);
message.put("content", content);
messages.put(message);
requestBody.put("messages", messages);
// 3. 发送请求
try (OutputStream os = connection.getOutputStream()) {
byte[] input = requestBody.toString().getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 4. 获取响应
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
try (BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
StringBuilder response = new StringBuilder();
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
// 解析响应,提取模型返回的内容
JSONObject jsonResponse = new JSONObject(response.toString());
JSONArray choices = jsonResponse.getJSONArray("choices");
if (choices.length() > 0) {
JSONObject firstChoice = choices.getJSONObject(0);
JSONObject messageObj = firstChoice.getJSONObject("message");
return messageObj.getString("content");
} else {
throw new IOException("未获取到有效响应");
}
}
} else {
// 读取错误流
try (BufferedReader br = new BufferedReader(
new InputStreamReader(connection.getErrorStream(), StandardCharsets.UTF_8))) {
StringBuilder errorResponse = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
errorResponse.append(line);
}
throw new IOException("HTTP请求失败: " + responseCode + ", 错误信息: " + errorResponse.toString());
}
}
}我的方法 测试有问题 然而我这个接口和方法没有问题 @PostMapping(value = "/compare", produces = {MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE})
public R compare(@RequestPart("File") MultipartFile file, @RequestPart("jsonContent") String jsonContent) {
//读取PDF和图片内容
String pdfText = compareService.extractContent(file);
//解析JSON配置
JsonNode jsonConfig = null;
List<ValidationResult> results = new ArrayList<>();
try {
if (compareService.isPipeSeparatedData(jsonContent)) {
jsonConfig = compareService.parsePipeSeparatedDataToJson(jsonContent);
results = compareService.compareAndValidate(pdfText, jsonConfig);
} else {
jsonConfig = compareService.parseJson(jsonContent);
results = compareService.compareContent(pdfText, jsonConfig);
}
} catch (Exception e) {
return R.fail(MessageUtils.message("failed.convert.json"));
}
// 返回没有匹配成功的数据
List<ValidationResult> failedResults = new ArrayList<>();
for (ValidationResult result : results) {
if (!result.isValid()) {
failedResults.add(result);
}
}
return failedResults.isEmpty() ? R.ok("条件符合规范") : R.fail(failedResults);
}private final ObjectMapper objectMapper = new ObjectMapper();
private Tesseract tesseract;
@Value("${tesseract.datapath}")
private String tessDataPath;
/**
* ocr配置
*/
@PostConstruct
public void initOcrEngine() {
tesseract = new Tesseract();
//语言包路径和支持语言
tesseract.setDatapath(tessDataPath);
tesseract.setLanguage("eng+chi_sim");
tesseract.setPageSegMode(6); // 完全自动页面分割模式
tesseract.setOcrEngineMode(2); // LSTM引擎
}
static {
//OpenCV本地库
System.load("D:\\work\\OpenCV\\opencv\\build\\java\\x64\\opencv_java4120.dll");
}
/**
* 支持PDF读取文件和图片ocr
*/
public String extractContent(MultipartFile file) {
String contentType = file.getContentType();
String fileName = file.getOriginalFilename().toLowerCase();
log.info("模版识别:" + fileName);
if (contentType == null) {
return "不支持的文件类型: " + contentType;
}
if (fileName.endsWith(".pdf")) {
return readPdfText(file);
}
return extractImageText(file);
}
/**
* 读取PDF文本内容
*
* @param file
* @return
*/
public String readPdfText(MultipartFile file) {
try (PDDocument doc = PDDocument.load(file.getInputStream())) {
PDFTextStripper stripper = new PDFTextStripper();
String rawText = stripper.getText(doc);
System.out.println("pdf内容" + rawText);
return rawText.trim();
} catch (Exception e) {
return MessageUtils.message("file.read.pdf.error");
}
}
/**
* OCR识别图片内容
*/
private String extractImageText(MultipartFile file) {
try (InputStream is = file.getInputStream()) {
BufferedImage image = ImageIO.read(is);
if (image == null) {
return MessageUtils.message("Image.parsing.failed");
}
// BufferedImage bufferedImage = preprocessImage(image);
// String result = tesseract.doOCR(bufferedImage);
String result = tesseract.doOCR(image);
result = postProcess(result);
result = result.replaceAll("\\s+", " ").trim();
System.out.println("图片内容:\n" + result);
return result;
} catch (Exception e) {
e.printStackTrace();
return MessageUtils.message("file.read.picture.error");
}
}
private BufferedImage preprocessImage(BufferedImage original) {
try {
//转换为OpenCV Mat格式
Mat mat = bufferedImageToMat(original);
//灰度化
Mat gray = new Mat();
Imgproc.cvtColor(mat, gray, Imgproc.COLOR_BGR2GRAY);
//降噪处理
Mat blurred = new Mat();
Imgproc.GaussianBlur(gray, blurred, new Size(3, 3), 0);
Mat binary = new Mat();
Imgproc.threshold(blurred, binary, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);
//分离粘连字符
Mat kernel = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(1, 3));
Mat dilated = new Mat();
Imgproc.dilate(binary, dilated, kernel);
Mat eroded = new Mat();
Imgproc.erode(dilated, eroded, kernel);
//转BufferedImage
return matToBufferedImage(eroded);
} catch (Exception e) {
e.printStackTrace();
return original; // 出错时返回原图
}
}
// BufferedImage转OpenCV Mat
private Mat bufferedImageToMat(BufferedImage image) {
int type = BufferedImage.TYPE_3BYTE_BGR;
if (image.getType() != type) {
BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
convertedImage.getGraphics().drawImage(image, 0, 0, null);
image = convertedImage;
}
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
// 确保数据元素数量是通道数的整数倍
int expectedLength = mat.rows() * mat.cols() * mat.channels();
if (data.length != expectedLength) {
byte[] newData = new byte[expectedLength];
System.arraycopy(data, 0, newData, 0, Math.min(data.length, expectedLength));
data = newData;
}
mat.put(0, 0, data);
return mat;
}
// OpenCV Mat转BufferedImage
private BufferedImage matToBufferedImage(Mat mat) {
int type = BufferedImage.TYPE_BYTE_GRAY;
if (mat.channels() > 1) {
type = BufferedImage.TYPE_3BYTE_BGR;
}
byte[] data = new byte[mat.cols() * mat.rows() * (int) mat.elemSize()];
mat.get(0, 0, data);
BufferedImage image = new BufferedImage(mat.cols(), mat.rows(), type);
image.getRaster().setDataElements(0, 0, mat.cols(), mat.rows(), data);
return image;
}
private String postProcess(String result) {
result = result
.replace("scHas", "sch-as")
// .replace("(oczg spol s.r.0", "(cz) spol s.r.o.")
// .replace("zahradou 101", "zahradou 1018")
.replace("¢", "c")
.replace("(Shanghai)Co", "applecomputertrading(shanghai)coltd1249centuryavenuetower3,pudongnewdistrict,shanghai200122,china");
return result;
}
/**
* 解析json
*/
public JsonNode parseJson(String jsonContent) throws Exception {
return this.objectMapper.readTree(jsonContent);
}
/**
* 比较pdf读取内容和 ocr图片内容 比较校验
*
* @param pdfText
* @param jsonConfig
* @return
*/
public List<ValidationResult> compareContent(String pdfText, JsonNode jsonConfig) {
List<ValidationResult> results = new ArrayList<>();
//HanLP
List<String> hanlpText = HanLP.segment(pdfText).stream()
.map(term -> term.word.replaceAll("\\s+", "").toLowerCase())
.collect(Collectors.toList());
System.out.println("分词的效果:" + hanlpText);
//处理JSON结构对象/数组
JsonNode dataNode = jsonConfig.isArray() && jsonConfig.size() > 0
? jsonConfig.get(0)
: jsonConfig;
//遍历JSON
dataNode.fields().forEachRemaining(entry -> {
String key = entry.getKey();
String value = entry.getValue().asText();
List<String> hanlpJsonText = HanLP.segment(value).stream()
.map(term -> term.word.replaceAll("\\s+", "").toLowerCase())
.collect(Collectors.toList());
if (!hanlpJsonText.isEmpty()) {
boolean found = isMatch(hanlpText, hanlpJsonText);
if (found) {
log.info("字段对比成功:{}", hanlpJsonText);
} else {
log.info("字段对比失败:{}", hanlpJsonText);
}
results.add(new ValidationResult(
"FIELD",
key,
String.join("", hanlpJsonText),
found ? "Found" : "Not Found",
found
));
}
});
return results;
}
/**
* 转为json结构
*
* @param inputData
* @return
* @throws Exception
*/
public JsonNode parsePipeSeparatedDataToJson(String inputData) throws Exception {
Map<String, String> dataMap = parsePipeSeparatedData(inputData);
return objectMapper.valueToTree(dataMap);
}
/**
* 解析分隔数据
*/
public Map<String, String> parsePipeSeparatedData(String fileCONTENT) {
//处理转义的换行符
fileCONTENT = fileCONTENT.replace("\\n", "\n").replaceAll("\\|+\"$", "").trim();
Map<String, String> dataMap = new LinkedHashMap<>();
String[] lines = fileCONTENT.split("\n");
if (lines.length >= 2) {
String[] headers = lines[0].split("\\|");
String[] values = lines[1].split("\\|");
int minLength = Math.min(headers.length, values.length);
for (int i = 0; i < minLength; i++) {
dataMap.put(headers[i], values[i]);
}
}
return dataMap;
}
public boolean isPipeSeparatedData(String inputData) {
return inputData.contains("|");
}
/**
* 比较和校验数据
*/
public List<ValidationResult> compareAndValidate(String fileContent, JsonNode jsonConfig) {
List<ValidationResult> results = new ArrayList<>();
// 处理 JSON 结构对象/数组
JsonNode dataNode = jsonConfig.isArray() && jsonConfig.size() > 0
? jsonConfig.get(0)
: jsonConfig;
// HanLP文本分词
List<String> hanlpTest = HanLP.segment(fileContent).stream()
.map(term -> term.word.replaceAll("\\s+", "").toLowerCase())
.collect(Collectors.toList());
System.out.println("分词的效果:" + hanlpTest);
// 遍历JSON
dataNode.fields().forEachRemaining(entry -> {
String key = entry.getKey();
String value = entry.getValue().asText();
List<String> hanlpJsonTest = HanLP.segment(value).stream()
.map(term -> term.word.replaceAll("\\s+", "").toLowerCase())
.collect(Collectors.toList());
if (!hanlpJsonTest.isEmpty()) {
boolean found = isMatch(hanlpTest, hanlpJsonTest);
if (found) {
log.info("字段对比成功:{}", hanlpJsonTest);
} else {
log.info("字段对比失败:{}", hanlpJsonTest);
}
results.add(new ValidationResult(
"FIELD",
key,
String.join("", hanlpJsonTest),
found ? "Found" : "Not Found",
found
));
}
});
return results;
}
private boolean isMatch(List<String> test, List<String> valueTokens) {
String Joined = String.join("", test);
String valueJoined = String.join("", valueTokens);
return Joined.contains(valueJoined);
}
最新发布