From 6cc5dc58de97a273a4cc0274cfa9ae6ed159016c Mon Sep 17 00:00:00 2001 From: wucongxing8150 <815046773@qq.com> Date: Mon, 30 Jun 2025 16:48:39 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=86=E8=BA=AB=E4=BB=BD?= =?UTF-8?q?=E8=AF=81=E8=AF=86=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sa-admin/pom.xml | 5 + .../admin/constant/AdminSwaggerTagConst.java | 2 +- .../sa/admin/extend/baidubce/Base.java | 33 +++++ .../lab1024/sa/admin/extend/baidubce/Ocr.java | 30 +++++ .../sa/admin/extend/fangxinqian/Base.java | 2 +- .../expert/controller/ExpertController.java | 2 - .../app/expert/service/ExpertService.java | 2 - .../app/file/controller/ImageController.java | 51 ++++++++ .../app/file/domain/vo/GetIdCardOcrVo.java | 16 +++ .../module/app/file/service/OcrService.java | 116 ++++++++++++++++++ .../src/main/resources/dev/application.yaml | 27 ++-- 11 files changed, 269 insertions(+), 17 deletions(-) create mode 100644 sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Base.java create mode 100644 sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Ocr.java create mode 100644 sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/controller/ImageController.java create mode 100644 sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/domain/vo/GetIdCardOcrVo.java create mode 100644 sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/service/OcrService.java diff --git a/sa-admin/pom.xml b/sa-admin/pom.xml index 3bc1422..27b7998 100644 --- a/sa-admin/pom.xml +++ b/sa-admin/pom.xml @@ -33,6 +33,11 @@ weixin-java-miniapp + + com.baidu.aip + java-sdk + 4.16.22 + diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java index d9eb902..74bfe7e 100644 --- a/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java @@ -60,7 +60,7 @@ public class AdminSwaggerTagConst extends SwaggerTagConst { public static final String Expert = "前端-登录、注册、首页"; public static final String ExpertSign = "前端-医生签名"; - public static final String OSS = "前端-oss"; + public static final String OSS = "前端-文件"; public static final String WX_MINI = "前端-微信小程序"; } } diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Base.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Base.java new file mode 100644 index 0000000..afdb394 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Base.java @@ -0,0 +1,33 @@ +package net.lab1024.sa.admin.extend.baidubce; + +import com.baidu.aip.ocr.AipOcr; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Slf4j +@Getter +@Component("baiducebase") +public class Base { + @Value("${baiduce.app-id}") + private String appId; + + @Value("${baiduce.app-key}") + private String appkey; + + @Value("${baiduce.app-secret}") + private String appSecret; + + // AipOcr 实例 + protected AipOcr ocrClient; + + @PostConstruct + public void init() { + ocrClient = new AipOcr(appId, appkey, appSecret); + ocrClient.setConnectionTimeoutInMillis(2000); + ocrClient.setSocketTimeoutInMillis(60000); + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Ocr.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Ocr.java new file mode 100644 index 0000000..519edd0 --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/baidubce/Ocr.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.admin.extend.baidubce; + +import java.util.HashMap; + +import com.baidu.aip.ocr.AipOcr; +import net.lab1024.sa.common.common.domain.ResponseDTO; +import net.lab1024.sa.common.common.exception.BusinessException; +import org.json.JSONObject; +import org.springframework.stereotype.Component; + +// 通用文字识别 +@Component +public class Ocr extends Base { + + /** + * 身份证识别 + */ + public JSONObject idCard(byte[] imageBytes,String idCardSide) { + try { + HashMap options = new HashMap<>(); + options.put("detect_direction", "true"); + options.put("detect_risk", "true"); + + return ocrClient.idcard(imageBytes, idCardSide, options); + + } catch (Exception e) { + throw new BusinessException("OCR识别失败: " + e.getMessage()); + } + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/fangxinqian/Base.java b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/fangxinqian/Base.java index 13c468e..c5182db 100644 --- a/sa-admin/src/main/java/net/lab1024/sa/admin/extend/fangxinqian/Base.java +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/extend/fangxinqian/Base.java @@ -18,7 +18,7 @@ import java.util.Map; import java.util.concurrent.TimeUnit; @Slf4j -@Component +@Component("fangxinqianbase") @Getter public class Base { private static final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/controller/ExpertController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/controller/ExpertController.java index 40437b2..f1981c1 100644 --- a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/controller/ExpertController.java +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/controller/ExpertController.java @@ -634,6 +634,4 @@ public class ExpertController { return ResponseDTO.error(ExpertBankVerifyFail); } } - - } diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/service/ExpertService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/service/ExpertService.java index 2bc34f6..1f74b7c 100644 --- a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/service/ExpertService.java +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/expert/service/ExpertService.java @@ -77,6 +77,4 @@ public class ExpertService { addForm.setToken(token); return addForm; } - - } diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/controller/ImageController.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/controller/ImageController.java new file mode 100644 index 0000000..4e6facc --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/controller/ImageController.java @@ -0,0 +1,51 @@ +package net.lab1024.sa.admin.module.app.file.controller; + +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.extend.baidubce.Ocr; +import net.lab1024.sa.admin.module.app.file.domain.vo.GetIdCardOcrVo; +import net.lab1024.sa.admin.module.app.file.service.OcrService; +import net.lab1024.sa.admin.module.business.bankcard.domain.form.CaseplatformBankAddForm; +import net.lab1024.sa.common.common.domain.ResponseDTO; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.validation.Valid; + +@RestController +@Api(tags = {AdminSwaggerTagConst.App.OSS}) +public class ImageController { + + @Resource + private OcrService ocrService; + + @ApiOperation(value = "身份证识别-ocr") + @PostMapping("/ocr/idCard") + public ResponseDTO getIdCardOcr( + @RequestParam("frontFile") MultipartFile frontFile, + @RequestParam("backFile") MultipartFile backFile + ){ + if (frontFile == null || frontFile.isEmpty()) { + return ResponseDTO.userErrorParam("参数错误"); + } + + if (backFile == null || backFile.isEmpty()) { + return ResponseDTO.userErrorParam("参数错误"); + } + + try { + byte[] frontBytes = frontFile.getBytes(); + byte[] backBytes = backFile.getBytes(); + + // 调用 Service + GetIdCardOcrVo result = ocrService.getIdCardOcr(frontBytes, backBytes); + return ResponseDTO.app_ok(result); + + } catch (Exception e) { + return ResponseDTO.userErrorParam("识别失败:" + e.getMessage()); + } + + } +} diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/domain/vo/GetIdCardOcrVo.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/domain/vo/GetIdCardOcrVo.java new file mode 100644 index 0000000..44ed69c --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/domain/vo/GetIdCardOcrVo.java @@ -0,0 +1,16 @@ +package net.lab1024.sa.admin.module.app.file.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class GetIdCardOcrVo { + @ApiModelProperty(value = "身份证姓名") + private String idCardName; + + @ApiModelProperty(value = "身份证号") + private String idCardNo; +} + diff --git a/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/service/OcrService.java b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/service/OcrService.java new file mode 100644 index 0000000..706951a --- /dev/null +++ b/sa-admin/src/main/java/net/lab1024/sa/admin/module/app/file/service/OcrService.java @@ -0,0 +1,116 @@ +package net.lab1024.sa.admin.module.app.file.service; + +import net.lab1024.sa.admin.extend.baidubce.Ocr; +import net.lab1024.sa.admin.extend.fangxinqian.company.Company; +import net.lab1024.sa.admin.module.app.expert.admin.ExpertSignVO; +import net.lab1024.sa.admin.module.app.expert.dao.ExpertSignDao; +import net.lab1024.sa.admin.module.app.file.domain.vo.GetIdCardOcrVo; +import net.lab1024.sa.common.common.exception.BusinessException; +import net.lab1024.sa.common.common.util.SmartRequestUtil; +import org.json.JSONObject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +@Service +public class OcrService { + + @Resource + private Ocr ocr; + + /** + * 身份证识别 + */ + public GetIdCardOcrVo getIdCardOcr(byte[] frontBytes,byte[] backBytes) { + try { + // 反面 + JSONObject result = ocr.idCard(backBytes,"back"); + + String imageStatus = result.getString("image_status"); + switch (imageStatus) { + case "normal": + // 识别正常,继续处理 + break; + case "reversed_side": + throw new BusinessException("身份证未摆正,请重新上传"); + case "non_idcard": + throw new BusinessException("上传的图片中不包含身份证,请上传正确图片"); + case "blurred": + throw new BusinessException("身份证模糊,请重新上传清晰图片"); + case "over_exposure": + throw new BusinessException("身份证关键字段反光或过曝,请重新拍摄"); + case "unknown": + default: + throw new BusinessException("无法识别身份证,请重新上传"); + } + + if (result.has("risk_type")) { + String riskType = result.getString("risk_type"); + if (!"normal".equals(riskType)) { + switch (riskType) { + case "copy": + throw new BusinessException("检测到复印件身份证,请上传原件"); + case "temporary": + throw new BusinessException("检测到临时身份证,请上传正式身份证"); + case "screen": + throw new BusinessException("检测到翻拍身份证,请上传原件照片"); + case "unknow": + default: + throw new BusinessException("身份证真实性存疑,请重新上传"); + } + } + } + + // 正面 + result = ocr.idCard(frontBytes,"front"); + + imageStatus = result.getString("image_status"); + switch (imageStatus) { + case "normal": + // 识别正常,继续处理 + break; + case "reversed_side": + throw new BusinessException("身份证未摆正,请重新上传"); + case "non_idcard": + throw new BusinessException("上传的图片中不包含身份证,请上传正确图片"); + case "blurred": + throw new BusinessException("身份证模糊,请重新上传清晰图片"); + case "over_exposure": + throw new BusinessException("身份证关键字段反光或过曝,请重新拍摄"); + case "unknown": + default: + throw new BusinessException("无法识别身份证,请重新上传"); + } + + if (result.has("risk_type")) { + String riskType = result.getString("risk_type"); + if (!"normal".equals(riskType)) { + switch (riskType) { + case "copy": + throw new BusinessException("检测到复印件身份证,请上传原件"); + case "temporary": + throw new BusinessException("检测到临时身份证,请上传正式身份证"); + case "screen": + throw new BusinessException("检测到翻拍身份证,请上传原件照片"); + case "unknow": + default: + throw new BusinessException("身份证真实性存疑,请重新上传"); + } + } + } + + // 解析识别结果 + String name = result.getJSONObject("words_result").getJSONObject("姓名").getString("words"); + String idNo = result.getJSONObject("words_result").getJSONObject("公民身份号码").getString("words"); + + // 构建返回对象 + GetIdCardOcrVo vo = new GetIdCardOcrVo(); + vo.setIdCardName(name); + vo.setIdCardNo(idNo); + return vo; + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } +} diff --git a/sa-admin/src/main/resources/dev/application.yaml b/sa-admin/src/main/resources/dev/application.yaml index c9dba14..2ced62f 100644 --- a/sa-admin/src/main/resources/dev/application.yaml +++ b/sa-admin/src/main/resources/dev/application.yaml @@ -54,14 +54,19 @@ fxq: client-secret: 97acf8ebb09641cbb90accf06e74ccf5 client-url: https://saasapi.fangxinqian.cn/openapi/v2/ - # json序列化相关配置 - jackson: - serialization: - write-enums-using-to-string: true - write-dates-as-timestamps: false - deserialization: - read-enums-using-to-string: true - fail-on-unknown-properties: false - default-property-inclusion: always - date-format: yyyy-MM-dd HH:mm:ss - time-zone: GMT+8 \ No newline at end of file +baiduce: + app-id: 119377580 + app-key: 2YFRnP3ryU8IP0IqbqybTu6u + app-secret: Zw8pTeM1ovys7kOsNUlElOc6jBi6zsFU + +# json序列化相关配置 +jackson: + serialization: + write-enums-using-to-string: true + write-dates-as-timestamps: false + deserialization: + read-enums-using-to-string: true + fail-on-unknown-properties: false + default-property-inclusion: always + date-format: yyyy-MM-dd HH:mm:ss + time-zone: GMT+8 \ No newline at end of file