Java百度云身份证识别
- 一、身份证识别工具类
- 二、获取Token工具类
- 三、java原生HTTP请求工具类
- 四、使用
一、身份证识别工具类
package com.cndatacom.cloud1.cdchr.modules.hireinfo.common;
import com.alibaba.fastjson.JSONObject;
import com.cndatacom.cloud1.cdchr.common.exception.SFException;
import com.cndatacom.cloud1.cdchr.modules.hireinfo.dictdatautil.filter.DictDataListFilter;
import com.cndatacom.cloud1.cdchr.modules.hireinfo.entity.CdcHirebaseEntity;
import org.apache.commons.codec.binary.base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Component
public class IdCard {
private static final Logger LOG = LoggerFactory.getLogger(IdCard.class);
@Autowired
private AuthService authService;
private static final Map MSG = new HashMap() {{
// put("normal","识别正常");
put("reversed_side", "身份证正反面颠倒");
put("non_idcard", "上传的图片中不包含身份证");
put("blurred", "身份证模糊");
put("other_type_card", "其他类型证照");
put("over_exposure", "身份证关键字段反光或过曝");
put("over_dark", "身份证欠曝(亮度过低)");
put("unknown", "未知状态");
}};
public String getIdCard(String filePath, String frontAndBack) {
LOG.info("进入百度云API身份证识别接口中[filePath=" + filePath + "][frontAndBack=" + frontAndBack + "]");
// 请求url
String url = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard";
LOG.info("正在读取文件[" + filePath + "]");
byte[] imgData = new byte[0];
try {
imgData = FileUtil.readFileByBytes(filePath);
} catch (IOException e) {
LOG.error("FileUtil读取[" + filePath + "]异常,信息为:" + e.getMessage());
throw new SFException("无法加载身份证照片");
}
String param = null;
String accessToken = null;
try {
LOG.info("正在base64加密字节集");
String imgStr = base64Util.encode(imgData);
LOG.info("正在UTF-8编码");
String imgParam = URLEncoder.encode(imgStr, "UTF-8");
param = "id_card_side=" + frontAndBack + "&image=" + imgParam + "&detect_photo=true";
// 注意这里仅为了简化编码每一次请求都去获取access_token,线上环境access_token有过期时间, 客户端可自行缓存,过期后重新获取。
LOG.info("正在获取调用百度云API接口的令牌");
accessToken = authService.getAuth();//获取token
LOG.info("令牌获取完成,准备调用接口");
} catch (UnsupportedEncodingException e) {
LOG.error("base64加密字节集 and UTF-8编码 异常,信息为:" + e.getMessage());
}
String result = null;
try {
result = HttpUtil.post(url, accessToken, param);
} catch (Exception e) {
LOG.error("调用百度云API身份证识别接口异常,信息为:" + e.getMessage());
throw new SFException("身份证图片识别异常");
}
LOG.info("调用百度云API身份证识别接口返回结果为:" + result);
Object image_status = JSONObject.parseObject(result).get("image_status");
if (image_status != null && MSG.containsKey(image_status))
throw new SFException(MSG.get(image_status));
return result;
}
public static final Info getUserInfo(String idCard) {
return new Info(idCard);
}
public static class Info {
private String userName;
private String nationId;
private String nation;
private String address;
private String cardIdNo;
private Date birthday;
private String sex;
private String photo;
public Info(String idCard) {
try {
JSONObject json = JSONObject.parseObject(idCard);
JSONObject words_result = json.getJSONObject("words_result");
this.userName = words_result.getJSONObject("姓名").getString("words");
LOG.info("识别身份证JSON结果[姓名]=[" + this.userName + "]");
this.nation = words_result.getJSONObject("民族").getString("words");
LOG.info("识别身份证JSON结果[民族]=[" + this.nation + "]");
if (this.nation != null && this.nation.length() > 0) {
LOG.info("正在查找民族对应的code码");
List nation = DictDataListFilter.getDictDataBybaseType("nation");
List collect = nation.stream().filter(e -> {
String baseName = e.getbaseName();
baseName = baseName.substring(0, baseName.length() - 1);
if (baseName.equals(this.nation)) {
this.nation += "族";
return true;
}
return false;
}).collect(Collectors.toList());
this.nationId = collect.get(0).getbaseCode();
}
LOG.info("查找结果为["+this.nationId+"]");
this.address = words_result.getJSONObject("住址").getString("words");
LOG.info("识别身份证JSON结果[住址]=[" + this.address + "]");
this.cardIdNo = words_result.getJSONObject("公民身份号码").getString("words");
LOG.info("识别身份证JSON结果[公民身份号码]=[" + this.cardIdNo + "]");
this.birthday = new SimpleDateFormat("yyyyMMdd").parse(words_result.getJSONObject("出生").getString("words"));
LOG.info("识别身份证JSON结果[出生]=[" + this.birthday + "]");
this.sex = words_result.getJSONObject("性别").getString("words").equals("男") ? "1" : "2";
LOG.info("识别身份证JSON结果[性别]=[" + this.sex + "][1=男,2=女]");
byte[] bytes = base64.decodebase64(json.getString("photo"));//获取结果中头像图片字节
String headFilePath = IOUtil.outHeader(bytes);//输出到本地
this.photo = headFilePath;
} catch (Exception e) {
LOG.error("IdCard Info 内部构造器在构造身份证基本信息时异常,信息为:" + e.getMessage());
}
}
public String getUserName() {
return userName;
}
public String getNation() {
return nation;
}
public String getAddress() {
return address;
}
public String getCardIdNo() {
return cardIdNo;
}
public Date getBirthday() {
return birthday;
}
public String getSex() {
return sex;
}
public String getPhoto() {
return photo;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setNation(String nation) {
this.nation = nation;
}
public void setAddress(String address) {
this.address = address;
}
public void setCardIdNo(String cardIdNo) {
this.cardIdNo = cardIdNo;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setPhoto(String photo) {
this.photo = photo;
}
public String getNationId() {
return nationId;
}
public void setNationId(String nationId) {
this.nationId = nationId;
}
}
}
二、获取Token工具类
package com.cndatacom.cloud1.cdchr.modules.hireinfo.common;
import com.cndatacom.cloud1.cdchr.common.utils.AesUtils;
import com.cndatacom.cloud1.cdchr.modules.sys.service.SysConfigService;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
@Component
public class AuthService {
@Autowired
private SysConfigService sysConfigService;
// @Value("${baidu.Id_card.app_key}")
// public String appKey;
// @Value("${baidu.Id_card.app_secret}")
// public String appSecret;
// @Value("${baidu.Id_card.access_token_valid_time}")
public Long accessTokenValidTime = 2505600L; //有效时间 2505600L = 29天 2592000 = 30天
public static Long accessTokenExpirationTime = null; //生成token的时候 时间==过期时间
public static String token = null;
public String getAuth() {
if (token == null || ((System.currentTimeMillis() - accessTokenExpirationTime) / 60) > accessTokenValidTime) {
// 如果token是空 或者 系统的秒值-之前生成token时的秒值 > 有效时间29天 重新生成
String baidu_appKey = sysConfigService.getValue("baidu_appKey");
String baidu_appSecret = sysConfigService.getValue("baidu_appSecret");
getAuth(AesUtils.decrypt(baidu_appKey), AesUtils.decrypt(baidu_appSecret));
}
return token;
}
public void getAuth(String ak, String sk) {
// 获取token地址
String authHost = "https://aip.baidubce.com/oauth/2.0/token?";
String getAccessTokenUrl = authHost
// 1. grant_type为固定参数
+ "grant_type=client_credentials"
// 2. 官网获取的 API Key
+ "&client_id=" + ak
// 3. 官网获取的 Secret Key
+ "&client_secret=" + sk;
try {
URL realUrl = new URL(getAccessTokenUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection();
connection.setRequestMethod("GET");
connection.connect();
// 获取所有响应头字段
Map> map = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.err.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String result = "";
String line;
while ((line = in.readLine()) != null) {
result += line;
}
System.err.println("result:" + result);
JSONObject jsonObject = new JSONObject(result);
String access_token = jsonObject.getString("access_token");
accessTokenExpirationTime = System.currentTimeMillis();
token = access_token;
} catch (Exception e) {
System.err.printf("获取token失败!");
e.printStackTrace(System.err);
}
}
public static final AuthService ok(){
return new AuthService();
}
}
三、java原生HTTP请求工具类
用于上传文件
package com.cndatacom.cloud1.cdchr.modules.hireinfo.common;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
public class HttpUtil {
public static String post(String requestUrl, String accessToken, String params)
throws Exception {
String contentType = "application/x-www-form-urlencoded";
return HttpUtil.post(requestUrl, accessToken, contentType, params);
}
public static String post(String requestUrl, String accessToken, String contentType, String params)
throws Exception {
String encoding = "UTF-8";
if (requestUrl.contains("nlp")) {
encoding = "GBK";
}
return HttpUtil.post(requestUrl, accessToken, contentType, params, encoding);
}
public static String post(String requestUrl, String accessToken, String contentType, String params, String encoding)
throws Exception {
String url = requestUrl + "?access_token=" + accessToken;
return HttpUtil.postGeneralUrl(url, contentType, params, encoding);
}
public static String postGeneralUrl(String generalUrl, String contentType, String params, String encoding)
throws Exception {
URL url = new URL(generalUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
// 设置通用的请求属性
connection.setRequestProperty("Content-Type", contentType);
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setDoInput(true);
// 得到请求的输出流对象
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.write(params.getBytes(encoding));
out.flush();
out.close();
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
Map> headers = connection.getHeaderFields();
// 遍历所有的响应头字段
for (String key : headers.keySet()) {
System.err.println(key + "--->" + headers.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = null;
in = new BufferedReader(
new InputStreamReader(connection.getInputStream(), encoding));
String result = "";
String getLine;
while ((getLine = in.readLine()) != null) {
result += getLine;
}
in.close();
System.err.println("result:" + result);
return result;
}
}
四、使用
String idCard = this.idCard.getIdCard(filePath, "front");//前面
String idCard = this.idCard.getIdCard(filePath, "back");//背面
IdCard.Info = IdCard.getUserInfo(idCard);//当正面时可以调这个方法来获取信息
IdCard.Info内部类如下图