✨ 身份证OCR改接ShenFenZheng,回填有效期与长期有效
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+3
@@ -418,6 +418,9 @@ public class DriverServiceImpl extends BaseServiceImpl<DriverMapper, Driver> imp
|
|||||||
driver.setDrivingLicenseBack(trimToNull(driver.getDrivingLicenseBack()));
|
driver.setDrivingLicenseBack(trimToNull(driver.getDrivingLicenseBack()));
|
||||||
driver.setQualificationFront(trimToNull(driver.getQualificationFront()));
|
driver.setQualificationFront(trimToNull(driver.getQualificationFront()));
|
||||||
driver.setQualificationBack(trimToNull(driver.getQualificationBack()));
|
driver.setQualificationBack(trimToNull(driver.getQualificationBack()));
|
||||||
|
if (driver.getIdCardLongTerm() == null) {
|
||||||
|
driver.setIdCardLongTerm(DEFAULT_FALSE);
|
||||||
|
}
|
||||||
if (driver.getDrivingLicenseLongTerm() == null) {
|
if (driver.getDrivingLicenseLongTerm() == null) {
|
||||||
driver.setDrivingLicenseLongTerm(DEFAULT_FALSE);
|
driver.setDrivingLicenseLongTerm(DEFAULT_FALSE);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -38,9 +38,22 @@ public class IDCardVO implements Serializable {
|
|||||||
*/
|
*/
|
||||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||||
private Date birthday;
|
private Date birthday;
|
||||||
|
/**
|
||||||
|
* 住址
|
||||||
|
*/
|
||||||
|
private String address;
|
||||||
|
/**
|
||||||
|
* 有效期起
|
||||||
|
*/
|
||||||
|
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||||
|
private Date validDateStart;
|
||||||
/**
|
/**
|
||||||
* 有效期止
|
* 有效期止
|
||||||
*/
|
*/
|
||||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||||
private Date validDateEnd;
|
private Date validDateEnd;
|
||||||
|
/**
|
||||||
|
* 长期有效:1-是,0-否
|
||||||
|
*/
|
||||||
|
private Integer longTerm;
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-28
@@ -1,6 +1,9 @@
|
|||||||
package org.springblade.thirdparty.ocr.service.impl;
|
package org.springblade.thirdparty.ocr.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.lang.TypeReference;
|
import cn.hutool.core.lang.TypeReference;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
import cn.hutool.json.JSONUtil;
|
import cn.hutool.json.JSONUtil;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -13,10 +16,10 @@ import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
|||||||
import org.springblade.thirdparty.ocr.convert.AttachmentIndexConvert;
|
import org.springblade.thirdparty.ocr.convert.AttachmentIndexConvert;
|
||||||
import org.springblade.thirdparty.ocr.exception.OCRException;
|
import org.springblade.thirdparty.ocr.exception.OCRException;
|
||||||
import org.springblade.thirdparty.ocr.feign.IOCRClient;
|
import org.springblade.thirdparty.ocr.feign.IOCRClient;
|
||||||
import org.springblade.thirdparty.ocr.feign.IOCROtherClient;
|
|
||||||
import org.springblade.thirdparty.ocr.pojo.dto.*;
|
import org.springblade.thirdparty.ocr.pojo.dto.*;
|
||||||
import org.springblade.thirdparty.ocr.pojo.vo.*;
|
import org.springblade.thirdparty.ocr.pojo.vo.*;
|
||||||
import org.springblade.thirdparty.ocr.service.IOCRService;
|
import org.springblade.thirdparty.ocr.service.IOCRService;
|
||||||
|
import org.springblade.thirdparty.ocr.support.ShenFenZhengIdCardSupport;
|
||||||
import org.springblade.thirdparty.ocr.util.ConvertUtil;
|
import org.springblade.thirdparty.ocr.util.ConvertUtil;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -43,10 +46,12 @@ public class OCRServiceImpl implements IOCRService {
|
|||||||
private static final BigDecimal WEIGHT_LIMIT = BigDecimal.valueOf(200);
|
private static final BigDecimal WEIGHT_LIMIT = BigDecimal.valueOf(200);
|
||||||
|
|
||||||
private final IOCRClient client;
|
private final IOCRClient client;
|
||||||
private final IOCROtherClient otherClient;
|
|
||||||
|
|
||||||
@Value("${thirdParty.ocr.baseOtherUrl}")
|
/**
|
||||||
private String ocrBaseOtherUrl;
|
* 身份证 OCR 服务地址,Nacos:thirdParty.ocr.idCardBaseUrl
|
||||||
|
*/
|
||||||
|
@Value("${thirdParty.ocr.idCardBaseUrl:${thirdParty.ocr.baseOtherUrl}}")
|
||||||
|
private String idCardBaseUrl;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransportCertificateVO recognitionTransportCertificate(CertificateBatchRecognitionDTO param) {
|
public TransportCertificateVO recognitionTransportCertificate(CertificateBatchRecognitionDTO param) {
|
||||||
@@ -339,45 +344,79 @@ public class OCRServiceImpl implements IOCRService {
|
|||||||
if (CollectionUtils.isEmpty(urls)) {
|
if (CollectionUtils.isEmpty(urls)) {
|
||||||
throw new OCRException("图像链接不能为空");
|
throw new OCRException("图像链接不能为空");
|
||||||
}
|
}
|
||||||
|
if (StringUtil.isBlank(idCardBaseUrl)) {
|
||||||
|
throw new OCRException("身份证OCR服务地址未配置(thirdParty.ocr.idCardBaseUrl)");
|
||||||
|
}
|
||||||
IDCardVO result = new IDCardVO();
|
IDCardVO result = new IDCardVO();
|
||||||
try {
|
try {
|
||||||
for (String url : urls) {
|
for (String url : urls) {
|
||||||
OCRCardBankDetRecDTO param = new OCRCardBankDetRecDTO(url);
|
if (StringUtil.isBlank(url)) {
|
||||||
// param.setDataType("IDCard-Main");
|
|
||||||
log.info("调用ocr证件定位+结构化信息提取接口,请求地址:{},请求参数:{}",
|
|
||||||
getCardBankDetRecUrl(), JSONUtil.toJsonStr(param));
|
|
||||||
OCRResultVO<OCRBigCommonCardVO> resultVO = otherClient.cardBankDetRec(param);
|
|
||||||
if (resultVO != null && OCRConstant.SUCCESS_CODE.equals(resultVO.getCode())) {
|
|
||||||
// 成功
|
|
||||||
OCRBigCommonCardVO card = resultVO.getResult();
|
|
||||||
convertIDCard(result, card);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
log.error("调用ocr接口证件定位+结构化信息提取异常响应参数:{}", JSONUtil.toJsonStr(resultVO));
|
ShenFenZhengIdCardSupport.merge(result, recognizeIdCardByShenFenZheng(url.trim()));
|
||||||
String message = getMessage(resultVO);
|
|
||||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常 " + message);
|
|
||||||
}
|
}
|
||||||
} catch (OCRException e) {
|
} catch (OCRException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("调用ocr接口证件定位+结构化信息提取异常", e);
|
log.error("调用身份证OCR接口异常", e);
|
||||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常");
|
throw new OCRException("调用身份证OCR接口异常");
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getCardBankDetRecUrl() {
|
/**
|
||||||
return ocrBaseOtherUrl.replaceAll("/+$", "") + "/CardBankDetRec";
|
* 下载图片后以 formData.image_file 调用 ShenFenZheng
|
||||||
|
*
|
||||||
|
* @param imageUrl 可访问的图片地址
|
||||||
|
* @return 单张识别结果
|
||||||
|
*/
|
||||||
|
private IDCardVO recognizeIdCardByShenFenZheng(String imageUrl) {
|
||||||
|
String requestUrl = idCardBaseUrl.replaceAll("/+$", "") + ShenFenZhengIdCardSupport.PATH;
|
||||||
|
byte[] imageBytes;
|
||||||
|
try {
|
||||||
|
imageBytes = HttpUtil.downloadBytes(imageUrl);
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("下载身份证图片失败,url={}", imageUrl, exception);
|
||||||
|
throw new OCRException("下载身份证图片失败");
|
||||||
|
}
|
||||||
|
if (imageBytes == null || imageBytes.length == 0) {
|
||||||
|
throw new OCRException("身份证图片内容为空");
|
||||||
|
}
|
||||||
|
String fileName = resolveImageFileName(imageUrl);
|
||||||
|
log.info("调用身份证OCR接口,请求地址:{},文件名:{},大小:{}", requestUrl, fileName, imageBytes.length);
|
||||||
|
try (HttpResponse response = HttpRequest.post(requestUrl)
|
||||||
|
.form(ShenFenZhengIdCardSupport.FILE_FIELD, imageBytes, fileName)
|
||||||
|
.timeout(60000)
|
||||||
|
.execute()) {
|
||||||
|
String body = response.body();
|
||||||
|
log.info("调用身份证OCR接口响应,status={},body={}", response.getStatus(), body);
|
||||||
|
if (!response.isOk()) {
|
||||||
|
throw new OCRException("调用身份证OCR接口失败,HTTP状态码:" + response.getStatus());
|
||||||
|
}
|
||||||
|
if (!ShenFenZhengIdCardSupport.isSuccess(body)) {
|
||||||
|
throw new OCRException("身份证OCR识别失败");
|
||||||
|
}
|
||||||
|
return ShenFenZhengIdCardSupport.parse(body);
|
||||||
|
} catch (OCRException exception) {
|
||||||
|
throw exception;
|
||||||
|
} catch (Exception exception) {
|
||||||
|
log.error("调用身份证OCR接口异常,url={}", requestUrl, exception);
|
||||||
|
throw new OCRException("调用身份证OCR接口异常");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private String resolveImageFileName(String imageUrl) {
|
||||||
* 转换身份证
|
String path = imageUrl;
|
||||||
* @param result
|
int queryIndex = path.indexOf('?');
|
||||||
* @param card
|
if (queryIndex >= 0) {
|
||||||
* @return
|
path = path.substring(0, queryIndex);
|
||||||
*/
|
}
|
||||||
private void convertIDCard(IDCardVO result, OCRBigCommonCardVO card) {
|
int slashIndex = path.lastIndexOf('/');
|
||||||
convert(result, card, ConvertUtil::getIDCardSetter, null);
|
String name = slashIndex >= 0 ? path.substring(slashIndex + 1) : path;
|
||||||
|
if (StringUtil.isBlank(name) || !name.contains(".")) {
|
||||||
|
return "id-card.jpg";
|
||||||
|
}
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+301
@@ -0,0 +1,301 @@
|
|||||||
|
/**
|
||||||
|
* 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.thirdparty.ocr.support;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import org.springblade.core.tool.utils.DateUtil;
|
||||||
|
import org.springblade.core.tool.utils.StringUtil;
|
||||||
|
import org.springblade.thirdparty.ocr.pojo.vo.IDCardVO;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.BiConsumer;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证 OCR(ShenFenZheng)响应解析
|
||||||
|
* <p>
|
||||||
|
* 第三方返回形如:
|
||||||
|
* {@code result."0" = [[{"label":"身份证_姓名"}], [{"result":"张三"}], {"r":[...]}]},
|
||||||
|
* 这里抽成「标签 → 文本」后再回填 {@link IDCardVO}。
|
||||||
|
*
|
||||||
|
* @author Chill
|
||||||
|
*/
|
||||||
|
public final class ShenFenZhengIdCardSupport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 接口路径
|
||||||
|
*/
|
||||||
|
public static final String PATH = "/ShenFenZheng";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* formData 文件字段名
|
||||||
|
*/
|
||||||
|
public static final String FILE_FIELD = "image_file";
|
||||||
|
|
||||||
|
private static final String LONG_TERM_TEXT = "长期";
|
||||||
|
|
||||||
|
private static final Pattern DATE_PATTERN = Pattern.compile("(\\d{4})\\D+(\\d{1,2})\\D+(\\d{1,2})");
|
||||||
|
|
||||||
|
private static final Map<String, BiConsumer<IDCardVO, String>> FIELD_SETTERS = initFieldSetters();
|
||||||
|
|
||||||
|
private ShenFenZhengIdCardSupport() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析第三方原始 JSON 为身份证 VO
|
||||||
|
*
|
||||||
|
* @param responseBody 响应原文
|
||||||
|
* @return 识别结果;结构异常时返回空对象
|
||||||
|
*/
|
||||||
|
public static IDCardVO parse(String responseBody) {
|
||||||
|
IDCardVO result = new IDCardVO();
|
||||||
|
if (StringUtil.isBlank(responseBody)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
JSONObject root = JSONUtil.parseObj(responseBody);
|
||||||
|
Map<String, String> fields = readLabelValues(root.getJSONObject("result"));
|
||||||
|
for (Map.Entry<String, String> entry : fields.entrySet()) {
|
||||||
|
BiConsumer<IDCardVO, String> setter = FIELD_SETTERS.get(normalizeLabel(entry.getKey()));
|
||||||
|
if (setter != null && StringUtil.isNotBlank(entry.getValue())) {
|
||||||
|
setter.accept(result, entry.getValue().trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断第三方是否识别成功
|
||||||
|
*
|
||||||
|
* @param responseBody 响应原文
|
||||||
|
* @return true 表示成功
|
||||||
|
*/
|
||||||
|
public static boolean isSuccess(String responseBody) {
|
||||||
|
if (StringUtil.isBlank(responseBody)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
JSONObject root = JSONUtil.parseObj(responseBody);
|
||||||
|
Boolean status = root.getBool("status");
|
||||||
|
if (Boolean.TRUE.equals(status)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 个别版本只给 identifyCode,1001 视为成功
|
||||||
|
Integer identifyCode = root.getInt("identifyCode");
|
||||||
|
return identifyCode != null && identifyCode == 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 合并多张图的识别结果:后写的非空值覆盖先写的,方便正反面各识别一次后汇总
|
||||||
|
*
|
||||||
|
* @param target 汇总目标
|
||||||
|
* @param source 本次识别结果
|
||||||
|
*/
|
||||||
|
public static void merge(IDCardVO target, IDCardVO source) {
|
||||||
|
if (target == null || source == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotBlank(source.getName())) {
|
||||||
|
target.setName(source.getName());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotBlank(source.getIdNo())) {
|
||||||
|
target.setIdNo(source.getIdNo());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotBlank(source.getGender())) {
|
||||||
|
target.setGender(source.getGender());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotBlank(source.getNation())) {
|
||||||
|
target.setNation(source.getNation());
|
||||||
|
}
|
||||||
|
if (source.getBirthday() != null) {
|
||||||
|
target.setBirthday(source.getBirthday());
|
||||||
|
}
|
||||||
|
if (StringUtil.isNotBlank(source.getAddress())) {
|
||||||
|
target.setAddress(source.getAddress());
|
||||||
|
}
|
||||||
|
if (source.getValidDateStart() != null) {
|
||||||
|
target.setValidDateStart(source.getValidDateStart());
|
||||||
|
}
|
||||||
|
if (source.getValidDateEnd() != null) {
|
||||||
|
target.setValidDateEnd(source.getValidDateEnd());
|
||||||
|
}
|
||||||
|
if (source.getLongTerm() != null) {
|
||||||
|
target.setLongTerm(source.getLongTerm());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, String> readLabelValues(JSONObject result) {
|
||||||
|
Map<String, String> fields = new LinkedHashMap<>();
|
||||||
|
if (result == null || result.isEmpty()) {
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
for (String key : result.keySet()) {
|
||||||
|
JSONArray item = result.getJSONArray(key);
|
||||||
|
if (item == null || item.size() < 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String label = readNestedText(item.get(0), "label");
|
||||||
|
String value = readNestedText(item.get(1), "result");
|
||||||
|
if (StringUtil.isNotBlank(label) && StringUtil.isNotBlank(value)) {
|
||||||
|
fields.put(label, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readNestedText(Object node, String fieldName) {
|
||||||
|
if (node instanceof JSONArray array) {
|
||||||
|
if (array.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object first = array.get(0);
|
||||||
|
if (first instanceof JSONObject object) {
|
||||||
|
return object.getStr(fieldName);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (node instanceof JSONObject object) {
|
||||||
|
return object.getStr(fieldName);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String normalizeLabel(String label) {
|
||||||
|
return StringUtil.isBlank(label) ? "" : label.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, BiConsumer<IDCardVO, String>> initFieldSetters() {
|
||||||
|
Map<String, BiConsumer<IDCardVO, String>> setters = new LinkedHashMap<>();
|
||||||
|
setters.put("身份证_姓名", IDCardVO::setName);
|
||||||
|
setters.put("姓名", IDCardVO::setName);
|
||||||
|
setters.put("身份证_公民身份号码", IDCardVO::setIdNo);
|
||||||
|
setters.put("公民身份号码", IDCardVO::setIdNo);
|
||||||
|
setters.put("公民身份证号码", IDCardVO::setIdNo);
|
||||||
|
setters.put("身份证_性别", IDCardVO::setGender);
|
||||||
|
setters.put("性别", IDCardVO::setGender);
|
||||||
|
setters.put("身份证_民族", (card, value) -> card.setNation(normalizeNation(value)));
|
||||||
|
setters.put("民族", (card, value) -> card.setNation(normalizeNation(value)));
|
||||||
|
setters.put("身份证_出生", (card, value) -> card.setBirthday(parseDate(value)));
|
||||||
|
setters.put("出生", (card, value) -> card.setBirthday(parseDate(value)));
|
||||||
|
setters.put("身份证_住址", IDCardVO::setAddress);
|
||||||
|
setters.put("住址", IDCardVO::setAddress);
|
||||||
|
setters.put("身份证_有效期限", ShenFenZhengIdCardSupport::applyValidity);
|
||||||
|
setters.put("有效期限", ShenFenZhengIdCardSupport::applyValidity);
|
||||||
|
setters.put("身份证_签发日期", (card, value) -> card.setValidDateStart(parseDate(value)));
|
||||||
|
setters.put("签发日期", (card, value) -> card.setValidDateStart(parseDate(value)));
|
||||||
|
setters.put("身份证_失效日期", ShenFenZhengIdCardSupport::applyEndDate);
|
||||||
|
setters.put("失效日期", ShenFenZhengIdCardSupport::applyEndDate);
|
||||||
|
return setters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String normalizeNation(String value) {
|
||||||
|
String nation = value == null ? "" : value.trim();
|
||||||
|
if (nation.isEmpty()) {
|
||||||
|
return nation;
|
||||||
|
}
|
||||||
|
return nation.endsWith("族") ? nation : nation + "族";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyValidity(IDCardVO card, String value) {
|
||||||
|
if (StringUtil.isBlank(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.contains(LONG_TERM_TEXT)) {
|
||||||
|
card.setLongTerm(1);
|
||||||
|
card.setValidDateEnd(null);
|
||||||
|
Date start = parseFirstDate(value);
|
||||||
|
if (start != null) {
|
||||||
|
card.setValidDateStart(start);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
card.setLongTerm(0);
|
||||||
|
Date start = parseFirstDate(value);
|
||||||
|
Date end = parseLastDate(value);
|
||||||
|
if (start != null) {
|
||||||
|
card.setValidDateStart(start);
|
||||||
|
}
|
||||||
|
if (end != null) {
|
||||||
|
card.setValidDateEnd(end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void applyEndDate(IDCardVO card, String value) {
|
||||||
|
if (StringUtil.isBlank(value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (value.contains(LONG_TERM_TEXT)) {
|
||||||
|
card.setLongTerm(1);
|
||||||
|
card.setValidDateEnd(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Date end = parseDate(value);
|
||||||
|
if (end != null) {
|
||||||
|
card.setLongTerm(0);
|
||||||
|
card.setValidDateEnd(end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Date parseDate(String text) {
|
||||||
|
return parseFirstDate(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Date parseFirstDate(String text) {
|
||||||
|
Matcher matcher = DATE_PATTERN.matcher(text);
|
||||||
|
if (!matcher.find()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return toDate(matcher.group(1), matcher.group(2), matcher.group(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Date parseLastDate(String text) {
|
||||||
|
Matcher matcher = DATE_PATTERN.matcher(text);
|
||||||
|
String year = null;
|
||||||
|
String month = null;
|
||||||
|
String day = null;
|
||||||
|
while (matcher.find()) {
|
||||||
|
year = matcher.group(1);
|
||||||
|
month = matcher.group(2);
|
||||||
|
day = matcher.group(3);
|
||||||
|
}
|
||||||
|
if (year == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return toDate(year, month, day);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Date toDate(String year, String month, String day) {
|
||||||
|
try {
|
||||||
|
String formatted = String.format("%s-%02d-%02d", year, Integer.parseInt(month), Integer.parseInt(day));
|
||||||
|
return DateUtil.parse(formatted, DateUtil.PATTERN_DATE);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -92,8 +92,10 @@ thirdParty:
|
|||||||
ocr:
|
ocr:
|
||||||
# OCR磅单、车牌识别接口地址
|
# OCR磅单、车牌识别接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
# OCR证件识别接口地址
|
# OCR证件识别接口地址(银行卡等通用证件)
|
||||||
baseOtherUrl: http://127.0.0.1:8080
|
baseOtherUrl: http://127.0.0.1:8080
|
||||||
|
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||||
|
idCardBaseUrl: http://124.71.22.123:8500
|
||||||
wps:
|
wps:
|
||||||
# WPS开放接口地址
|
# WPS开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
|
|||||||
@@ -54,8 +54,10 @@ thirdParty:
|
|||||||
ocr:
|
ocr:
|
||||||
# OCR磅单、车牌识别接口地址
|
# OCR磅单、车牌识别接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
# OCR证件识别接口地址
|
# OCR证件识别接口地址(银行卡等通用证件)
|
||||||
baseOtherUrl: http://127.0.0.1:8080
|
baseOtherUrl: http://127.0.0.1:8080
|
||||||
|
# 身份证 OCR 服务地址(POST /ShenFenZheng,formData 字段 image_file)
|
||||||
|
idCardBaseUrl: http://124.71.22.123:8500
|
||||||
wps:
|
wps:
|
||||||
# WPS开放接口地址
|
# WPS开放接口地址
|
||||||
baseUrl: http://127.0.0.1:8080
|
baseUrl: http://127.0.0.1:8080
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ thirdParty:
|
|||||||
ocr:
|
ocr:
|
||||||
# OCR磅单、车牌识别接口地址
|
# OCR磅单、车牌识别接口地址
|
||||||
baseUrl: ${OCR_BASE_URL:http://127.0.0.1:8080}
|
baseUrl: ${OCR_BASE_URL:http://127.0.0.1:8080}
|
||||||
# OCR证件识别接口地址
|
# OCR证件识别接口地址(银行卡等通用证件)
|
||||||
baseOtherUrl: ${OCR_BASE_OTHER_URL:http://127.0.0.1:8080}
|
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}
|
||||||
wps:
|
wps:
|
||||||
# WPS开放接口地址
|
# WPS开放接口地址
|
||||||
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
|
||||||
|
|||||||
Reference in New Issue
Block a user