网站首页 >> 牛刀云小程序开发 >> 第2篇 开发模式 >> 服务开发 >> 接入第三方SDK

3.4.3.3 实战案例:身份证识别

【学习目标】

通过接入百度AI的身份证识别功能,掌握在开发模式下接入第三方SDK的方法。

【案例说明】

在页面上,通过附件组件上传身份证正面照片。在服务中添加百度SDK依赖,在请求中调用身份证识别API,获取身份证正面全部信息,从中取出身份证号码。

使用附件组件上传的图片不是以二进制形式存储在数据集中,而是以文件形式存储在Minio对象存储服务中,在数据集中存储的是JSON数组,每个JSON存储一张图片的存储文件名和真实文件名两个信息。通过Storage对象存储代理服务的获取对象查看的预签名上传url获取访问图片的URL

【开发过程】

1、添加身份证信息数据集

    在数据制作区,添加动态数据集“身份证”,用于存储身份证正面照片。在页面中上传照片,保存到数据集。在服务请求中从数据集中获取照片,作为调用百度身份证识别API的图片参数。

    “身份证”数据集包括2列,“正面照片”和“身份证号”,分别是图片类型和文本类型,如图15-14所示。

15-14  身份证数据集结构

2、添加服务、设置百度SDK依赖

    在服务制作区中,添加服务“身份证识别”。从中央仓库找到百度AI SDKMaven参数,如图15-15所示。在“身份证识别”服务上“设置依赖”,“组名称”填入com.baidu.aip,“名称”填入java-sdk,版本号填入4.1.1

15-15  Maven百度SDK参数

 

3、添加获取身份证号请求

在“获取身份证号”请求中,接收页面传过来的身份证数据集主键参数dataid,使用该参数查询出身份证正面照片img,发送http请求获取图片路径imgUrl,读出图片二进制数据imgByte,调用百度AI身份证识别API获得idcardInfo,从中获取身份证号idcardID

1)添加请求

在“身份证识别”服务中添加请求“获取身份证号”。“请求方法”选择GET,“请求返回”选择“字符串”。添加一个请求参数,“参数名称”为dataid,“显示名称”为“数据主键”,“数据类型”为“字符串”,“传参方式”为“请求参数”,如图15-16所示。

15-16  获取身份证号请求参数

2)设计处理逻辑

在请求的处理逻辑中,通过画代码的方法实现下面的逻辑,如图15-17所示。

第一步:根据参数dataid查询出身份证数据对象idcard

第二步:获取正面照片列中的值img

第三步:声明变量idcardID,暂时等于img

第四步:将idcardID赋值给身份证号列

第五步:保存身份证仓库

第六步:返回idcardID

15-17  获取身份证号处理逻辑

    从上面的步骤中可以看出,需要在JAVA代码中实现的是第三步,将img转化为idcardID。在写JAVA代码之前,可以先添加页面,看看运行效果。现在调用“获取身份证号”请求虽然不会获得身份证号,但是可以获得正面照片列中的值,看看JSON数组的内容,如图15-18所示。

15-18  调用请求返回正面照片列中的值

    在制作台开启开发模式,在服务制作区切换到请求的JAVA页,可以看到系统生成的JAVA方法huoqusfzh,代码如下:

public String huoqusfzh(String dataid) throws Exception {

Shenfenz idcard = com.justep.cloud.boot.service.X5ContextService.getInstance(

main.repository.ShenfenzRepository.class).findOne(dataid);

    String img = idcard.getFtupian();

    String idcardID = img;

    idcard.setFshenfenzh(idcardID);

    com.justep.cloud.boot.service.X5ContextService.getInstance(

main.repository.ShenfenzRepository.class).saveAndFlush(idcard);

    return idcardID;

}

    String idcardID = img;改为,真正从身份证正面照片中获取身份证号,代码如下:

public String huoqusfzh(String dataid) throws Exception{

Shenfenz idcard = com.justep.cloud.boot.service.X5ContextService.getInstance(

main.repository.ShenfenzRepository.class).findOne(dataid);

    String img = idcard.getFtupian();

    // 调用Storage请求获取图片URL

HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.

getRequestAttributes()).getRequest();

    JSONArray jsonArray = new JSONArray(img);

img = "http://" + request.getServerName() +

"/storage/presignedGetObject?objectName="

        + jsonArray.getJSONObject(0).get("storeFileName");

    String imgUrl = sendGet(img);

    // 获取图片二进制数据

    byte[] imgByte = GetImageFromUrl(imgUrl);

    // 初始化一个AipOcr

    AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);

    // 传入可选参数调用接口

    HashMap<String, String> options = new HashMap<String, String>();

    options.put("detect_direction", "true");

    options.put("detect_risk", "false");

    // 设置识别身份证正面

    String idCardSide = "front";

    // 调用身份证识别API,返回JSON对象

    JSONObject idcardInfo = client.idcard(imgByte, idCardSide, options);

    // JSON对象中获得身份证号

