✨ 客商档案营业执照OCR改接第三方businessLicense接口
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+54
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.pojo.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 营业执照 OCR 识别结果。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "营业执照OCR识别结果")
|
||||
public class BusinessLicenseOcrVO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 按第三方返回 key 聚合的字段,例如 uscc、company_name、legal_name。
|
||||
*/
|
||||
@Schema(description = "识别字段,键为第三方 OCR 的 key")
|
||||
private Map<String, String> fields = new LinkedHashMap<>();
|
||||
|
||||
}
|
||||
+17
@@ -36,7 +36,9 @@ import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.transport.ocr.constant.BaiduOcrType;
|
||||
import org.springblade.transport.ocr.service.IBaiduOcrService;
|
||||
import org.springblade.transport.ocr.service.IBusinessLicenseOcrService;
|
||||
import org.springblade.transport.pojo.vo.BaiduOcrResultVO;
|
||||
import org.springblade.transport.pojo.vo.BusinessLicenseOcrVO;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -60,6 +62,7 @@ import java.io.IOException;
|
||||
public class BaiduOcrController extends BladeController {
|
||||
|
||||
private final IBaiduOcrService baiduOcrService;
|
||||
private final IBusinessLicenseOcrService businessLicenseOcrService;
|
||||
|
||||
/**
|
||||
* 识别上传的图片。
|
||||
@@ -109,6 +112,20 @@ public class BaiduOcrController extends BladeController {
|
||||
return R.data(baiduOcrService.recognizeUrl(resolveType(type), side, imageUrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* 营业执照图片地址识别(第三方 /businessLicense)。
|
||||
*
|
||||
* @param imageUrl 图片地址
|
||||
* @return 识别结果
|
||||
*/
|
||||
@PostMapping("/business-license")
|
||||
@ApiOperationSupport(order = 3)
|
||||
@Operation(summary = "营业执照OCR识别", description = "按图片地址调用第三方营业执照识别接口")
|
||||
public R<BusinessLicenseOcrVO> recognizeBusinessLicense(
|
||||
@Parameter(description = "图片地址", required = true) @RequestParam String imageUrl) {
|
||||
return R.data(businessLicenseOcrService.recognizeUrl(imageUrl));
|
||||
}
|
||||
|
||||
private BaiduOcrType resolveType(String type) {
|
||||
try {
|
||||
return BaiduOcrType.from(type);
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.ocr.service;
|
||||
|
||||
import org.springblade.transport.pojo.vo.BusinessLicenseOcrVO;
|
||||
|
||||
/**
|
||||
* 营业执照 OCR 服务。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface IBusinessLicenseOcrService {
|
||||
|
||||
/**
|
||||
* 根据图片地址识别营业执照。
|
||||
*
|
||||
* @param imageUrl 图片地址
|
||||
* @return 识别结果
|
||||
*/
|
||||
BusinessLicenseOcrVO recognizeUrl(String imageUrl);
|
||||
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.transport.ocr.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.exception.ServiceException;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.transport.ocr.service.IBusinessLicenseOcrService;
|
||||
import org.springblade.transport.pojo.vo.BusinessLicenseOcrVO;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 营业执照 OCR 服务实现,调用第三方 /businessLicense 接口。
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class BusinessLicenseOcrServiceImpl implements IBusinessLicenseOcrService {
|
||||
|
||||
private static final String PATH = "/businessLicense";
|
||||
private static final String DATA_TYPE_URL = "url";
|
||||
private static final int SUCCESS_CODE = 0;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
private final HttpClient httpClient;
|
||||
|
||||
/**
|
||||
* 营业执照 OCR 服务地址,Nacos:thirdParty.ocr.businessLicenseBaseUrl
|
||||
*/
|
||||
@Value("${thirdParty.ocr.businessLicenseBaseUrl:http://124.71.22.123:8888}")
|
||||
private String businessLicenseBaseUrl;
|
||||
|
||||
public BusinessLicenseOcrServiceImpl(ObjectMapper objectMapper,
|
||||
@Qualifier("baiduOcrHttpClient") HttpClient httpClient) {
|
||||
this.objectMapper = objectMapper;
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BusinessLicenseOcrVO recognizeUrl(String imageUrl) {
|
||||
if (StringUtil.isBlank(imageUrl)) {
|
||||
throw new ServiceException("OCR图片地址不能为空");
|
||||
}
|
||||
String normalizedUrl = imageUrl.trim();
|
||||
validateImageUrl(normalizedUrl);
|
||||
if (StringUtil.isBlank(businessLicenseBaseUrl)) {
|
||||
throw new ServiceException("营业执照OCR服务地址未配置(thirdParty.ocr.businessLicenseBaseUrl)");
|
||||
}
|
||||
String requestUrl = businessLicenseBaseUrl.replaceAll("/+$", "") + PATH;
|
||||
Map<String, String> body = new LinkedHashMap<>();
|
||||
body.put("img_path", normalizedUrl);
|
||||
body.put("data_type", DATA_TYPE_URL);
|
||||
JsonNode response = sendRequest(requestUrl, body);
|
||||
int code = response.path("code").asInt(Integer.MIN_VALUE);
|
||||
if (code != SUCCESS_CODE) {
|
||||
String message = firstNonBlank(response.path("msg").asText(null), response.path("message").asText(null), "未知错误");
|
||||
log.warn("营业执照OCR识别失败,code={},msg={},imageUrl={}", code, message, normalizedUrl);
|
||||
throw new ServiceException("营业执照OCR识别失败:" + message);
|
||||
}
|
||||
BusinessLicenseOcrVO result = new BusinessLicenseOcrVO();
|
||||
result.setFields(extractFields(response.path("data")));
|
||||
return result;
|
||||
}
|
||||
|
||||
private JsonNode sendRequest(String requestUrl, Map<String, String> body) {
|
||||
try {
|
||||
String jsonBody = objectMapper.writeValueAsString(body);
|
||||
HttpRequest request = HttpRequest.newBuilder(URI.create(requestUrl))
|
||||
.timeout(Duration.ofSeconds(60))
|
||||
.header("Content-Type", "application/json")
|
||||
.header("Accept", "application/json")
|
||||
.POST(HttpRequest.BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
|
||||
.build();
|
||||
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
if (response.statusCode() < 200 || response.statusCode() >= 300) {
|
||||
log.error("营业执照OCR接口响应异常,status={},url={}", response.statusCode(), requestUrl);
|
||||
throw new ServiceException("营业执照OCR接口调用失败,HTTP状态码:" + response.statusCode());
|
||||
}
|
||||
JsonNode result = objectMapper.readTree(response.body());
|
||||
if (result == null || !result.isObject()) {
|
||||
throw new ServiceException("营业执照OCR响应格式异常");
|
||||
}
|
||||
return result;
|
||||
} catch (ServiceException exception) {
|
||||
throw exception;
|
||||
} catch (InterruptedException exception) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.error("调用营业执照OCR接口被中断,url={}", requestUrl, exception);
|
||||
throw new ServiceException("营业执照OCR接口调用被中断");
|
||||
} catch (IllegalArgumentException exception) {
|
||||
log.error("营业执照OCR接口地址配置不正确,url={}", requestUrl);
|
||||
throw new ServiceException("营业执照OCR接口地址配置不正确");
|
||||
} catch (IOException exception) {
|
||||
log.error("调用营业执照OCR接口失败,url={}", requestUrl, exception);
|
||||
throw new ServiceException("营业执照OCR接口调用失败");
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> extractFields(JsonNode dataNode) {
|
||||
Map<String, String> fields = new LinkedHashMap<>();
|
||||
if (dataNode == null || !dataNode.isArray()) {
|
||||
return fields;
|
||||
}
|
||||
for (JsonNode item : dataNode) {
|
||||
if (item == null || !item.isObject()) {
|
||||
continue;
|
||||
}
|
||||
String key = item.path("key").asText(null);
|
||||
String value = item.path("value").asText(null);
|
||||
if (StringUtil.isBlank(key) || value == null) {
|
||||
continue;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
if (StringUtil.isBlank(trimmed)) {
|
||||
continue;
|
||||
}
|
||||
fields.put(key.trim(), trimmed);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
private void validateImageUrl(String imageUrl) {
|
||||
if (imageUrl.getBytes(StandardCharsets.UTF_8).length > 1024) {
|
||||
throw new ServiceException("OCR图片地址长度不能超过1024字节");
|
||||
}
|
||||
try {
|
||||
URI imageUri = URI.create(imageUrl);
|
||||
String scheme = imageUri.getScheme();
|
||||
if (StringUtil.isBlank(scheme) || StringUtil.isBlank(imageUri.getHost())
|
||||
|| imageUri.getUserInfo() != null
|
||||
|| !("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme))) {
|
||||
throw new ServiceException("OCR图片地址必须是有效的HTTP或HTTPS地址");
|
||||
}
|
||||
} catch (IllegalArgumentException exception) {
|
||||
throw new ServiceException("OCR图片地址格式不正确");
|
||||
}
|
||||
}
|
||||
|
||||
private String firstNonBlank(String... values) {
|
||||
if (values == null) {
|
||||
return null;
|
||||
}
|
||||
for (String value : values) {
|
||||
if (StringUtil.isNotBlank(value)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -96,6 +96,8 @@ thirdParty:
|
||||
baseOtherUrl: http://127.0.0.1:8080
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: http://124.71.22.123:8500
|
||||
# 营业执照 OCR 服务地址(POST /businessLicense,JSON:img_path、data_type)
|
||||
businessLicenseBaseUrl: http://124.71.22.123:8888
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
|
||||
@@ -58,6 +58,8 @@ thirdParty:
|
||||
baseOtherUrl: http://127.0.0.1:8080
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: http://124.71.22.123:8500
|
||||
# 营业执照 OCR 服务地址(POST /businessLicense,JSON:img_path、data_type)
|
||||
businessLicenseBaseUrl: http://124.71.22.123:8888
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: http://127.0.0.1:8080
|
||||
|
||||
@@ -7,6 +7,8 @@ thirdParty:
|
||||
baseOtherUrl: ${OCR_BASE_OTHER_URL:http://127.0.0.1:8080}
|
||||
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||
idCardBaseUrl: ${OCR_ID_CARD_BASE_URL:http://124.71.22.123:8500}
|
||||
# 营业执照 OCR 服务地址(POST /businessLicense,JSON:img_path、data_type)
|
||||
businessLicenseBaseUrl: ${OCR_BUSINESS_LICENSE_BASE_URL:http://124.71.22.123:8888}
|
||||
wps:
|
||||
# WPS开放接口地址
|
||||
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
||||
|
||||
Reference in New Issue
Block a user