新增了身份证识别

This commit is contained in:
wucongxing8150 2025-06-30 16:48:39 +08:00
parent 7c09fd4172
commit 6cc5dc58de
11 changed files with 269 additions and 17 deletions

View File

@ -33,6 +33,11 @@
<artifactId>weixin-java-miniapp</artifactId> <artifactId>weixin-java-miniapp</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.16.22</version>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -60,7 +60,7 @@ public class AdminSwaggerTagConst extends SwaggerTagConst {
public static final String Expert = "前端-登录、注册、首页"; public static final String Expert = "前端-登录、注册、首页";
public static final String ExpertSign = "前端-医生签名"; public static final String ExpertSign = "前端-医生签名";
public static final String OSS = "前端-oss"; public static final String OSS = "前端-文件";
public static final String WX_MINI = "前端-微信小程序"; public static final String WX_MINI = "前端-微信小程序";
} }
} }

View File

@ -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);
}
}

View File

@ -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<String, String> 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());
}
}
}

View File

@ -18,7 +18,7 @@ import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Slf4j @Slf4j
@Component @Component("fangxinqianbase")
@Getter @Getter
public class Base { public class Base {
private static final ObjectMapper objectMapper = new ObjectMapper(); private static final ObjectMapper objectMapper = new ObjectMapper();

View File

@ -634,6 +634,4 @@ public class ExpertController {
return ResponseDTO.error(ExpertBankVerifyFail); return ResponseDTO.error(ExpertBankVerifyFail);
} }
} }
} }

View File

@ -77,6 +77,4 @@ public class ExpertService {
addForm.setToken(token); addForm.setToken(token);
return addForm; return addForm;
} }
} }

View File

@ -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<GetIdCardOcrVo> 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());
}
}
}

View File

@ -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;
}

View File

@ -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());
}
}
}

View File

@ -54,14 +54,19 @@ fxq:
client-secret: 97acf8ebb09641cbb90accf06e74ccf5 client-secret: 97acf8ebb09641cbb90accf06e74ccf5
client-url: https://saasapi.fangxinqian.cn/openapi/v2/ client-url: https://saasapi.fangxinqian.cn/openapi/v2/
# json序列化相关配置 baiduce:
jackson: app-id: 119377580
serialization: app-key: 2YFRnP3ryU8IP0IqbqybTu6u
write-enums-using-to-string: true app-secret: Zw8pTeM1ovys7kOsNUlElOc6jBi6zsFU
write-dates-as-timestamps: false
deserialization: # json序列化相关配置
read-enums-using-to-string: true jackson:
fail-on-unknown-properties: false serialization:
default-property-inclusion: always write-enums-using-to-string: true
date-format: yyyy-MM-dd HH:mm:ss write-dates-as-timestamps: false
time-zone: GMT+8 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