java 调用腾讯身份OCR接口文档实例(绝对可用)

1.情景展示

  通过读取身份证照片上的信息,实现自动填充功能。 

2.原因分析

  想要解析照片上所携带的相关信息,就需要识别照片的功能,腾讯提供了免费的身份证OCR接口,可供大家使用。

  没有耐心的可以直接看接口调用(跳过接口规则介绍)

3.接口规则

  接口地址:https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr

  API地址:https://ai.qq.com/doc/ocridcardocr.shtml

  规则

  注意:

  1.调取接口的请求方式必须使用form表单提交,JSON请求调取接口无效(我已经试过);

  2.返回的是JSON格式的字符串,解析具体数据时,并不能直接当做json对象取值,需要先将其转换成JSON对象。

  入参介绍

  app_id,注册账号后自动生成的唯一标识,配合密钥,才能拥有调取接口的权限;

  time_stamp,时间戳,获取系统当前时间戳(单位是秒,不是毫秒),用于超时校验的(5分钟);

  nonce_str,随机字符串,最大长度为32位,我们直接生成32位即可。

  sign,用于安全校验,主要是防止数据在传输过程中被篡改的;

  image,由图片转换成base64码,只支持jpg,png和bmp格式的图片并且图片大小不能够超过1MB。

  另外,不能包含图片类型的声明,即:需要将头部的,"data:image/jpeg;base64,","data:image/png;base64,","data:image/bmp;base64,"去掉。

  card_type,就很简单了,如果是正面用0,反面用1。

  需要说明的是:app_id,time_stamp和card_type这三个字段的值实际上是字符串,不用理会对于整数的说明,本身它对值的类型根本就限制不住,因为它要求的是必须是form表单提交,form表单提交的数据类型,永远只有一种,那就是字符串,这一点他们是自相矛盾的!

  sign的生成规则如下:


  意思是说:将这几个必要参数,排除sign后,按照字典升序排列(ASCII升序排列),组成get请求url参数拼接的形式,

  1.必要参数的升序拼接结果:app_id=value1&card_type=value2&image=value3&nonce_str=value4&sign=value5&time_stamp=value6

  2.image的值,即base64格式的数据需要使用URL进行编码,其余字段的值不需要使用URL编码。

  3.生成未加密前的字符串:将第一步的结果在其末尾拼接上密钥,即:app_id=value1&card_type=value2&image=value3&nonce_str=value4&sign=value5&time_stamp=value6&app_key=value7

  4.生成sign:对第三步的结果,使用MD5加密,加密结果转大写,得到sign的值。

  返回数据

  并发量限制(QPS-每秒可调用请求的次数) 

4.具体调用

  前提:假设前端给我们传过来的是一个base64格式的图片。

  设置好常量

// 接口分配的ID
private final static int TX_APP_ID = 1111111111;
// 接口对应的密钥
private final static String TX_APP_KEY = "2222222222222222";
// 接口调取地址
private final static String TX_ORCURL = "https://api.ai.qq.com/fcgi-bin/ocr/ocr_idcardocr";  

  导入

import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;  

  具体代码

String imgBase64 = request.getParameter("imgBase64");
if (imgBase64.startsWith("data:image/jpeg;base64,")) {
    imgBase64 = imgBase64.replace("data:image/jpeg;base64,", "");
} else if (imgBase64.startsWith("data:image/png;base64,")) {
    imgBase64 = imgBase64.replace("data:image/png;base64,", "");
} else if (imgBase64.startsWith("data:image/bmp;base64,")) {
    imgBase64 = imgBase64.replace("data:image/bmp;base64,", "");
}

// 时间戳
int time_stamp = (int) (System.currentTimeMillis()/1000);
// 随机字符串
String nonce_str = UUID.randomUUID().toString().replace("-", "");
// 鉴权
String sign = "";
// String image = URLEncoder.encode(imgBase64, "UTF-8");
// base64图片
String image = imgBase64;
// 身份证正反面(0-正面;1-反面)
int card_type = 0;
// 必须使用TreeMap(会自动生成有序Map)
Map<String, String> sortedMap = new TreeMap<>();
sortedMap.put("app_id", String.valueOf(TX_APP_ID));
sortedMap.put("time_stamp", String.valueOf(time_stamp));
sortedMap.put("nonce_str", nonce_str);
sortedMap.put("image", image);
sortedMap.put("card_type", String.valueOf(card_type));
// 生成鉴权
sign = generateSign(sortedMap);
sortedMap.put("sign", sign);
// 调取腾讯接口
String resultData = httpPostWithForm(TX_ORCURL,sortedMap);
// TODO 对resultData进行进一步处理(可直接返给前端处理)  

  生成鉴权代码

  需导入

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
/**
 * 生成腾讯身份证OCR鉴权
 * @explain key1=value1&key2=value2&...
 * @param sortedMap	key按照字典进行升序排列的Map
 * @return	sign(MD5加密并转大写)
 */
private static String generateSign(Map<String, String> sortedMap) {
    // 鉴权
    String sign = "";
    Iterator<String> iter = sortedMap.keySet().iterator();
    StringBuilder sb = new StringBuilder();
    while(iter.hasNext()){ 
        String key =iter.next(); 
        Object value = sortedMap.get(key);
        // base64需要使用URL进行编码
        if (key.equals("image")) {
            try {
                value = URLEncoder.encode(sortedMap.get(key), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        sb.append(key).append("=").append(value).append("&");
    }  
    sb.append("app_key").append("=").append(TX_APP_KEY);
    // 加密前
    sign = sb.toString();
    // 加密后(MD5加密并转大写)
    sign = DigestUtils.md5Hex(sign).toUpperCase();
    return sign;
}

  发送post请求代码

  需导入

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
/**
 * 以form表单形式提交数据,发送post请求
 * @explain 
 *   1.请求头:httppost.setHeader("Content-Type","application/x-www-form-urlencoded")
 *   2.提交的数据格式:key1=value1&key2=value2...
 * @param url 请求地址
 * @param paramsMap 具体数据
 * @return 服务器返回数据
 */
public static String httpPostWithForm(String url,Map<String, String> paramsMap){
    // 用于接收返回的结果
    String resultData ="";
     try {
            HttpPost post = new HttpPost(url);
            List<BasicNameValuePair> pairList = new ArrayList<BasicNameValuePair>();
            // 迭代Map-->取出key,value放到BasicNameValuePair对象中-->添加到list中
            for (String key : paramsMap.keySet()) {
                pairList.add(new BasicNameValuePair(key, paramsMap.get(key)));
            }
            UrlEncodedFormEntity uefe = new UrlEncodedFormEntity(pairList, "utf-8");
            post.setEntity(uefe); 
            // 创建一个http客户端
            CloseableHttpClient httpClient = HttpClientBuilder.create().build();
            // 发送post请求
            HttpResponse response = httpClient.execute(post);
            
            // 状态码为:200
            if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
                // 返回数据:
                resultData = EntityUtils.toString(response.getEntity(),"UTF-8");
            }else{
                throw new RuntimeException("接口连接失败!");
            }
        } catch (Exception e) {
            throw new RuntimeException("接口连接失败!");
        }
     return resultData;
}

  

  

  

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

猜你喜欢

转载自www.cnblogs.com/Marydon20170307/p/11448975.html