refactor(certificate): 合并身份证正反面OCR识别接口
- 移除旧的正面、反面单独识别接口,改用统一的身份证OCR合并识别接口 - 优化身份证OCR调用逻辑,添加图片base64转换失败处理 - 新增身份证识别服务实现,调用阿里云蜜堂有信接口 - 统一身份证照片识别失败错误码和提示,增强日志记录 - 验证身份证信息一致性及有效期,支持多格式日期解析 - 调整controller逻辑,使用新身份证OCR响应对象进行验证和回填
This commit is contained in:
@@ -13,9 +13,7 @@ import com.gxwebsoft.common.system.service.UserService;
|
|||||||
import com.gxwebsoft.love.entity.Certificate;
|
import com.gxwebsoft.love.entity.Certificate;
|
||||||
import com.gxwebsoft.love.param.CertificateParam;
|
import com.gxwebsoft.love.param.CertificateParam;
|
||||||
import com.gxwebsoft.love.service.CertificateService;
|
import com.gxwebsoft.love.service.CertificateService;
|
||||||
import com.gxwebsoft.love.vo.idcheck.BackRecognitionResult;
|
import com.gxwebsoft.oa.vo.IdcardRespVO;
|
||||||
import com.gxwebsoft.love.vo.idcheck.FrontRecognitionResult;
|
|
||||||
import com.gxwebsoft.love.vo.idcheck.Response;
|
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
@@ -97,26 +95,22 @@ public class CertificateController extends BaseController {
|
|||||||
return fail("请上传身份证照片", certificate);
|
return fail("请上传身份证照片", certificate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证正面
|
// 身份证OCR识别(正反面合并)
|
||||||
Response<FrontRecognitionResult> front = certificateService.idcardfrontrecongnition(collect.get(0));
|
IdcardRespVO resp = certificateService.idcardOcr(collect.get(0), collect.get(1));
|
||||||
if (front.getError_code() != 0) {
|
if (resp == null) {
|
||||||
return fail(front.getReason());
|
return fail("身份证识别调用失败", certificate);
|
||||||
}
|
}
|
||||||
|
if (!"FP00000".equals(resp.getCode())) {
|
||||||
|
return fail(resp.getMessage() == null ? "身份证识别失败" : resp.getMessage(), certificate);
|
||||||
// 验证反面
|
|
||||||
Response<BackRecognitionResult> back = certificateService.idcardbackrecongnition(collect.get(1));
|
|
||||||
if (back.getError_code() != 0) {
|
|
||||||
return fail(back.getReason());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
certificate.setStatus(30);
|
certificate.setStatus(30);
|
||||||
|
|
||||||
// 信息是否一致
|
// 信息是否一致
|
||||||
if (!certificate.getCertificateCode().equals(front.getResult().getIdcardno())) {
|
if (!certificate.getCertificateCode().equals(resp.getIdCardNo())) {
|
||||||
return fail("认证失败", certificate);
|
return fail("认证失败", certificate);
|
||||||
}
|
}
|
||||||
if (!certificate.getRealName().equals(front.getResult().getName())) {
|
if (!certificate.getRealName().equals(resp.getName())) {
|
||||||
return fail("认证失败", certificate);
|
return fail("认证失败", certificate);
|
||||||
}
|
}
|
||||||
User user = new User();
|
User user = new User();
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
import com.gxwebsoft.common.core.web.PageResult;
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
import com.gxwebsoft.love.entity.Certificate;
|
import com.gxwebsoft.love.entity.Certificate;
|
||||||
import com.gxwebsoft.love.param.CertificateParam;
|
import com.gxwebsoft.love.param.CertificateParam;
|
||||||
import com.gxwebsoft.love.vo.idcheck.BackRecognitionResult;
|
import com.gxwebsoft.oa.vo.IdcardRespVO;
|
||||||
import com.gxwebsoft.love.vo.idcheck.FrontRecognitionResult;
|
|
||||||
import com.gxwebsoft.love.vo.idcheck.Response;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -42,10 +40,15 @@ public interface CertificateService extends IService<Certificate> {
|
|||||||
*/
|
*/
|
||||||
Certificate getByIdRel(Integer certificateId);
|
Certificate getByIdRel(Integer certificateId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证OCR识别(正反面合并识别)
|
||||||
|
*
|
||||||
|
* @param frontImageUrl 正面图片 URL
|
||||||
|
* @param backImageUrl 反面图片 URL
|
||||||
|
* @return 识别结果
|
||||||
|
*/
|
||||||
|
IdcardRespVO idcardOcr(String frontImageUrl, String backImageUrl);
|
||||||
|
|
||||||
boolean verifyIdcard(Certificate param, List<String> files);
|
boolean verifyIdcard(Certificate param, List<String> files);
|
||||||
|
|
||||||
Response<FrontRecognitionResult> idcardfrontrecongnition(String imageUrl);
|
|
||||||
|
|
||||||
Response<BackRecognitionResult> idcardbackrecongnition(String imageUrl);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package com.gxwebsoft.love.service.impl;
|
|||||||
|
|
||||||
import cn.hutool.core.exceptions.ExceptionUtil;
|
import cn.hutool.core.exceptions.ExceptionUtil;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.gxwebsoft.common.core.utils.HttpUtils;
|
import com.gxwebsoft.common.core.utils.HttpUtils;
|
||||||
import com.gxwebsoft.common.core.utils.ImageUtil;
|
import com.gxwebsoft.common.core.utils.ImageUtil;
|
||||||
@@ -12,9 +11,7 @@ import com.gxwebsoft.love.entity.Certificate;
|
|||||||
import com.gxwebsoft.love.mapper.CertificateMapper;
|
import com.gxwebsoft.love.mapper.CertificateMapper;
|
||||||
import com.gxwebsoft.love.param.CertificateParam;
|
import com.gxwebsoft.love.param.CertificateParam;
|
||||||
import com.gxwebsoft.love.service.CertificateService;
|
import com.gxwebsoft.love.service.CertificateService;
|
||||||
import com.gxwebsoft.love.vo.idcheck.BackRecognitionResult;
|
import com.gxwebsoft.oa.vo.IdcardRespVO;
|
||||||
import com.gxwebsoft.love.vo.idcheck.FrontRecognitionResult;
|
|
||||||
import com.gxwebsoft.love.vo.idcheck.Response;
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
@@ -22,10 +19,12 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDate;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 证件管理记录表Service实现
|
* 证件管理记录表Service实现
|
||||||
@@ -39,12 +38,13 @@ public class CertificateServiceImpl extends ServiceImpl<CertificateMapper, Certi
|
|||||||
@Resource
|
@Resource
|
||||||
private RestTemplate restTemplate;
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
private String appcode = "566b5786c5874464909d8c0b7f64cdc7";
|
private static final String HOST = "https://miitangs14.market.alicloudapi.com";
|
||||||
|
private static final String APP_CODE = "1390018309a443c695c98c8da2bed691";
|
||||||
|
private static final String SUCCESS_CODE = "FP00000";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<Certificate> pageRel(CertificateParam param) {
|
public PageResult<Certificate> pageRel(CertificateParam param) {
|
||||||
PageParam<Certificate, CertificateParam> page = new PageParam<>(param);
|
PageParam<Certificate, CertificateParam> page = new PageParam<>(param);
|
||||||
//page.setDefaultOrder("create_time desc");
|
|
||||||
List<Certificate> list = baseMapper.selectPageRel(page, param);
|
List<Certificate> list = baseMapper.selectPageRel(page, param);
|
||||||
return new PageResult<>(list, page.getTotal());
|
return new PageResult<>(list, page.getTotal());
|
||||||
}
|
}
|
||||||
@@ -52,9 +52,7 @@ public class CertificateServiceImpl extends ServiceImpl<CertificateMapper, Certi
|
|||||||
@Override
|
@Override
|
||||||
public List<Certificate> listRel(CertificateParam param) {
|
public List<Certificate> listRel(CertificateParam param) {
|
||||||
List<Certificate> list = baseMapper.selectListRel(param);
|
List<Certificate> list = baseMapper.selectListRel(param);
|
||||||
// 排序
|
|
||||||
PageParam<Certificate, CertificateParam> page = new PageParam<>();
|
PageParam<Certificate, CertificateParam> page = new PageParam<>();
|
||||||
//page.setDefaultOrder("create_time desc");
|
|
||||||
return page.sortRecords(list);
|
return page.sortRecords(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,94 +63,81 @@ public class CertificateServiceImpl extends ServiceImpl<CertificateMapper, Certi
|
|||||||
return param.getOne(baseMapper.selectListRel(param));
|
return param.getOne(baseMapper.selectListRel(param));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IdcardRespVO idcardOcr(String frontImageUrl, String backImageUrl) {
|
||||||
|
String frontImg = ImageUtil.ImageBase64(frontImageUrl);
|
||||||
|
String backImg = ImageUtil.ImageBase64(backImageUrl);
|
||||||
|
if (frontImg == null || frontImg.isEmpty() || backImg == null || backImg.isEmpty()) {
|
||||||
|
IdcardRespVO fail = new IdcardRespVO();
|
||||||
|
fail.setCode("PARAM_ERROR");
|
||||||
|
fail.setMessage("身份证图片转base64失败");
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
headers.put("Authorization", "APPCODE " + APP_CODE);
|
||||||
|
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
|
headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
|
||||||
|
|
||||||
|
Map<String, String> querys = new HashMap<>();
|
||||||
|
Map<String, String> bodys = new HashMap<>();
|
||||||
|
bodys.put("reqNo", UUID.randomUUID().toString().replace("-", ""));
|
||||||
|
bodys.put("frontImg", frontImg);
|
||||||
|
bodys.put("backImg", backImg);
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpResponse response = HttpUtils.doPost(HOST, "/v1/tools/ocr/idCard", "POST", headers, querys, bodys);
|
||||||
|
HttpEntity entity = response.getEntity();
|
||||||
|
String string = EntityUtils.toString(entity);
|
||||||
|
return JSONObject.parseObject(string, IdcardRespVO.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean verifyIdcard(Certificate param, List<String> files) {
|
public boolean verifyIdcard(Certificate param, List<String> files) {
|
||||||
// 验证正面
|
if (files == null || files.size() < 2) {
|
||||||
Response<FrontRecognitionResult> front = idcardfrontrecongnition(files.get(0));
|
ExceptionUtil.wrapAndThrow(new RuntimeException("缺少身份证正反面照片"));
|
||||||
if(front.getError_code() != 0){
|
|
||||||
ExceptionUtil.wrapAndThrow(new Exception(front.getReason()));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IdcardRespVO resp = idcardOcr(files.get(0), files.get(1));
|
||||||
// 验证反面
|
if (resp == null) {
|
||||||
Response<BackRecognitionResult> back = idcardbackrecongnition(files.get(1));
|
ExceptionUtil.wrapAndThrow(new RuntimeException("身份证识别调用失败"));
|
||||||
if(back.getError_code() != 0){
|
return false;
|
||||||
ExceptionUtil.wrapAndThrow(new Exception(back.getReason()));
|
}
|
||||||
|
if (!SUCCESS_CODE.equals(resp.getCode())) {
|
||||||
|
ExceptionUtil.wrapAndThrow(new RuntimeException(resp.getMessage() == null ? "身份证识别失败" : resp.getMessage()));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 信息是否一致
|
// 信息是否一致
|
||||||
if(!param.getCertificateCode().equals(front.getResult().getIdcardno())){
|
if (!param.getCertificateCode().equals(resp.getIdCardNo())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!param.getRealName().equals(front.getResult().getName())){
|
if (!param.getRealName().equals(resp.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
boolean b = LocalDateTime.parse(back.getResult().getEndDate()).compareTo(LocalDateTime.now()) > 0;
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// 有效期是否过期
|
||||||
public Response<FrontRecognitionResult> idcardfrontrecongnition(String imageUrl) {
|
String expireDate = resp.getExpireDate();
|
||||||
|
if (expireDate == null || expireDate.isEmpty()) {
|
||||||
String host = "https://zidv2.market.alicloudapi.com";
|
return false;
|
||||||
String path = "/thirdnode/ImageAI/idcardfrontrecongnition";
|
|
||||||
String method = "POST";
|
|
||||||
Map<String, String> headers = new HashMap<String, String>();
|
|
||||||
//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
|
|
||||||
headers.put("Authorization", "APPCODE " + appcode);
|
|
||||||
//根据API的要求,定义相对应的Content-Type
|
|
||||||
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
|
||||||
Map<String, String> querys = new HashMap<String, String>();
|
|
||||||
Map<String, String> bodys = new HashMap<String, String>();
|
|
||||||
bodys.put("base64Str", ImageUtil.ImageBase64(imageUrl));
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
|
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
String string = EntityUtils.toString(entity);
|
|
||||||
Response<FrontRecognitionResult> o = JSONObject.parseObject(string, new TypeReference<Response<FrontRecognitionResult>>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
return o;
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
|
LocalDate expire;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Response<BackRecognitionResult> idcardbackrecongnition(String imageUrl) {
|
|
||||||
|
|
||||||
String host = "https://zidv2.market.alicloudapi.com";
|
|
||||||
String path = "/thirdnode/ImageAI/idcardbackrecongnition";
|
|
||||||
String method = "POST";
|
|
||||||
Map<String, String> headers = new HashMap<String, String>();
|
|
||||||
//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
|
|
||||||
headers.put("Authorization", "APPCODE " + appcode);
|
|
||||||
//根据API的要求,定义相对应的Content-Type
|
|
||||||
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
|
||||||
Map<String, String> querys = new HashMap<String, String>();
|
|
||||||
Map<String, String> bodys = new HashMap<String, String>();
|
|
||||||
bodys.put("base64Str", ImageUtil.ImageBase64(imageUrl));
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
|
expire = LocalDate.parse(expireDate, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
HttpEntity entity = response.getEntity();
|
|
||||||
String string = EntityUtils.toString(entity);
|
|
||||||
Response<BackRecognitionResult> o = JSONObject.parseObject(string, new TypeReference<Response<BackRecognitionResult>>() {
|
|
||||||
});
|
|
||||||
|
|
||||||
return o;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
// 尝试按 yyyyMMdd 解析
|
||||||
|
try {
|
||||||
|
expire = LocalDate.parse(expireDate, DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return expire.isAfter(LocalDate.now());
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
package com.gxwebsoft.oa.service.impl;
|
package com.gxwebsoft.oa.service.impl;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
|
||||||
import com.gxwebsoft.common.core.utils.HttpUtils;
|
import com.gxwebsoft.common.core.utils.HttpUtils;
|
||||||
import com.gxwebsoft.love.vo.idcheck.FrontRecognitionResult;
|
|
||||||
import com.gxwebsoft.love.vo.idcheck.Response;
|
|
||||||
import com.gxwebsoft.oa.service.IdcardService;
|
import com.gxwebsoft.oa.service.IdcardService;
|
||||||
import com.gxwebsoft.oa.vo.IdcardRespVO;
|
import com.gxwebsoft.oa.vo.IdcardRespVO;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.util.EntityUtils;
|
import org.apache.http.util.EntityUtils;
|
||||||
@@ -16,42 +14,75 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class IdcardServiceImpl implements IdcardService {
|
public class IdcardServiceImpl implements IdcardService {
|
||||||
|
|
||||||
|
/** 阿里云市场 - 身份证 OCR 供应商(蜜堂有信) */
|
||||||
|
private static final String HOST = "https://miitangs14.market.alicloudapi.com";
|
||||||
|
private static final String APP_CODE = "1390018309a443c695c98c8da2bed691";
|
||||||
|
private static final String SUCCESS_CODE = "FP00000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param frontImg 身份证正面图片的 base64 字符串(已带 ?x-oss-process 压缩,调用方负责生成)
|
||||||
|
* @param backImg 身份证反面图片的 base64 字符串
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IdcardRespVO verify(String frontImg, String backImg) {
|
public IdcardRespVO verify(String frontImg, String backImg) {
|
||||||
|
// 1. 校验输入
|
||||||
|
if (frontImg == null || frontImg.isEmpty() || backImg == null || backImg.isEmpty()) {
|
||||||
|
log.warn("身份证 verify 调用缺少正/反面图片, frontIsBlank={}, backIsBlank={}",
|
||||||
|
frontImg == null || frontImg.isEmpty(),
|
||||||
|
backImg == null || backImg.isEmpty());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String host = "https://miitangs14.market.alicloudapi.com";
|
// 2. 调用新接口(正反面合并为一次请求)
|
||||||
String path = "/v1/tools/ocr/idCard";
|
IdcardRespVO resp;
|
||||||
String method = "POST";
|
try {
|
||||||
String appcode = "1390018309a443c695c98c8da2bed691";
|
resp = callOcr(frontImg, backImg);
|
||||||
Map<String, String> headers = new HashMap<String, String>();
|
} catch (Exception e) {
|
||||||
//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
|
log.error("身份证OCR识别调用异常", e);
|
||||||
headers.put("Authorization", "APPCODE " + appcode);
|
return null;
|
||||||
//根据API的要求,定义相对应的Content-Type
|
}
|
||||||
|
if (resp == null) {
|
||||||
|
log.warn("身份证OCR识别返回为空(接口无响应或解析失败)");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 失败返回具体原因
|
||||||
|
if (!SUCCESS_CODE.equals(resp.getCode())) {
|
||||||
|
log.warn("身份证OCR识别失败 code={}, message={}", resp.getCode(), resp.getMessage());
|
||||||
|
IdcardRespVO fail = new IdcardRespVO();
|
||||||
|
fail.setCode(resp.getCode());
|
||||||
|
fail.setMessage(resp.getMessage());
|
||||||
|
return fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 成功
|
||||||
|
log.info("身份证识别成功 name={}, idCardNo={}", resp.getName(), resp.getIdCardNo());
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用蜜堂有信身份证 OCR 接口:POST /v1/tools/ocr/idCard
|
||||||
|
*/
|
||||||
|
private IdcardRespVO callOcr(String frontImg, String backImg) throws Exception {
|
||||||
|
Map<String, String> headers = new HashMap<>();
|
||||||
|
headers.put("Authorization", "APPCODE " + APP_CODE);
|
||||||
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||||
//需要给X-Ca-Nonce的值生成随机字符串,每次请求不能相同
|
|
||||||
headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
|
headers.put("X-Ca-Nonce", UUID.randomUUID().toString());
|
||||||
Map<String, String> querys = new HashMap<String, String>();
|
|
||||||
Map<String, String> bodys = new HashMap<String, String>();
|
Map<String, String> querys = new HashMap<>();
|
||||||
|
Map<String, String> bodys = new HashMap<>();
|
||||||
|
bodys.put("reqNo", UUID.randomUUID().toString().replace("-", ""));
|
||||||
bodys.put("frontImg", frontImg);
|
bodys.put("frontImg", frontImg);
|
||||||
bodys.put("backImg", backImg);
|
bodys.put("backImg", backImg);
|
||||||
|
|
||||||
|
HttpResponse response = HttpUtils.doPost(HOST, "/v1/tools/ocr/idCard", "POST", headers, querys, bodys);
|
||||||
try {
|
HttpEntity entity = response.getEntity();
|
||||||
|
String body = EntityUtils.toString(entity);
|
||||||
HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
|
log.debug("OCR 调用 frontImgLen={}, backImgLen={}, respLen={}", frontImg.length(), backImg.length(), body.length());
|
||||||
HttpEntity entity = response.getEntity();
|
return JSONObject.parseObject(body, IdcardRespVO.class);
|
||||||
String string = EntityUtils.toString(entity);
|
|
||||||
IdcardRespVO respVO = JSONObject.parseObject(string, new TypeReference<IdcardRespVO>() {
|
|
||||||
});
|
|
||||||
return respVO;
|
|
||||||
//获取response的body
|
|
||||||
//System.out.println(EntityUtils.toString(response.getEntity()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,14 +474,21 @@ public class OpenEquipmentController extends BaseController {
|
|||||||
return fail("身份证识别服务暂时不可用,请稍后重试");
|
return fail("身份证识别服务暂时不可用,请稍后重试");
|
||||||
}
|
}
|
||||||
if (verify == null) {
|
if (verify == null) {
|
||||||
return fail("身份证识别失败,请稍后重试");
|
return fail("身份证识别服务调用失败,请稍后重试");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 正面校验:非 FP00000 说明传的不是有效身份证人像面
|
// 4. 正面校验:非 FP00000 说明传的不是有效身份证人像面
|
||||||
if (!"FP00000".equals(verify.getCode())) {
|
if (!"FP00000".equals(verify.getCode())) {
|
||||||
// 内部错误码仅记录日志,不回吐给用户
|
// 优先用阿里云返回的具体原因,没拿到再回退到通用提示
|
||||||
log.warn("身份证正面识别失败 code={}, message={}", verify.getCode(), verify.getMessage());
|
String reason = verify.getMessage();
|
||||||
return fail("身份证正面照片识别失败,请重新上传清晰的身份证人像面照片");
|
if ("FRONT_FAIL".equals(verify.getCode())) {
|
||||||
|
return fail(StrUtil.isNotBlank(reason) ? reason : "身份证正面照片识别失败,请重新上传清晰的身份证人像面照片");
|
||||||
|
}
|
||||||
|
if ("BACK_FAIL".equals(verify.getCode())) {
|
||||||
|
return fail(StrUtil.isNotBlank(reason) ? reason : "身份证反面照片识别失败,请重新上传清晰的身份证国徽面照片");
|
||||||
|
}
|
||||||
|
log.warn("身份证识别未通过 code={}, message={}", verify.getCode(), verify.getMessage());
|
||||||
|
return fail(StrUtil.isNotBlank(reason) ? reason : "身份证识别失败,请重新上传清晰的身份证照片");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 反面校验:签发机关/日期缺失说明传的不是有效身份证国徽面
|
// 5. 反面校验:签发机关/日期缺失说明传的不是有效身份证国徽面
|
||||||
@@ -491,6 +498,12 @@ public class OpenEquipmentController extends BaseController {
|
|||||||
return fail("身份证反面照片识别失败,请重新上传清晰的身份证国徽面照片");
|
return fail("身份证反面照片识别失败,请重新上传清晰的身份证国徽面照片");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 6. 正面字段也兜底校验一次(避免 OCR 返回空字符串导致回填出空实名)
|
||||||
|
if (StringUtils.isEmpty(verify.getName())
|
||||||
|
|| StringUtils.isEmpty(verify.getIdCardNo())) {
|
||||||
|
return fail("身份证正面照片识别失败,请重新上传清晰的身份证人像面照片");
|
||||||
|
}
|
||||||
|
|
||||||
// 6. 校验通过,回填实名信息
|
// 6. 校验通过,回填实名信息
|
||||||
order.setRealName(verify.getName());
|
order.setRealName(verify.getName());
|
||||||
order.setIdCode(verify.getIdCardNo());
|
order.setIdCode(verify.getIdCardNo());
|
||||||
|
|||||||
Reference in New Issue
Block a user