String idcardID = idcardInfo.getJSONObject("words_result").

getJSONObject("公民身份号码").getString("words");

    idcard.setFshenfenzh(idcardID);

    com.justep.cloud.boot.service.X5ContextService.getInstance(

main.repository.ShenfenzRepository.class).saveAndFlush(idcard);

    return idcardID;

}

    关于百度云应用的三个参数:APP_ID, API_KEY, SECRET_KEY,需要登录百度云,创建应用后获取。代码中用到两个方法sendGetGetImageFromUrlsendGet用来发送GET请求,获取返回值,GetImageFromUrl用来读取网络图片,返回二进制数据,代码如下:

public static String sendGet(String urlParam) { 

    StringBuffer resultBuffer = null; 

    HttpURLConnection con = null; 

    BufferedReader br = null; 

    try { 

        URL url = new URL(urlParam); 

        con = (HttpURLConnection) url.openConnection(); 

        con.connect(); 

        resultBuffer = new StringBuffer(); 

        br = new BufferedReader(new InputStreamReader(con.getInputStream())); 

        String temp; 

        while ((temp = br.readLine()) != null) { 

            resultBuffer.append(temp); 

        } 

    } catch (Exception e) { 

        throw new RuntimeException(e); 

    } finally { 

        if (br != null) { 

            try { 

                br.close(); 

            } catch (IOException e) { 

                br = null; 

                throw new RuntimeException(e); 

            } finally { 

                if (con != null) { 

                    con.disconnect(); 

                    con = null; 

                } 

            } 

        } 

    } 

    return resultBuffer.toString(); 

}

 

public static byte[] GetImageFromUrl(String imgURL) { 

    byte[] data = null; 

    try { 

        // 创建URL 

        URL url = new URL(imgURL); 

        // 创建链接 

        HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 

        conn.setRequestMethod("GET"); 

        conn.setConnectTimeout(5 * 1000); 

        InputStream inStream = conn.getInputStream(); 

        ByteArrayOutputStream output = new ByteArrayOutputStream();

        byte[] buf = new byte[1024];

        int numBytesRead = 0;

        while ((numBytesRead = inStream.read(buf)) != -1) {

            output.write(buf, 0, numBytesRead);

        }

        data = output.toByteArray();

        output.close();

        inStream.close(); 

    } catch (IOException e) { 

        e.printStackTrace(); 

    } 

    return data; 

} 

代码中需要声明的引用如下:

import main.entity.*;

 

import com.baidu.aip.ocr.*;

 

import org.springframework.stereotype.Service;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;

import org.json.*;

 

import java.util.*;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStreamReader; 

import java.io.InputStream; 

import java.io.BufferedReader;

import java.net.URL; 

import java.net.HttpURLConnection; 

 

import javax.servlet.http.HttpServletRequest;

 

4、添加上传身份证页面

    在页面制作区,添加 “上传身份证”页面,页面组件说明见表15-3

15-3  上传身份证页组件说明

添加组件

父组件

属性设置

身份证数据集

数据组件容器

自动模式=自动新增

获取身份证号码

服务组件容器

参数设置 cardid=身份证.主键

请求成功=刷新

目标数据集=身份证

图片附件

页面组件

绑定数据列=身份证.正面照片

文件数=1

文本组件

页面组件

动态文本=身份证.身份证号

按钮组件

页面组件

显示名称=读取

点击=操作组合

操作名称=保存

目标数据集=身份证

操作名称=发送服务请求

目标对象=获取身份证号

 

5、确认JAVA编译和查看请求结果

1)确认JAVA编译

在请求的JAVA页签中编辑JAVA代码保存后,不会自动编译JAVA,需要切换到设计页签,修改任意内容,再保存才会编译,调试期间可以采用修改另外请求的请求方法,实现编译。

如何确定JAVA有没有编译呢?打开Chrome浏览器的开发者工具,在Network页签中查看有没有compile.j,如果有,说明正在编译JAVA,当请求返回状态码为200时,查看请求返回中的message是否为“GoX5服务模型资源编译成功”,如果提示成功,说明JAVA编译通过,如图15-19所示。

15-19  查看compile.j请求

这其中如果没有看到compile.j请求,需要修改请求方法,再保存,以刺激编译。如果compile.j返回的状态码不是200,进入制作台的高级页面,重启控制台。如果compile.j请求返回的message是失败,则检查JAVA代码。

 

2)查看发送服务请求返回结果

    预览运行时,打开Chrome浏览器的开发者工具,切换到Network页签,单击发送服务请求的按钮,观察Network中的请求,如果返回状态码200说明请求成功,切换到Preview查看请求返回是否正常。如果返回状态码是500,如图15-20所示,说明服务端报错。

15-20  请求返回500

    需要打开日志跟踪,查看Tomcat控制台,如图15-21所示,查看报错原因。

15-21  查看Tomcat控制台日志