feat:添加OA系统对接相关代码
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
package org.springblade.thirdparty.ocr.config;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import org.springblade.thirdparty.ocr.interceptor.OCRRequestInterceptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* @author bfhuange
|
||||
* @since 2024/12/18
|
||||
*/
|
||||
public class OCRFeignClientConfig {
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
return new OCRRequestInterceptor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.springblade.thirdparty.ocr.config;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 第三方api ocr配置类
|
||||
* @author bfhuange
|
||||
* @date 2024/12/18
|
||||
*/
|
||||
@ComponentScan("org.springblade.thirdparty.ocr")
|
||||
@Configuration
|
||||
public class ThirdPartyOCRAutoConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.springblade.thirdparty.ocr.constant;
|
||||
|
||||
/**
|
||||
* ocr 常量类
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
public class OCRConstant {
|
||||
/**
|
||||
* 成功状态码
|
||||
*/
|
||||
public static final Integer SUCCESS_CODE = 200;
|
||||
|
||||
/**
|
||||
* 重量单位 kg
|
||||
*/
|
||||
public static final String UNIT_KG = "kg";
|
||||
|
||||
/**
|
||||
* 重量大卫 t
|
||||
*/
|
||||
public static final String UNIT_T = "t";
|
||||
|
||||
/**
|
||||
* 重量单位 吨
|
||||
*/
|
||||
public static final String UNIT_T_ZH = "吨";
|
||||
|
||||
/**
|
||||
* 请求头,请求时间
|
||||
*/
|
||||
public static final String REQUEST_HEADER_TIME = "request_time";
|
||||
/**
|
||||
* 请求头,trace id
|
||||
*/
|
||||
public static final String REQUEST_HEADER_TRACE_ID = "trace_id";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package org.springblade.thirdparty.ocr.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 图像类型枚举
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum OCRImageType {
|
||||
/**
|
||||
* 身份证-正⻚
|
||||
*/
|
||||
ID_CARD_MAIN("IDCard-Main", "身份证-正⻚", OCRKey.ID_CARD_MAIN_KEYS),
|
||||
/**
|
||||
* 身份证-副⻚
|
||||
*/
|
||||
ID_CARD_SIDE("IDCard-Side", "身份证-副⻚", OCRKey.ID_CARD_SIDE_KEYS),
|
||||
/**
|
||||
* 驾驶证-电子版
|
||||
*/
|
||||
DRIVER_LICENSE_ELEC("DriverLicense-Elec", "驾驶证-电子版", OCRKey.DRIVER_LICENSE_MAIN_KEYS),
|
||||
/**
|
||||
* 驾驶证-正⻚
|
||||
*/
|
||||
DRIVER_LICENSE_MAIN("DriverLicense-Main", "驾驶证-正⻚", OCRKey.DRIVER_LICENSE_MAIN_KEYS),
|
||||
/**
|
||||
* 驾驶证-副⻚
|
||||
*/
|
||||
DRIVER_LICENSE_SIDE("DriverLicense-Side", "驾驶证-副⻚", Collections.emptyList()),
|
||||
/**
|
||||
* ⾏驶证-正⻚-挂车
|
||||
*/
|
||||
VEHICLE_LICENSE_MAIN_GUA("VehicleLicense-Main-Gua", "⾏驶证-正⻚-挂车", OCRKey.VEHICLE_LICENSE_MAIN_KEYS),
|
||||
/**
|
||||
* ⾏驶证-正⻚-其他
|
||||
*/
|
||||
VEHICLE_LICENSE_MAIN_OTHERS("VehicleLicense-Main-Others", "⾏驶证-正⻚-其他", OCRKey.VEHICLE_LICENSE_MAIN_KEYS),
|
||||
/**
|
||||
* ⾏驶证-正⻚
|
||||
*/
|
||||
VEHICLE_LICENSE_MAIN("VehicleLicense-Main", "⾏驶证-正⻚", OCRKey.VEHICLE_LICENSE_MAIN_KEYS),
|
||||
/**
|
||||
* ⾏驶证-副⻚
|
||||
*/
|
||||
VEHICLE_LICENSE_SIDE("VehicleLicense-Side", "⾏驶证-副⻚", OCRKey.VEHICLE_LICENSE_SIDE_KEYS),
|
||||
/**
|
||||
* ⻋头
|
||||
*/
|
||||
CAR_FRONT("Car-Front", "⻋头", OCRKey.CAR_FRONT_KEYS),
|
||||
/**
|
||||
* ⻋尾
|
||||
*/
|
||||
CAR_BACK("Car-Back", "⻋尾", OCRKey.CAR_BACK_KEYS),
|
||||
// =======================下面是非erp识别所需信息,录入配置非磅单类型====================
|
||||
/**
|
||||
* 未知
|
||||
*/
|
||||
UNKNOWN("UNK", "未知"),
|
||||
/**
|
||||
* 其他
|
||||
*/
|
||||
OTHERS("Others", "其他"),
|
||||
/**
|
||||
* 证件
|
||||
*/
|
||||
CARD("CARD", "证件"),
|
||||
/**
|
||||
* 碎片
|
||||
*/
|
||||
SCRAP("Scrap", "碎片"),
|
||||
/**
|
||||
* 有⻋辆没有检测到⻋牌
|
||||
*/
|
||||
NO_PLATE("NoPlate", "有⻋辆没有检测到⻋牌"),
|
||||
/**
|
||||
* ⽆⻋
|
||||
*/
|
||||
NO_CAR("NoCar", "⽆⻋"),
|
||||
;
|
||||
/**
|
||||
* 类型标识
|
||||
*/
|
||||
private final String id;
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private final String type;
|
||||
/**
|
||||
* key列表
|
||||
*/
|
||||
private final List<OCRKey.KeyInfo> keys;
|
||||
|
||||
OCRImageType(String id, String type) {
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.keys = Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
package org.springblade.thirdparty.ocr.constant;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 各类型字段枚举
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
public class OCRKey {
|
||||
/**
|
||||
* 驾驶证-正⻚ 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> DRIVER_LICENSE_MAIN_KEYS = List.of(
|
||||
// 证号
|
||||
KeyInfo.ID_NO,
|
||||
// 姓名
|
||||
KeyInfo.NAME,
|
||||
// 性别
|
||||
KeyInfo.SEX,
|
||||
// 出⽣⽇期
|
||||
KeyInfo.DATE_BIRTH,
|
||||
// 初次领证⽇期
|
||||
KeyInfo.DATE_FIRST_ISSUE,
|
||||
// 准驾⻋型
|
||||
KeyInfo.CLASS,
|
||||
// 有效期限(起始时间)
|
||||
// KeyInfo.DATE_VALID_START,
|
||||
// 有效期限(终⽌时间)
|
||||
// KeyInfo.DATE_VALID_END,
|
||||
// 有效期限
|
||||
KeyInfo.DATE_VALID,
|
||||
// 住址
|
||||
KeyInfo.ADDRESS
|
||||
);
|
||||
/**
|
||||
* ⾏驶证-正⻚ 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> VEHICLE_LICENSE_MAIN_KEYS = List.of(
|
||||
// 车牌号
|
||||
KeyInfo.PLATE_NO,
|
||||
// ⻋辆类型
|
||||
KeyInfo.VEHICLE_TYPE,
|
||||
// 姓名
|
||||
KeyInfo.NAME,
|
||||
// 使⽤性质
|
||||
KeyInfo.USE_CHARACTER,
|
||||
// 品牌型号
|
||||
KeyInfo.MODEL,
|
||||
// ⻋架号
|
||||
KeyInfo.VIN,
|
||||
// 发动机号码
|
||||
KeyInfo.ENGINE_NO,
|
||||
// 注册⽇期
|
||||
KeyInfo.DATE_REGISTER,
|
||||
// 发证⽇期
|
||||
KeyInfo.DATE_ISSUE,
|
||||
// 住址
|
||||
KeyInfo.ADDRESS
|
||||
);
|
||||
/**
|
||||
* ⾏驶证-副⻚ 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> VEHICLE_LICENSE_SIDE_KEYS = List.of(
|
||||
// 检验有效期
|
||||
KeyInfo.DATE_VALID_INSPECTION
|
||||
);
|
||||
/**
|
||||
* ⻋头 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> CAR_FRONT_KEYS = List.of(
|
||||
// ⻋牌号
|
||||
KeyInfo.PLATE_NO
|
||||
);
|
||||
/**
|
||||
* ⻋尾 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> CAR_BACK_KEYS = List.of(
|
||||
// ⻋牌号
|
||||
KeyInfo.PLATE_NO
|
||||
);
|
||||
/**
|
||||
* 过磅单 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> POUND_KEYS = List.of(
|
||||
// ⽇期
|
||||
KeyInfo.DATE,
|
||||
// 单位
|
||||
KeyInfo.UNIT_MEASURE,
|
||||
// ⻋牌号
|
||||
KeyInfo.PLATE_NO,
|
||||
// 货品
|
||||
KeyInfo.NAME_GOODS,
|
||||
// 收货单位
|
||||
KeyInfo.COMPANY_RECEIPT,
|
||||
// 发货单位
|
||||
KeyInfo.COMPANY_SHIP,
|
||||
// ⽑重
|
||||
KeyInfo.WEIGHT_GROSS,
|
||||
// ⽪重
|
||||
KeyInfo.WEIGHT_TARE,
|
||||
// 净重
|
||||
KeyInfo.WEIGHT_NET,
|
||||
// 扣重
|
||||
KeyInfo.WEIGHT_DEDUCT,
|
||||
// 实际净重
|
||||
KeyInfo.WEIGHT_RECEIVED
|
||||
);
|
||||
/**
|
||||
* 身份证-正⻚ 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> ID_CARD_MAIN_KEYS = List.of(
|
||||
// 姓名
|
||||
KeyInfo.NAME,
|
||||
// 公民身份号码
|
||||
KeyInfo.ID_NO,
|
||||
// 性别
|
||||
KeyInfo.ID_CARD_MAIN_GENDER,
|
||||
// 民族
|
||||
KeyInfo.ID_CARD_MAIN_ETHNIC_GROUP,
|
||||
// 出生
|
||||
KeyInfo.DATE,
|
||||
// 住址
|
||||
KeyInfo.ID_CARD_MAIN_ADD
|
||||
);
|
||||
/**
|
||||
* 身份证-副⻚ 字段列表
|
||||
*/
|
||||
public static final List<KeyInfo> ID_CARD_SIDE_KEYS = List.of(
|
||||
// 签发机关
|
||||
KeyInfo.ISSUING_AUTHORITY,
|
||||
// 有效期限
|
||||
KeyInfo.DATE_VALID
|
||||
);
|
||||
|
||||
/**
|
||||
* 所有类型
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum KeyInfo {
|
||||
/**
|
||||
* 住址
|
||||
*/
|
||||
ADDRESS("address", "住址"),
|
||||
/**
|
||||
* 证号
|
||||
*/
|
||||
ID_NO("ID_no", "证号"),
|
||||
/**
|
||||
* 发动机号码
|
||||
*/
|
||||
ENGINE_NO("engine_no", "发动机号码"),
|
||||
/**
|
||||
* 档案编号
|
||||
*/
|
||||
FILE_NO("file_no", "档案编号"),
|
||||
/**
|
||||
* 供货单位、客户名称、发货单位
|
||||
*/
|
||||
COMPANY_SHIP("company_ship", "供货单位、客户名称、发货单位"),
|
||||
/**
|
||||
* 收货单位
|
||||
*/
|
||||
COMPANY_RECEIPT("company_receipt", "收货单位"),
|
||||
/**
|
||||
* ⽇期
|
||||
*/
|
||||
DATE("date", "⽇期"),
|
||||
/**
|
||||
* 出⽣⽇期
|
||||
*/
|
||||
DATE_BIRTH("date_birth", "出⽣⽇期"),
|
||||
/**
|
||||
* 注册⽇期
|
||||
*/
|
||||
DATE_REGISTER("date_register", "注册⽇期"),
|
||||
/**
|
||||
* 初次领证⽇期
|
||||
*/
|
||||
DATE_FIRST_ISSUE("date_first_issue", "初次领证⽇期"),
|
||||
/**
|
||||
* 注册⽇期
|
||||
*/
|
||||
DATE_ISSUE("date_issue", "发证⽇期"),
|
||||
/**
|
||||
* 有效期限(起始时间)
|
||||
*/
|
||||
DATE_VALID_START("date_vaild_start", "有效期限(起始时间)"),
|
||||
/**
|
||||
* 有效期限(终⽌时间)
|
||||
*/
|
||||
DATE_VALID_END("date_vaild_end", "有效期限(终⽌时间)"),
|
||||
/**
|
||||
* ⾏驶证副⻚-备注 -> 检验有效期
|
||||
*/
|
||||
DATE_VALID_INSPECTION("date_vaild_inspection", "⾏驶证副⻚-备注 -> 检验有效期"),
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
SEX("six", "性别"),
|
||||
/**
|
||||
* 国籍
|
||||
*/
|
||||
NATIONALITY("nationality", "国籍"),
|
||||
/**
|
||||
* ⺠族
|
||||
*/
|
||||
NATION("nation", "⺠族"),
|
||||
/**
|
||||
* 姓名、所有⼈
|
||||
*/
|
||||
NAME("name", "姓名、所有⼈"),
|
||||
/**
|
||||
* 货物名称、货品名称
|
||||
*/
|
||||
NAME_GOODS("name_goods", "货物名称、货品名称"),
|
||||
/**
|
||||
* 物料
|
||||
*/
|
||||
NAME_MATERIAL("name_material", "物料"),
|
||||
/**
|
||||
* ⻋辆类型
|
||||
*/
|
||||
VEHICLE_TYPE("vehicle_type", "⻋辆类型"),
|
||||
/**
|
||||
* 使⽤性质
|
||||
*/
|
||||
USE_CHARACTER("use_character", "使⽤性质"),
|
||||
/**
|
||||
* 品牌型号
|
||||
*/
|
||||
MODEL("model", "品牌型号"),
|
||||
/**
|
||||
* 准驾⻋型
|
||||
*/
|
||||
CLASS("class", "准驾⻋型"),
|
||||
/**
|
||||
* ⻋架号
|
||||
*/
|
||||
VIN("vin", "⻋架号"),
|
||||
/**
|
||||
* ⻋牌号、号牌号码、⻋号
|
||||
*/
|
||||
PLATE_NO("plate_no", "⻋牌号、号牌号码、⻋号"),
|
||||
/**
|
||||
* 扣重、扣杂
|
||||
*/
|
||||
WEIGHT_DEDUCT("weight_deduct", "扣重、扣杂"),
|
||||
/**
|
||||
* ⽑重、总重
|
||||
*/
|
||||
WEIGHT_GROSS("weight_gross", "⽑重、总重"),
|
||||
/**
|
||||
* ⽪重、空重
|
||||
*/
|
||||
WEIGHT_TARE("weight_tare", "⽪重、空重"),
|
||||
/**
|
||||
* 净重
|
||||
*/
|
||||
WEIGHT_NET("weight_net", "净重"),
|
||||
/**
|
||||
* 实际净重
|
||||
*/
|
||||
WEIGHT_RECEIVED("weight_received", "实际净重"),
|
||||
/**
|
||||
* 杂质
|
||||
*/
|
||||
WEIGHT_IMPURITY("weight_impurity", "杂质"),
|
||||
/**
|
||||
* 粉末
|
||||
*/
|
||||
WEIGHT_POWDER("weight_powder", "粉末"),
|
||||
/**
|
||||
* 明⽔
|
||||
*/
|
||||
WEIGHT_CWATER("weight_cwater", "明⽔"),
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
UNIT_MEASURE("unit_measure", "单位"),
|
||||
/**
|
||||
* 识别了但是还未⽀持整合的结构化字段
|
||||
*/
|
||||
UN_SUPPORT("unsupport", "识别了但是还未⽀持整合的结构化字段"),
|
||||
|
||||
//===================身份证的有些字段不一样==============================
|
||||
/**
|
||||
* 身份证-性别
|
||||
*/
|
||||
ID_CARD_MAIN_GENDER("gender", "性别"),
|
||||
/**
|
||||
* 身份证-民族
|
||||
*/
|
||||
ID_CARD_MAIN_ETHNIC_GROUP("ethnic_group", "民族"),
|
||||
/**
|
||||
* 身份证-住址
|
||||
*/
|
||||
ID_CARD_MAIN_ADD("add", "住址"),
|
||||
/**
|
||||
* 签发机关
|
||||
*/
|
||||
ISSUING_AUTHORITY("issuing_authority", "签发机关"),
|
||||
/**
|
||||
* 有效期限
|
||||
*/
|
||||
DATE_VALID("date_vaild", "有效期限"),
|
||||
;
|
||||
/**
|
||||
* 字段编码
|
||||
*/
|
||||
private final String key;
|
||||
/**
|
||||
* 字段描述
|
||||
*/
|
||||
private final String description;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.springblade.thirdparty.ocr.convert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.exception.OCRException;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 附件索引转换器
|
||||
* @author bfhuange
|
||||
* @date 2024/11/8
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum AttachmentIndexConvert {
|
||||
/**
|
||||
* 车头
|
||||
*/
|
||||
CAR_FRONT(List.of(OCRImageType.CAR_FRONT), TransportCertificateVO::getCarFrontIndexes, TransportCertificateVO::getOtherIndexes),
|
||||
/**
|
||||
* 车尾
|
||||
*/
|
||||
CAR_BACK(List.of(OCRImageType.CAR_BACK), TransportCertificateVO::getCarBackIndexes, TransportCertificateVO::getOtherIndexes),
|
||||
/**
|
||||
* 行驶证 只从 VEHICLE_LICENSE_MAIN、VEHICLE_LICENSE_MAIN_OTHERS 取车牌号,VEHICLE_LICENSE_SIDE、VEHICLE_LICENSE_MAIN_GUA,没有车牌,但是要分类成行驶证
|
||||
*/
|
||||
VEHICLE_LICENSE(List.of(OCRImageType.VEHICLE_LICENSE_MAIN, OCRImageType.VEHICLE_LICENSE_MAIN_OTHERS, OCRImageType.VEHICLE_LICENSE_SIDE, OCRImageType.VEHICLE_LICENSE_MAIN_GUA), TransportCertificateVO::getVehicleLicenseIndexes, TransportCertificateVO::getOtherIndexes, false),
|
||||
/**
|
||||
* 驾驶证 只从 DRIVER_LICENSE_MAIN、DRIVER_LICENSE_ELEC 取有效期,DRIVER_LICENSE_SIDE 没有有效期,但是要分类驾驶证
|
||||
*/
|
||||
DRIVER_LICENSE(List.of(OCRImageType.DRIVER_LICENSE_MAIN, OCRImageType.DRIVER_LICENSE_ELEC, OCRImageType.DRIVER_LICENSE_SIDE), TransportCertificateVO::getDriverLicenseIndexes, TransportCertificateVO::getOtherIndexes, true),
|
||||
/**
|
||||
* 其他
|
||||
*/
|
||||
OTHER(List.of(OCRImageType.ID_CARD_MAIN, OCRImageType.ID_CARD_SIDE, OCRImageType.UNKNOWN, OCRImageType.OTHERS, OCRImageType.CARD,
|
||||
OCRImageType.SCRAP, OCRImageType.NO_PLATE, OCRImageType.NO_CAR), TransportCertificateVO::getOtherIndexes, TransportCertificateVO::getOtherIndexes, true),
|
||||
/**
|
||||
* 磅单
|
||||
*/
|
||||
POUND(Collections.emptyList(), TransportCertificateVO::getPoundIndexes, TransportCertificateVO::getOtherIndexes),
|
||||
;
|
||||
|
||||
/**
|
||||
* 图像类型列表
|
||||
*/
|
||||
private final List<OCRImageType> imageTypes;
|
||||
/**
|
||||
* 是否多个,除了其他,都是单个
|
||||
*/
|
||||
private final boolean multi;
|
||||
/**
|
||||
* 默认附件索引列表
|
||||
*/
|
||||
private final Function<TransportCertificateVO, List<Integer>> defaultListGetter;
|
||||
/**
|
||||
* 单个的情况下,其他的附件放的索引列表
|
||||
*/
|
||||
private final Function<TransportCertificateVO, List<Integer>> otherListGetter;
|
||||
/**
|
||||
* 多个的情况下,是否设置多次,后面的会覆盖前面的
|
||||
*/
|
||||
private final boolean multiSet;
|
||||
|
||||
AttachmentIndexConvert(List<OCRImageType> imageTypes, Function<TransportCertificateVO, List<Integer>> defaultListGetter, Function<TransportCertificateVO, List<Integer>> otherListGetter) {
|
||||
this(imageTypes, false, defaultListGetter, otherListGetter, true);
|
||||
}
|
||||
|
||||
AttachmentIndexConvert(List<OCRImageType> imageTypes, Function<TransportCertificateVO, List<Integer>> defaultListGetter, Function<TransportCertificateVO, List<Integer>> otherListGetter, boolean multiSet) {
|
||||
this(imageTypes, true, defaultListGetter, otherListGetter, multiSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加索引到list
|
||||
* @param certificate 凭证
|
||||
* @param index 索引
|
||||
* @return
|
||||
*/
|
||||
public boolean addIndex2list(TransportCertificateVO certificate, Integer index) {
|
||||
List<Integer> list = defaultListGetter.apply(certificate);
|
||||
// 是否放入默认list
|
||||
boolean defaultList = true;
|
||||
if (!multi && !list.isEmpty() && !list.contains(index)) {
|
||||
// 单个且默认list已经有数据了且待放入的数据不在默认list,放入其他
|
||||
// 处理同一张图包含能取字段的驾驶证或行驶证以及不能取字段的驾驶证或行驶证时,不能取字段的驾驶证或行驶证类型先识别,导致后续把能取字段的驾驶证或行驶证类型放到其他
|
||||
list = otherListGetter.apply(certificate);
|
||||
defaultList = false;
|
||||
}
|
||||
if (list.contains(index)) {
|
||||
// 如果已经包含了图片,设置多个,返回true,不设置多个,返回false
|
||||
return multiSet;
|
||||
}
|
||||
// 没有当前索引才添加,防止一张图片识别出多个结果重复添加索引
|
||||
list.add(index);
|
||||
return defaultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 图像类型对应的附件转换
|
||||
*/
|
||||
private static final Map<String, AttachmentIndexConvert> CONVERT_MAP = initConvertMap();
|
||||
|
||||
/**
|
||||
* 初始化 图像类型对应的附件转换
|
||||
* @return
|
||||
*/
|
||||
private static Map<String, AttachmentIndexConvert> initConvertMap() {
|
||||
return Stream.of(values())
|
||||
.flatMap(convert -> convert.imageTypes.stream()
|
||||
.collect(Collectors.toMap(OCRImageType::getId, e -> convert))
|
||||
.entrySet().stream()
|
||||
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
|
||||
throw new OCRException("图像类型对应的附件转换重复");
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据typeId 查询转换器,没找到的是磅单
|
||||
* @param typeId
|
||||
* @return
|
||||
*/
|
||||
public static AttachmentIndexConvert getConvertByTypeId(String typeId) {
|
||||
// 磅单的typeId过多,还在新增,所以没有配置的都认为是磅单
|
||||
return CONVERT_MAP.getOrDefault(typeId, AttachmentIndexConvert.POUND);
|
||||
}
|
||||
|
||||
public List<String> getImageTypeIds() {
|
||||
return imageTypes.stream()
|
||||
.map(OCRImageType::getId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.springblade.thirdparty.ocr.convert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRKey;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.IDCardVO;
|
||||
import org.springblade.thirdparty.ocr.util.ConvertUtil;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* 身份证转换
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum IDCardConvert {
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
NAME(OCRImageType.ID_CARD_MAIN, OCRKey.KeyInfo.NAME, IDCardVO::setName),
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
ID_NO(OCRImageType.ID_CARD_MAIN, OCRKey.KeyInfo.ID_NO, IDCardVO::setIdNo),
|
||||
/**
|
||||
* 有效期止
|
||||
*/
|
||||
VALID_DATE_END(OCRImageType.ID_CARD_SIDE, OCRKey.KeyInfo.DATE_VALID, (idCard, dateString) -> ConvertUtil.extractEndDate(dateString)
|
||||
.accept(idCard::setValidDateEnd)),
|
||||
;
|
||||
/**
|
||||
* 图像类型列表
|
||||
*/
|
||||
private final OCRImageType imageType;
|
||||
/**
|
||||
* 字段配置
|
||||
*/
|
||||
private final OCRKey.KeyInfo keyInfo;
|
||||
/**
|
||||
* setter方法
|
||||
*/
|
||||
private final BiConsumer<IDCardVO, String> setter;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.springblade.thirdparty.ocr.convert;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRKey;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static org.springblade.thirdparty.ocr.util.ConvertUtil.*;
|
||||
|
||||
/**
|
||||
* 车辆运输凭证转换
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum TransportCertificateConvert {
|
||||
/**
|
||||
* 车头车牌号
|
||||
*/
|
||||
CAR_FRONT_PLATE_NO(OCRImageType.CAR_FRONT, OCRKey.KeyInfo.PLATE_NO, TransportCertificateVO::setCarFrontPlateNo),
|
||||
/**
|
||||
* 车尾车牌号
|
||||
*/
|
||||
CAR_BACK_PLATE_NO(OCRImageType.CAR_BACK, OCRKey.KeyInfo.PLATE_NO, TransportCertificateVO::setCarBackPlateNo),
|
||||
/**
|
||||
* 行驶证上的车牌号
|
||||
*/
|
||||
DRIVING_PLATE_NO(List.of(OCRImageType.VEHICLE_LICENSE_MAIN, OCRImageType.VEHICLE_LICENSE_MAIN_OTHERS), OCRKey.KeyInfo.PLATE_NO, TransportCertificateVO::setDrivingPlateNo),
|
||||
/**
|
||||
* 驾驶证有效期限(终⽌时间)
|
||||
*/
|
||||
DRIVER_LICENSE_VALID_DATE_END(List.of(OCRImageType.DRIVER_LICENSE_MAIN, OCRImageType.DRIVER_LICENSE_ELEC), OCRKey.KeyInfo.DATE_VALID, (transportCertificate, dateString) -> convertDateValid(dateString)
|
||||
.accept(transportCertificate::setDriverLicenseValidDateEnd)),
|
||||
/**
|
||||
* 磅单车牌号
|
||||
*/
|
||||
POUND_PLATE_NO(Collections.emptyList(), OCRKey.KeyInfo.PLATE_NO, TransportCertificateVO::setPoundPlateNo),
|
||||
/**
|
||||
* 磅单供货日期
|
||||
*/
|
||||
POUND_DATE(Collections.emptyList(), OCRKey.KeyInfo.DATE, (transportCertificate, dateString) -> convertDate(dateString)
|
||||
.accept(transportCertificate::setSupplyMaterialDate)),
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
UNIT_MEASURE(Collections.emptyList(), OCRKey.KeyInfo.UNIT_MEASURE, TransportCertificateVO::setUnitMeasure),
|
||||
/**
|
||||
* 货品名称
|
||||
*/
|
||||
NAME_GOODS(Collections.emptyList(), OCRKey.KeyInfo.NAME_GOODS, TransportCertificateVO::setProductName),
|
||||
/**
|
||||
* 物料规格
|
||||
*/
|
||||
NAME_MATERIAL(Collections.emptyList(), OCRKey.KeyInfo.NAME_MATERIAL, TransportCertificateVO::setSpecificationMaterial),
|
||||
/**
|
||||
* ⽑重
|
||||
*/
|
||||
GROSS_WEIGHT(Collections.emptyList(), OCRKey.KeyInfo.WEIGHT_GROSS, (transportCertificate, string) -> convertWeightBigDecimal(string)
|
||||
.accept(transportCertificate::setGrossWeight)),
|
||||
/**
|
||||
* ⽪重
|
||||
*/
|
||||
TARE_WEIGHT(Collections.emptyList(), OCRKey.KeyInfo.WEIGHT_TARE, (transportCertificate, string) -> convertWeightBigDecimal(string)
|
||||
.accept(transportCertificate::setSkinWeight)),
|
||||
/**
|
||||
* 净重
|
||||
*/
|
||||
NET_WEIGHT(Collections.emptyList(), OCRKey.KeyInfo.WEIGHT_NET, (transportCertificate, string) -> convertWeightBigDecimal(string)
|
||||
.accept(transportCertificate::setNetWeight)),
|
||||
/**
|
||||
* 扣重
|
||||
*/
|
||||
DEDUCT_WEIGHT(Collections.emptyList(), OCRKey.KeyInfo.WEIGHT_DEDUCT, (transportCertificate, string) -> convertWeightBigDecimal(string)
|
||||
.accept(transportCertificate::setMiscellaneousWeight)),
|
||||
/**
|
||||
* 实际净重
|
||||
*/
|
||||
RECEIVED_WEIGHT(Collections.emptyList(), OCRKey.KeyInfo.WEIGHT_RECEIVED, (transportCertificate, string) -> convertWeightBigDecimal(string)
|
||||
.accept(transportCertificate::setRealityWeight)),
|
||||
|
||||
;
|
||||
/**
|
||||
* 图像类型列表
|
||||
*/
|
||||
private final List<OCRImageType> imageTypes;
|
||||
/**
|
||||
* 字段配置
|
||||
*/
|
||||
private final OCRKey.KeyInfo keyInfo;
|
||||
/**
|
||||
* setter方法
|
||||
*/
|
||||
private final BiConsumer<TransportCertificateVO, String> setter;
|
||||
|
||||
TransportCertificateConvert(OCRImageType imageType, OCRKey.KeyInfo keyInfo, BiConsumer<TransportCertificateVO, String> setter) {
|
||||
this.imageTypes = List.of(imageType);
|
||||
this.keyInfo = keyInfo;
|
||||
this.setter = setter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.springblade.thirdparty.ocr.exception;
|
||||
|
||||
/**
|
||||
* ocr 接口异常
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
public class OCRException extends RuntimeException {
|
||||
public OCRException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public OCRException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springblade.thirdparty.ocr.exception;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.tool.api.R;
|
||||
import org.springblade.core.tool.api.ResultCode;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
/**
|
||||
* @author bfhuange
|
||||
* @since 2025/3/29
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class OCRExceptionTranslator {
|
||||
|
||||
@ExceptionHandler(OCRException.class)
|
||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public R handleError(OCRException e) {
|
||||
log.error("ocr异常", e);
|
||||
return R.fail(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springblade.thirdparty.ocr.feign;
|
||||
|
||||
import org.springblade.thirdparty.ocr.config.OCRFeignClientConfig;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.OCRBigCommonCardBatchDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.OCRBigCommonCardDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.OCRSingleDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.OCRBigCommonCardVO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.OCRResultVO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr接口 磅单接口
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@FeignClient(name = "OCR", url = "${thirdParty.ocr.baseUrl}", configuration = OCRFeignClientConfig.class)
|
||||
public interface IOCRClient {
|
||||
|
||||
/**
|
||||
* 批量磅单卡证识别(⼀个⽂件夹的数据)功能接⼝说明
|
||||
* @param param
|
||||
* @param code
|
||||
*/
|
||||
@PostMapping("/BigCommonCardBatch")
|
||||
OCRResultVO<List<OCRResultVO<OCRBigCommonCardVO>>> batchRecognition(@RequestBody OCRBigCommonCardBatchDTO param, @RequestHeader(value = "code", required = false) String code);
|
||||
|
||||
/**
|
||||
* 磅单卡证识别功能接⼝
|
||||
* @param param
|
||||
*/
|
||||
@PostMapping("/BigCommonCard")
|
||||
OCRResultVO<OCRBigCommonCardVO> singleRecognition(@RequestBody OCRBigCommonCardDTO param, @RequestHeader(value = "code", required = false) String code);
|
||||
|
||||
/**
|
||||
* 磅单单独识别功能接⼝
|
||||
* @param param
|
||||
*/
|
||||
@PostMapping("/logisticRec")
|
||||
OCRResultVO<OCRBigCommonCardVO> poundRecognition(@RequestBody OCRSingleDTO param, @RequestHeader(value = "code", required = false) String code);
|
||||
|
||||
/**
|
||||
* ⻋牌识别单独接⼝
|
||||
* @param param
|
||||
*/
|
||||
@PostMapping("/CLPR")
|
||||
OCRResultVO<OCRBigCommonCardVO> plateNoRecognition(@RequestBody OCRSingleDTO param, @RequestHeader(value = "code", required = false) String code);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.springblade.thirdparty.ocr.feign;
|
||||
|
||||
import org.springblade.thirdparty.ocr.config.OCRFeignClientConfig;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.OCRCardBankDetRecDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.OCRBigCommonCardVO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.OCRResultVO;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr接口 证件接口,因为端口不同,要新建一个
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@FeignClient(name = "OCRO", url = "${thirdParty.ocr.baseOtherUrl}", configuration = OCRFeignClientConfig.class)
|
||||
public interface IOCROtherClient {
|
||||
|
||||
/**
|
||||
* 磅单业务-证件定位+结构化信息提取接⼝
|
||||
* @param param
|
||||
* @return imageInfos 没有
|
||||
*/
|
||||
@PostMapping("/CardBankDetRec")
|
||||
OCRResultVO<OCRBigCommonCardVO> cardBankDetRec(@RequestBody OCRCardBankDetRecDTO param);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package org.springblade.thirdparty.ocr.interceptor;
|
||||
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.log.utils.LogTraceUtil;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRConstant;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author bfhuange
|
||||
* @since 2024/12/26
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
public class OCRRequestInterceptor implements RequestInterceptor {
|
||||
@Override
|
||||
public void apply(RequestTemplate template) {
|
||||
// 请求时间
|
||||
template.header(OCRConstant.REQUEST_HEADER_TIME, DateUtil.formatDateTime(new Date()));
|
||||
String traceId = LogTraceUtil.getTraceIdFromMDC();
|
||||
if (StringUtil.isBlank(traceId)) {
|
||||
traceId = LogTraceUtil.getTraceId();
|
||||
}
|
||||
// traceId
|
||||
template.header(OCRConstant.REQUEST_HEADER_TRACE_ID, traceId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 凭证批量识别参数,所有图像链接统一识别,不分类
|
||||
* @author bfhuange
|
||||
* @since 2025/3/13
|
||||
*/
|
||||
@Data
|
||||
public class CertificateBatchRecognitionDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 所有图像链接列表
|
||||
*/
|
||||
private List<String> urls;
|
||||
/**
|
||||
* 项目简称
|
||||
*/
|
||||
private String projectAbbreviation;
|
||||
/**
|
||||
* 凭证编码
|
||||
*/
|
||||
private String code;
|
||||
/**
|
||||
* 目录名称
|
||||
*/
|
||||
private String dirName;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 凭证识别参数,依次调用单张识别
|
||||
* @author bfhuange
|
||||
* @since 2024/12/13
|
||||
*/
|
||||
@Data
|
||||
public class CertificateRecognitionDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 磅单url
|
||||
*/
|
||||
private String poundUrl;
|
||||
/**
|
||||
* 车头url
|
||||
*/
|
||||
private String carFrontUrl;
|
||||
/**
|
||||
* 驾驶证url
|
||||
*/
|
||||
private String driverLicenseUrl;
|
||||
/**
|
||||
* 行驶证url
|
||||
*/
|
||||
private String vehicleLicenseUrl;
|
||||
/**
|
||||
* 项目简称
|
||||
*/
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr批量磅单卡证识别参数
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class OCRBigCommonCardBatchDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 图像本地路径或者远程服务器地址列表
|
||||
*/
|
||||
@JsonProperty("img_path")
|
||||
private List<String> imgPaths;
|
||||
/**
|
||||
* 项目简称
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String name;
|
||||
/**
|
||||
* 目录名称
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String dirName;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr批量磅单卡证识别参数
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class OCRBigCommonCardDTO extends OCRSingleDTO {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 非必填
|
||||
* 可选值 -1, 0, 1, 2, 3
|
||||
* 输⼊图⽚的⽂本⽅向, 如果需要系统识别则为默认的-1(可不传), 0: 正⽅向, 1:顺时针90度, 2: 180, 3: -90
|
||||
*/
|
||||
@JsonProperty("direction_id")
|
||||
private Integer directionId;
|
||||
/**
|
||||
* 非必填
|
||||
* 可选值 True, False
|
||||
* 是否是区域图, 如果True: 表⽰不需要调⽤证件定位模型获取区域
|
||||
*/
|
||||
@JsonProperty("is_rect")
|
||||
private String isRect;
|
||||
/**
|
||||
* 非必填
|
||||
* ["VehicleLicense-Main", "IDCard-Main", "IDCard-Side", "DriverLicense-Main"]
|
||||
* 需要提取信息的ID列表, 不填写表⽰都要提取, 如果填写则只返回所需要列表中的信息, 返回结构不变
|
||||
*/
|
||||
@JsonProperty("need_data_type")
|
||||
private List<String> needDataTypes;
|
||||
|
||||
public OCRBigCommonCardDTO(String imgPath, String name) {
|
||||
super(imgPath, name);
|
||||
}
|
||||
|
||||
public OCRBigCommonCardDTO(String imgPath, String name, List<String> needDataTypes) {
|
||||
super(imgPath, name);
|
||||
this.needDataTypes = needDataTypes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ocr 证件识别参数
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@Data
|
||||
public class OCRCardBankDetRecDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 图像本地路径或者远程服务器地址,必填
|
||||
*/
|
||||
@JsonProperty("img_path")
|
||||
private String imgPath;
|
||||
/**
|
||||
* 图像内容类型,位置为"", ["", "BankCard-Main","BankCard-Side", "IDCard-Main", "IDCard-Side"] 其他依次对应: 银⾏卡-正⾯、银⾏卡-背⾯、身份证-信息⻚、身份证-国徽⻚,非必填
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@JsonProperty("data_type")
|
||||
private String dataType;
|
||||
|
||||
public OCRCardBankDetRecDTO(String imgPath) {
|
||||
this.imgPath = imgPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ocr单张识别参数
|
||||
* @author bfhuange
|
||||
* @date 2024/12/13
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class OCRSingleDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 图像本地路径或者远程服务器地址
|
||||
*/
|
||||
@JsonProperty("img_path")
|
||||
private String imgPath;
|
||||
/**
|
||||
* 项目简称
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 身份证识别结果
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@Data
|
||||
public class IDCardVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 身份证号
|
||||
*/
|
||||
private String idNo;
|
||||
/**
|
||||
* 有效期止
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE, timezone = "GMT+8")
|
||||
private Date validDateEnd;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRBigCommonCardVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 原始图像的识别信息-图像相关
|
||||
*/
|
||||
// ocr返回的结构有点问题,先注释掉,这个对象没用到
|
||||
//@JsonProperty("image_info")
|
||||
//private OCRImageInfoSummaryVO imageInfos;
|
||||
/**
|
||||
* 每⼀个证件⽬标的识别结果,列表顺序对应type_descriptions中的顺序
|
||||
*/
|
||||
private List<OCRRecognitionResultVO> objects;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 图⽚hash值
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRImageHashVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 感知hash,⽀持轻微旋转移动和轻微质量丢失
|
||||
*/
|
||||
@JsonProperty("phash")
|
||||
private String phash;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 原始图像的识别信息-图像相关
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRImageInfoSummaryVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 图像评分,⽬前只需要取list中的第⼀位即可,1: 正常图像、0: 图像 质量差, 其他值: 算法还需要进⼀步判断
|
||||
*/
|
||||
@JsonProperty("QA_scores")
|
||||
private List<Integer> qaScores;
|
||||
/**
|
||||
* 图像中包含的数据类型(这⾥的顺序对应下⾯结构化结果的顺序)
|
||||
*/
|
||||
@JsonProperty("type_descriptions")
|
||||
private List<String> typeDescriptions;
|
||||
/**
|
||||
* 图像中包含的数据类型id(这⾥的顺序对应下⾯结构化结果的顺序)
|
||||
*/
|
||||
@JsonProperty("type_ids")
|
||||
private List<String> typeIds;
|
||||
/**
|
||||
* 图⽚hash值
|
||||
*/
|
||||
@JsonProperty("img_hash")
|
||||
private OCRImageHashVO imageHash;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 结构化提取后的key-value-description信息
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRKeyInfoVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* ?字段编码
|
||||
*/
|
||||
@JsonProperty("key")
|
||||
private String key;
|
||||
/**
|
||||
* ?字段说明
|
||||
*/
|
||||
@JsonProperty("description")
|
||||
private String description;
|
||||
/**
|
||||
* ?字段值
|
||||
*/
|
||||
@JsonProperty("value")
|
||||
private String value;
|
||||
/**
|
||||
* ?匹配度,有些没有
|
||||
*/
|
||||
@JsonProperty("rec_score")
|
||||
private BigDecimal recScore;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 行信息
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRLineInfoVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* ?? 区域坐标
|
||||
*/
|
||||
@JsonProperty("bbox")
|
||||
private List<Integer> bBoxes;
|
||||
/**
|
||||
* ??
|
||||
*/
|
||||
private String direct;
|
||||
/**
|
||||
* 匹配度 ?
|
||||
*/
|
||||
private BigDecimal score;
|
||||
/**
|
||||
* 文本?
|
||||
*/
|
||||
private String text;
|
||||
/**
|
||||
* ?? 有些没有
|
||||
*/
|
||||
private List<List<BigDecimal>> polygons;
|
||||
/**
|
||||
* ?? 有些没有
|
||||
*/
|
||||
@JsonProperty("position")
|
||||
private List<Integer> positions;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 ⼦⽬标证件的基本识别信息
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRRecognitionImageInfoVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 证件⽬标对于原始图像的坐标位置[x, y, w, h]
|
||||
*/
|
||||
// @JsonProperty("bbox")
|
||||
// private List<Integer> bBoxes;
|
||||
/**
|
||||
* 证件⽬标在原始图像中的⻆度
|
||||
*/
|
||||
// @JsonProperty("image_angle")
|
||||
// private Integer imageAngle;
|
||||
/**
|
||||
* 证件⽬标的证件类型
|
||||
*/
|
||||
// @JsonProperty("type_description")
|
||||
// private String typeDescription;
|
||||
/**
|
||||
* 磅单对应的ID号(⽬前只有磅单返回)
|
||||
*/
|
||||
@JsonProperty("type_id")
|
||||
private String typeId;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 证件⽬标的识别结果
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRRecognitionResultVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 证件⽬标结构化结果(系统调⽤主要使⽤的信息)
|
||||
*/
|
||||
@JsonProperty("structured")
|
||||
private OCRStructureVO structured;
|
||||
/**
|
||||
* ⼦⽬标证件的基本识别信息
|
||||
*/
|
||||
@JsonProperty("image_info")
|
||||
private OCRRecognitionImageInfoVO imageInfo;
|
||||
/**
|
||||
* 所有的识别结果,非必须
|
||||
*/
|
||||
//@JsonProperty("lines")
|
||||
//private List<OCRLineInfoVO> lines;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springblade.core.tool.support.NoErrorFallback;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* ocr 返回结果
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRResultVO<T> implements Serializable, NoErrorFallback {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 程序执⾏状态(200: 成功且为卡证数据,
|
||||
* -1:图像是⻋牌,但质量有问题,
|
||||
* -2: 没有检测出⻋牌或证件⽬标,
|
||||
* -3: 输⼊的img_bas64有问题,
|
||||
* -4: 没有检测出证件,
|
||||
* -5: 输⼊的数据类型不⽀持(⽀持img_bas64/img_path),
|
||||
* -6: C++接⼝问题,
|
||||
* -7: 图像质量问题,有⻋辆没有⻋牌,
|
||||
* -8: 运⾏成功但程序识别内容为空,
|
||||
* -9: json数据异常)
|
||||
*/
|
||||
private Integer code;
|
||||
/**
|
||||
* code的解释说明
|
||||
*/
|
||||
private String message;
|
||||
/**
|
||||
* 返回的识别结果
|
||||
*/
|
||||
private T result;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 磅单卡证识别响应参数 证件⽬标结构化结果
|
||||
* @author bfhuange
|
||||
* @date 2024/11/4
|
||||
*/
|
||||
@Data
|
||||
public class OCRStructureVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 磅单对应的ID号(⽬前只有磅单返回)
|
||||
*/
|
||||
@JsonProperty("type_id")
|
||||
private String typeId;
|
||||
/**
|
||||
* 证件⽬标的证件类型
|
||||
*/
|
||||
@JsonProperty("type_description")
|
||||
private String typeDescription;
|
||||
/**
|
||||
* 磅单对应的ID号的单位(⽬前只有磅单返回), 当未知单位的时候返回"", ⽬前会返回的字段有: t, T, 吨, kg, 公⽄, 千克
|
||||
*/
|
||||
@JsonProperty("unit_measure")
|
||||
private String unitMeasure;
|
||||
/**
|
||||
* 结构化提取后的key-value-description信息
|
||||
*/
|
||||
@JsonProperty("key_info")
|
||||
private List<OCRKeyInfoVO> keyInfos;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package org.springblade.thirdparty.ocr.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 车辆运输凭证
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "车辆运输凭证识别结果")
|
||||
public class TransportCertificateVO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 车头车牌号
|
||||
*/
|
||||
@Schema(description = "车头车牌号")
|
||||
private String carFrontPlateNo;
|
||||
/**
|
||||
* 车尾车牌号
|
||||
*/
|
||||
@Schema(description = "车尾车牌号")
|
||||
private String carBackPlateNo;
|
||||
/**
|
||||
* 行驶证上的车牌号
|
||||
*/
|
||||
@Schema(description = "行驶证上的车牌号")
|
||||
private String drivingPlateNo;
|
||||
/**
|
||||
* 驾驶证有效期限(终⽌时间)
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE,timezone = "GMT+8")
|
||||
@Schema(description = "驾驶证有效期限(终⽌时间)")
|
||||
private Date driverLicenseValidDateEnd;
|
||||
/**
|
||||
* 磅单车牌号
|
||||
*/
|
||||
@Schema(description = "磅单车牌号")
|
||||
private String poundPlateNo;
|
||||
/**
|
||||
* 磅单供货日期
|
||||
*/
|
||||
@JsonFormat(pattern = DateUtil.PATTERN_DATE,timezone = "GMT+8")
|
||||
@Schema(description = "磅单供货日期")
|
||||
private Date supplyMaterialDate;
|
||||
/**
|
||||
* 货物名称
|
||||
*/
|
||||
@Schema(description = "货物名称")
|
||||
private String productName;
|
||||
/**
|
||||
* 规格料型
|
||||
*/
|
||||
@Schema(description = "规格料型")
|
||||
private String specificationMaterial;
|
||||
/**
|
||||
* 单位
|
||||
*/
|
||||
@Schema(description = "单位")
|
||||
private String unitMeasure;
|
||||
/**
|
||||
* ⽑重
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class, nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "⽑重")
|
||||
private BigDecimal grossWeight;
|
||||
/**
|
||||
* ⽪重
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class, nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "⽪重")
|
||||
private BigDecimal skinWeight;
|
||||
/**
|
||||
* 净重
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class, nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "净重")
|
||||
private BigDecimal netWeight;
|
||||
/**
|
||||
* 扣重
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class, nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "扣重")
|
||||
private BigDecimal miscellaneousWeight;
|
||||
/**
|
||||
* 实际净重
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class, nullsUsing = NullSerializer.class)
|
||||
@Schema(description = "实际净重")
|
||||
private BigDecimal realityWeight;
|
||||
/**
|
||||
* 磅单附件索引,只取一个,其余的丢弃
|
||||
*/
|
||||
@Schema(description = "磅单附件索引,只取一个,其余的丢弃")
|
||||
private List<Integer> poundIndexes = new ArrayList<>();
|
||||
/**
|
||||
* 驾驶证附件索引,只取一个,其余的丢弃
|
||||
*/
|
||||
@Schema(description = "驾驶证附件索引,只取一个,其余的丢弃")
|
||||
private List<Integer> driverLicenseIndexes = new ArrayList<>();
|
||||
/**
|
||||
* 行驶证附件索引,只取一个,其余的丢弃
|
||||
*/
|
||||
@Schema(description = "行驶证附件索引,只取一个,其余的丢弃")
|
||||
private List<Integer> vehicleLicenseIndexes = new ArrayList<>();
|
||||
/**
|
||||
* 车头附件索引,只取一个,其余的丢弃
|
||||
*/
|
||||
@Schema(description = "车头附件索引,只取一个,其余的丢弃")
|
||||
private List<Integer> carFrontIndexes = new ArrayList<>();
|
||||
/**
|
||||
* 车尾附件索引,只取一个,其余的丢弃
|
||||
*/
|
||||
@Schema(description = "车尾附件索引,只取一个,其余的丢弃")
|
||||
private List<Integer> carBackIndexes = new ArrayList<>();
|
||||
/**
|
||||
* 其他附件索引
|
||||
*/
|
||||
@Schema(description = "其他附件索引")
|
||||
private List<Integer> otherIndexes = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package org.springblade.thirdparty.ocr.service;
|
||||
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.CertificateBatchRecognitionDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.dto.CertificateRecognitionDTO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.IDCardVO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ocr 接口
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
public interface IOCRService {
|
||||
|
||||
/**
|
||||
* 识别车辆运输凭证,同一个车辆的图片地址批量传入,不知道每张图片类型
|
||||
* @param param 参数
|
||||
* @return
|
||||
*/
|
||||
TransportCertificateVO recognitionTransportCertificate(CertificateBatchRecognitionDTO param);
|
||||
|
||||
/**
|
||||
* 识别车辆运输凭证,依次调用单独识别接口,知道每张图片类型
|
||||
*
|
||||
* @param param 各个类型图片链接
|
||||
* @param code
|
||||
* @return
|
||||
*/
|
||||
TransportCertificateVO recognitionTransportCertificate(CertificateRecognitionDTO param, String code);
|
||||
|
||||
/**
|
||||
* 识别身份证,支持同时传同一身份证的正反面,不同身份证的会覆盖
|
||||
* @param urls 图片链接列表
|
||||
* @return
|
||||
*/
|
||||
IDCardVO recognitionIDCard(List<String> urls);
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
package org.springblade.thirdparty.ocr.service.impl;
|
||||
|
||||
import cn.hutool.core.lang.TypeReference;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.springblade.core.tool.utils.CollectionUtil;
|
||||
import org.springblade.core.tool.utils.ObjectUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRConstant;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.convert.AttachmentIndexConvert;
|
||||
import org.springblade.thirdparty.ocr.exception.OCRException;
|
||||
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.vo.*;
|
||||
import org.springblade.thirdparty.ocr.service.IOCRService;
|
||||
import org.springblade.thirdparty.ocr.util.ConvertUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author bfhuange
|
||||
* @date 2024/11/6
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class OCRServiceImpl implements IOCRService {
|
||||
/**
|
||||
* 限制 200,超过转为kg,否则为t
|
||||
*/
|
||||
private static final BigDecimal WEIGHT_LIMIT = BigDecimal.valueOf(200);
|
||||
|
||||
private final IOCRClient client;
|
||||
private final IOCROtherClient otherClient;
|
||||
|
||||
@Override
|
||||
public TransportCertificateVO recognitionTransportCertificate(CertificateBatchRecognitionDTO param) {
|
||||
log.info("ocr 批量识别参数:{}", JSONUtil.toJsonStr(param));
|
||||
if (param == null || CollectionUtils.isEmpty(param.getUrls())) {
|
||||
throw new OCRException("图像链接不能为空");
|
||||
}
|
||||
List<OCRResultVO<OCRBigCommonCardVO>> result = this.getCardResult(() -> client.batchRecognition(new OCRBigCommonCardBatchDTO(param.getUrls(), param.getProjectAbbreviation(), param.getDirName()), param.getCode()), "批量磅单卡证识别");
|
||||
List<OCRBigCommonCardVO> cards = result.stream()
|
||||
.map(OCRResultVO::getResult)
|
||||
.toList();
|
||||
return convertTransportCertificate(cards);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportCertificateVO recognitionTransportCertificate(CertificateRecognitionDTO param, String code) {
|
||||
log.info("ocr 单张识别参数:{}", JSONUtil.toJsonStr(param));
|
||||
if (param == null || ObjectUtil.isEmpty(param)) {
|
||||
throw new OCRException("凭证识别参数不能为空");
|
||||
}
|
||||
List<OCRBigCommonCardVO> cards = new ArrayList<>(4);
|
||||
if (StringUtil.isNotBlank(param.getPoundUrl())) {
|
||||
// 磅单
|
||||
OCRBigCommonCardVO card = this.getCardResult(() -> client.poundRecognition(new OCRSingleDTO(param.getPoundUrl(), param.getName()), code), "磅单单独识别");
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
if (StringUtil.isNotBlank(param.getDriverLicenseUrl())) {
|
||||
// 驾驶证
|
||||
OCRBigCommonCardVO card = this.getCardResult(() -> client.singleRecognition(new OCRBigCommonCardDTO(param.getDriverLicenseUrl(), param.getName(),
|
||||
// 驾驶证-正页
|
||||
List.of(OCRImageType.DRIVER_LICENSE_MAIN.getId(),
|
||||
// 驾驶证-副页
|
||||
OCRImageType.DRIVER_LICENSE_SIDE.getId(),
|
||||
// 驾驶证-电子版
|
||||
OCRImageType.DRIVER_LICENSE_ELEC.getId())), code
|
||||
), "驾驶证识别");
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
if (StringUtil.isNotBlank(param.getVehicleLicenseUrl())) {
|
||||
// 行驶证
|
||||
OCRBigCommonCardVO card = this.getCardResult(() -> client.singleRecognition(new OCRBigCommonCardDTO(param.getVehicleLicenseUrl(), param.getName(),
|
||||
// ⾏驶证-正⻚-挂车
|
||||
List.of(OCRImageType.VEHICLE_LICENSE_MAIN_GUA.getId(),
|
||||
// ⾏驶证-正⻚
|
||||
OCRImageType.VEHICLE_LICENSE_MAIN.getId(),
|
||||
// ⾏驶证-副⻚
|
||||
OCRImageType.VEHICLE_LICENSE_SIDE.getId())), code
|
||||
), "行驶证识别");
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
if (StringUtil.isNotBlank(param.getCarFrontUrl())) {
|
||||
// 车头
|
||||
OCRBigCommonCardVO card = this.getCardResult(() -> client.plateNoRecognition(new OCRSingleDTO(param.getCarFrontUrl(), param.getName()), code), "⻋牌单独识别");
|
||||
if (card != null) {
|
||||
cards.add(card);
|
||||
}
|
||||
}
|
||||
return CollectionUtil.isEmpty(cards) ? null : convertTransportCertificate(cards);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取卡证结果
|
||||
* @param resultSupplier
|
||||
* @param name
|
||||
* @return
|
||||
*/
|
||||
private <T> T getCardResult(Supplier<OCRResultVO<T>> resultSupplier, String name) {
|
||||
try {
|
||||
OCRResultVO<T> resultVO = resultSupplier.get();
|
||||
log.info("调用ocr接口 {} 响应参数:{}", name, JSONUtil.toJsonStr(resultVO));
|
||||
if (resultVO != null && OCRConstant.SUCCESS_CODE.equals(resultVO.getCode())) {
|
||||
// 成功
|
||||
return resultVO.getResult();
|
||||
}
|
||||
log.error("调用ocr接口 {} 异常响应参数:{}", name, JSONUtil.toJsonStr(resultVO));
|
||||
String message = getMessage(resultVO);
|
||||
throw new OCRException("调用ocr接口" + name + "异常 " + message);
|
||||
} catch (OCRException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("调用ocr接口 {} 异常", name, e);
|
||||
throw new OCRException("调用ocr接口" + name + "异常");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换车辆凭证
|
||||
* @param cards
|
||||
* @return
|
||||
*/
|
||||
private static TransportCertificateVO convertTransportCertificate(List<OCRBigCommonCardVO> cards) {
|
||||
TransportCertificateVO result = new TransportCertificateVO();
|
||||
if (CollectionUtils.isEmpty(cards)) {
|
||||
return result;
|
||||
}
|
||||
OCRBigCommonCardVO card = null;
|
||||
for (int index = 0; index < cards.size(); index++) {
|
||||
card = cards.get(index);
|
||||
convert(result, card, ConvertUtil::getTransportCertificateSetter, index);
|
||||
}
|
||||
// 处理重量单位
|
||||
handleWeightUnit(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理重量单位
|
||||
* @param result
|
||||
*/
|
||||
private static void handleWeightUnit(TransportCertificateVO result) {
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
// 重量超过200,默认kg,否则t
|
||||
if (overLimit(result.getGrossWeight()) || overLimit(result.getSkinWeight()) || overLimit(result.getNetWeight())) {
|
||||
// 毛重、皮重、净重 超过限制,是kg
|
||||
result.setGrossWeight(divideThousand(result.getGrossWeight()));
|
||||
result.setSkinWeight(divideThousand(result.getSkinWeight()));
|
||||
result.setNetWeight(divideThousand(result.getNetWeight()));
|
||||
result.setMiscellaneousWeight(divideThousand(result.getMiscellaneousWeight()));
|
||||
result.setRealityWeight(divideThousand(result.getRealityWeight()));
|
||||
return;
|
||||
}
|
||||
String unitMeasure = result.getUnitMeasure();
|
||||
if (OCRConstant.UNIT_T.equalsIgnoreCase(unitMeasure) || OCRConstant.UNIT_T_ZH.equals(unitMeasure)) {
|
||||
// t或者吨,无需处理
|
||||
return;
|
||||
}
|
||||
if (OCRConstant.UNIT_KG.equalsIgnoreCase(unitMeasure)) {
|
||||
// kg,转成吨保留5位小数
|
||||
result.setGrossWeight(divideThousand(result.getGrossWeight()));
|
||||
result.setSkinWeight(divideThousand(result.getSkinWeight()));
|
||||
result.setNetWeight(divideThousand(result.getNetWeight()));
|
||||
result.setMiscellaneousWeight(divideThousand(result.getMiscellaneousWeight()));
|
||||
result.setRealityWeight(divideThousand(result.getRealityWeight()));
|
||||
return;
|
||||
}
|
||||
if (StringUtil.isNotBlank(unitMeasure)) {
|
||||
log.warn("未知的单位类型:{}", unitMeasure);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否超过限制
|
||||
* @param weight
|
||||
* @return
|
||||
*/
|
||||
private static boolean overLimit(BigDecimal weight) {
|
||||
return weight != null && weight.compareTo(WEIGHT_LIMIT) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 除以1000保留5位小数
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
private static BigDecimal divideThousand(BigDecimal num) {
|
||||
if (num == null) {
|
||||
return null;
|
||||
}
|
||||
return num.divide(BigDecimal.valueOf(1000), 5, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDCardVO recognitionIDCard(List<String> urls) {
|
||||
if (CollectionUtils.isEmpty(urls)) {
|
||||
throw new OCRException("图像链接不能为空");
|
||||
}
|
||||
IDCardVO result = new IDCardVO();
|
||||
try {
|
||||
for (String url : urls) {
|
||||
OCRCardBankDetRecDTO param = new OCRCardBankDetRecDTO(url);
|
||||
OCRResultVO<OCRBigCommonCardVO> resultVO = otherClient.cardBankDetRec(param);
|
||||
if (resultVO != null && OCRConstant.SUCCESS_CODE.equals(resultVO.getCode())) {
|
||||
// 成功
|
||||
OCRBigCommonCardVO card = resultVO.getResult();
|
||||
convertIDCard(result, card);
|
||||
continue;
|
||||
}
|
||||
log.error("调用ocr接口证件定位+结构化信息提取异常响应参数:{}", JSONUtil.toJsonStr(resultVO));
|
||||
String message = getMessage(resultVO);
|
||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常 " + message);
|
||||
}
|
||||
} catch (OCRException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("调用ocr接口证件定位+结构化信息提取异常", e);
|
||||
throw new OCRException("调用ocr接口证件定位+结构化信息提取异常");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换身份证
|
||||
* @param result
|
||||
* @param card
|
||||
* @return
|
||||
*/
|
||||
private void convertIDCard(IDCardVO result, OCRBigCommonCardVO card) {
|
||||
convert(result, card, ConvertUtil::getIDCardSetter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*
|
||||
* @param <T>
|
||||
* @param result
|
||||
* @param card
|
||||
* @param setterGetter
|
||||
* @param index
|
||||
*/
|
||||
private static <T> void convert(T result, OCRBigCommonCardVO card, BiFunction<String, String, BiConsumer<T, String>> setterGetter, Integer index) {
|
||||
if (result == null || card == null || setterGetter == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<OCRRecognitionResultVO> objects = card.getObjects();
|
||||
if (CollectionUtils.isEmpty(objects)) {
|
||||
return;
|
||||
}
|
||||
// 排序类型
|
||||
sortByTypeId(objects);
|
||||
for (OCRRecognitionResultVO object : objects) {
|
||||
OCRStructureVO structured = object.getStructured();
|
||||
String typeId = getTypeId(object);
|
||||
if (typeId == null) {
|
||||
continue;
|
||||
}
|
||||
// 是否处理数据
|
||||
boolean handleData = true;
|
||||
if (index != null && result instanceof TransportCertificateVO transportCertificate) {
|
||||
// 车辆凭证类型,添加索引到list
|
||||
// 添加到默认list要处理数据,添加到其他list,不处理数据
|
||||
handleData = AttachmentIndexConvert.getConvertByTypeId(typeId)
|
||||
.addIndex2list(transportCertificate, index);
|
||||
}
|
||||
if (structured == null || !handleData) {
|
||||
// 提取的数据为空或添加到了其他附件,不处理数据了,保持图片和数据一致
|
||||
continue;
|
||||
}
|
||||
List<OCRKeyInfoVO> keyInfos = structured.getKeyInfos();
|
||||
if (CollectionUtils.isEmpty(keyInfos)) {
|
||||
continue;
|
||||
}
|
||||
for (OCRKeyInfoVO keyInfo : keyInfos) {
|
||||
// 根据typeId和key查找setter,找到了执行
|
||||
Optional.ofNullable(setterGetter.apply(typeId, keyInfo.getKey()))
|
||||
.ifPresent(consumer -> consumer.accept(result, keyInfo.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按类型排序
|
||||
* @param objects
|
||||
*/
|
||||
private static void sortByTypeId(List<OCRRecognitionResultVO> objects) {
|
||||
// 行驶证类型的,把 VehicleLicense-Main 放到第一个,优先取它的数据
|
||||
List<String> imageTypeIds = AttachmentIndexConvert.VEHICLE_LICENSE.getImageTypeIds();
|
||||
boolean vehicleLicense = objects.stream()
|
||||
.map(OCRServiceImpl::getTypeId)
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(imageTypeIds::contains);
|
||||
if (vehicleLicense) {
|
||||
objects.sort(Comparator.comparing(OCRServiceImpl::getTypeId, Comparator.comparing(typeId -> {
|
||||
if (typeId == null) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
int index = imageTypeIds.indexOf(typeId);
|
||||
if (index < 0) {
|
||||
return Integer.MAX_VALUE - 1;
|
||||
}
|
||||
return index;
|
||||
})));
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getTypeId(OCRRecognitionResultVO object) {
|
||||
OCRStructureVO structured = object.getStructured();
|
||||
String typeId = Optional.ofNullable(structured)
|
||||
.map(OCRStructureVO::getTypeId)
|
||||
.orElse(null);
|
||||
if (typeId == null) {
|
||||
// typeId为空,从 imageInfo 中取
|
||||
OCRRecognitionImageInfoVO imageInfo = object.getImageInfo();
|
||||
typeId = Optional.ofNullable(imageInfo)
|
||||
.map(OCRRecognitionImageInfoVO::getTypeId)
|
||||
.orElse(null);
|
||||
}
|
||||
return typeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误消息
|
||||
* @param resultVO
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
private <T> String getMessage(OCRResultVO<T> resultVO) {
|
||||
return resultVO == null ? "" : resultVO.getMessage();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String json = "";
|
||||
OCRResultVO<List<OCRResultVO<OCRBigCommonCardVO>>> resultVO = JSONUtil.toBean(json, new TypeReference<OCRResultVO<List<OCRResultVO<OCRBigCommonCardVO>>>>() {
|
||||
}, true);
|
||||
if (resultVO != null && OCRConstant.SUCCESS_CODE.equals(resultVO.getCode())) {
|
||||
// 成功
|
||||
List<OCRResultVO<OCRBigCommonCardVO>> result = resultVO.getResult();
|
||||
List<OCRBigCommonCardVO> cards = result.stream()
|
||||
.map(OCRResultVO::getResult)
|
||||
.toList();
|
||||
TransportCertificateVO transportCertificateVO = convertTransportCertificate(cards);
|
||||
System.out.println(JSONUtil.toJsonStr(transportCertificateVO));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
package org.springblade.thirdparty.ocr.util;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springblade.core.tool.utils.DateUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springblade.thirdparty.ocr.constant.OCRImageType;
|
||||
import org.springblade.thirdparty.ocr.convert.IDCardConvert;
|
||||
import org.springblade.thirdparty.ocr.convert.TransportCertificateConvert;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.IDCardVO;
|
||||
import org.springblade.thirdparty.ocr.pojo.vo.TransportCertificateVO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 转换工具类
|
||||
* @author bfhuange
|
||||
* @date 2024/11/7
|
||||
*/
|
||||
@Slf4j
|
||||
public class ConvertUtil {
|
||||
private ConvertUtil() {}
|
||||
|
||||
/**
|
||||
* 有效期分隔符
|
||||
*/
|
||||
private static final String DATE_VALID_SPLIT = "至";
|
||||
/**
|
||||
* 有效期至 长期
|
||||
*/
|
||||
private static final String DATE_VALID_END_LONG_TERM = "长期";
|
||||
|
||||
/**
|
||||
* 非磅单类型set
|
||||
*/
|
||||
private static final Set<String> NONE_POUND_TYPE_SET = initNonePoundTypeSet();
|
||||
/**
|
||||
* 车辆凭证setter map
|
||||
*/
|
||||
private static final Map<String, BiConsumer<TransportCertificateVO, String>> TRANSPORT_CERTIFICATE_SETTER_MAP = initTransportCertificateSetterMap();
|
||||
/**
|
||||
* 身份证setter map
|
||||
*/
|
||||
private static final Map<String, Map<String, BiConsumer<IDCardVO, String>>> ID_CARD_SETTER_MAP = initIDCardSetterMap();
|
||||
|
||||
/**
|
||||
* 获取车辆凭证setter
|
||||
* @param typeId
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static BiConsumer<TransportCertificateVO, String> getTransportCertificateSetter(String typeId, String key) {
|
||||
String mapKey = ConvertUtil.generateKey(typeId, key);
|
||||
return TRANSPORT_CERTIFICATE_SETTER_MAP.get(mapKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取身份证setter
|
||||
* @param typeId
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static BiConsumer<IDCardVO, String> getIDCardSetter(String typeId, String key) {
|
||||
Map<String, BiConsumer<IDCardVO, String>> setterMap = ID_CARD_SETTER_MAP.get(typeId);
|
||||
if (setterMap == null) {
|
||||
return null;
|
||||
}
|
||||
BiConsumer<IDCardVO, String> setter = setterMap.get(key);
|
||||
if (setter == null) {
|
||||
return null;
|
||||
}
|
||||
return setter;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换日期
|
||||
* @param dateString
|
||||
* @return
|
||||
*/
|
||||
public static Consumer<Consumer<Date>> convertDate(String dateString) {
|
||||
Date date = ConvertUtil.convert2date(dateString);
|
||||
return consumer -> consumer.accept(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换有效期
|
||||
* @param dateString
|
||||
* @return
|
||||
*/
|
||||
public static Consumer<Consumer<Date>> convertDateValid(String dateString) {
|
||||
Date date = ConvertUtil.convert2dateValid(dateString);
|
||||
return consumer -> consumer.accept(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换有效期
|
||||
* @param dateString 日期字符串,2015-05-31至2025-05-31
|
||||
* @return
|
||||
*/
|
||||
private static Date convert2dateValid(String dateString) {
|
||||
if (StringUtil.isBlank(dateString)) {
|
||||
return null;
|
||||
}
|
||||
if (dateString.contains(DATE_VALID_END_LONG_TERM)) {
|
||||
// 如果有效期至是长期,设置为10年后
|
||||
return DateUtil.plusYears(new Date(), 10);
|
||||
}
|
||||
// 按至分隔,解析最后一截日期
|
||||
String[] splitDate = dateString.split(DATE_VALID_SPLIT);
|
||||
return ConvertUtil.convert2date(splitDate[splitDate.length -1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取有效期止
|
||||
* @param dateString
|
||||
* @return
|
||||
*/
|
||||
public static Consumer<Consumer<Date>> extractEndDate(String dateString) {
|
||||
Date date = ConvertUtil.parseEndDate(dateString);
|
||||
return consumer -> consumer.accept(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析有效期止
|
||||
* @param dateString 日期字符串,格式 2020.12.15-2030.12.15
|
||||
* @return
|
||||
*/
|
||||
private static Date parseEndDate(String dateString) {
|
||||
if (dateString == null || dateString.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
dateString = dateString.substring(dateString.lastIndexOf("-") + 1);
|
||||
return DateUtil.parse(dateString, "yyyy.MM.dd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换重量数值
|
||||
*
|
||||
* @param numString 重量字符串
|
||||
* @return
|
||||
*/
|
||||
public static Consumer<Consumer<BigDecimal>> convertWeightBigDecimal(String numString) {
|
||||
BigDecimal bigDecimal = ConvertUtil.convert2WeightBigDecimal(numString);
|
||||
return consumer -> consumer.accept(bigDecimal);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转日期
|
||||
* @param dateString
|
||||
* @return
|
||||
*/
|
||||
private static Date convert2date(String dateString) {
|
||||
if (dateString == null || dateString.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DateUtil.parse(dateString, "yyyy-MM-dd");
|
||||
} catch (Exception e) {
|
||||
log.error("解析日期异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转数值
|
||||
*
|
||||
* @param numString
|
||||
* @return
|
||||
*/
|
||||
public static BigDecimal convert2WeightBigDecimal(String numString) {
|
||||
if (numString == null || numString.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(numString);
|
||||
} catch (Exception e) {
|
||||
log.error("解析数值异常", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 非磅单类型set
|
||||
* @return
|
||||
*/
|
||||
private static Set<String> initNonePoundTypeSet() {
|
||||
return Stream.of(OCRImageType.values())
|
||||
.map(OCRImageType::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化setter map
|
||||
* @return
|
||||
*/
|
||||
private static Map<String, BiConsumer<TransportCertificateVO, String>> initTransportCertificateSetterMap() {
|
||||
Map<String, BiConsumer<TransportCertificateVO, String>> setterMap = new HashMap<>();
|
||||
for (TransportCertificateConvert convert : TransportCertificateConvert.values()) {
|
||||
if (convert.getImageTypes().isEmpty()) {
|
||||
// 图像类型列表为空,设置类型id为空,只用key
|
||||
String key = ConvertUtil.generateKey(null, convert.getKeyInfo().getKey());
|
||||
setterMap.put(key, convert.getSetter());
|
||||
} else {
|
||||
for (OCRImageType imageType : convert.getImageTypes()) {
|
||||
// 图像类型列表不为空,每个类型id和key重新生成key
|
||||
String key = ConvertUtil.generateKey(imageType.getId(), convert.getKeyInfo().getKey());
|
||||
setterMap.put(key, convert.getSetter());
|
||||
}
|
||||
}
|
||||
}
|
||||
return setterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化 身份证 setter map
|
||||
* @return
|
||||
*/
|
||||
private static Map<String, Map<String, BiConsumer<IDCardVO, String>>> initIDCardSetterMap() {
|
||||
return Stream.of(IDCardConvert.values())
|
||||
// 先按类型id分组
|
||||
.collect(Collectors.groupingBy(convert -> convert.getImageType().getId(),
|
||||
// 再按key分组
|
||||
Collectors.toMap(convert -> convert.getKeyInfo().getKey(), IDCardConvert::getSetter, (a, b) -> a)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成key,typeId + - + key
|
||||
* @param typeId
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
private static String generateKey(String typeId, String key) {
|
||||
return typeId == null || !NONE_POUND_TYPE_SET.contains(typeId)? key : typeId + "-" + key;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
org.springblade.thirdparty.ocr.config.ThirdPartyOCRAutoConfiguration
|
||||
Reference in New Issue
Block a user