准备工作:
环境:windows、jdk(32bit)
华视SDK开发包:
- sdtapi.dll(函数的动态联接库)
- Termb.dll(安全模块通讯函数)
- WltRS.dll(身份证相片解码库)
JNA实现library接口:
注意:
将**sdtapi.dll、Termb.dll、WltRS.dll放到工程目录的lib目录中。
将**sdtapi.dll、Termb.dll、WltRS.dll放到jdk/bin目录下。
直接上代码:
public interface IdCardSdk extends Library {
IdCardSdk INSTANCE = Native.load("Termb", IdCardSdk.class);
/**
函数调用流程
初始化->卡认证->读卡->函数取信息->关闭连接
注意:若采用查询方式自动判断卡片是否放置,则间隔时间建议大于600ms。
*/
/**
* 1. 初始化链接
* 原 型:int CVR_InitComm (int Port)
* 说 明:本函数用于PC与华视电子第二代居民身份证阅读器的连接。
* 参 数:Port:连接串口(COM1~COM16)或USB口(1001~1016)
*
* 参数名 含义 取值范围
* int Port 端口编号 见下表
* 端口编号: 1=串口1 2=串口2 ... 16=串口16
* 1001=USB口1 1002=USB口2 ... 1016=USB口16
*
* 返回值:1:正确 2:端口打开失败 -1:未知错误 -2:动态库加载失败
* @return
*/
int CVR_InitComm(int Port);
/**
* 2. 关闭端口
* 原 型:int CVR_CloseComm(void)
* 说 明:本函数用于关闭PC到阅读器的连接。
* 参 数:无
* 返回值:1:关闭成功 0:端口号不合法 -1:端口已经关闭 -2:动态库加载失败
* @return
*/
int CVR_CloseComm();
/**
* 3. 卡认证
* 原 型:int CVR_Authenticate (void)
* 说 明:本函数用于读卡器和卡片之间的合法身份确认。卡认证循环间隔大于300ms。
* 参 数:
* 返回值:1:正确 卡片认证成功 2:错误 寻卡失败 3:错误 选卡失败 4:错误 未连接读卡器 4:错误 动态库未加载
* (若卡片放置后发生认证错误时,请移走卡片重新放置。)
*/
int CVR_Authenticate();
//此处读卡分为两种 根据需要选择
/**
* 4. 读卡操作1(与读卡操作2平级,根据需要选择)
* 原 型:int CVR_Read_Content(int active);
* 说 明:本函数用于通过阅读器从第二代居民身份证中读取相应信息。卡认证成功以后才可做读卡操作,读卡完毕若继续读卡应移走二代证卡片重新放置做卡认证。
* 参 数:
* 参数名 含义 取值范围
* int active 临时目录中保存的文件种类 见取值说明
* 取值说明:
* 值 意义
* 1 wz.txt,xp.wlt,zp.bmp,fp.dat
* 2 wz.txt,xp.wlt,fp.dat
* 4 wz.txt,zp.bmp,fp.dat
* 保存目录为临时目录,例如win7环境下路径:
* C:\Users\mac\AppData\Local\Temp\chinaidcard。其中mac是用户名称。
* 以上为示例路径,请根据客户开发环境,确定实际路径,该路径不能更改。
* 文件说明:
* 文件名 意义
* wz.txt 身份证基本信息,如姓名、性别等
* xp.wlt 加密的头像数据
* zp.bmp 解密的头像数据
* fp.dat 指纹数据,若无指纹则该文件大小仍为1024字节,每个字节均为0
*
*
* 返回值:1:正确 0:错误,读身份证失败 4:错误,身份证读卡器未连接 99:动态库未加载
*/
int CVR_Read_Content(int active);
/**
* 5. 读卡操作2(与读卡操作1平级,根据需要选择)
* 原 型:int CVR_Read_FPContent()
* 说 明:本函数用于通过阅读器从第二代居民身份证中读取相应信息。卡认证成功以后才可做读卡操作,读卡完毕若继续读卡应移走二代证卡片重新放置做卡认证。
* 参 数: 无
* 执行后会在运行目录下生成以下文件信息
* 文件说明:
* 文件名 意义
* wz.txt 身份证基本信息,如姓名、性别等
* xp.wlt 加密的头像数据
* zp.bmp 解密的头像数据
* fp.dat 指纹数据,若无指纹则该文件大小仍为1024字节,每个字节均为0
*
* 返回值:1:正确 0:错误,读身份证失败 4:错误,身份证读卡器未连接 99:动态库未加载
*/
int CVR_Read_FPContent();
/**
* 6. 获取民族代码
* 原 型:int GetNationCode(unsigned char * nationData, int * pLen);
* 说 明:本函数获取民族代码
* 参 数:
* 参数名 含义 取值范围
* unsigned char * nationData 缓冲区地址
* int * pLen 缓冲区长度指针 4字节
* 返 回 值:1:正确 0:错误
*/
int GetNationCode(String nationData,int pLen);
/**
*
* 其他函数
* int GetPeopleName(char *strTmp, int *strLen) //得到姓名信息
* int GetPeopleSex(char *strTmp, int *strLen) //得到性别信息
* int GetPeopleNation(char *strTmp, int *strLen) //得到民族信息
* int GetPeopleBirthday(char *strTmp, int *strLen) //得到出生日期
* int GetPeopleAddress(char *strTmp, int *strLen) //得到地址信息
* int GetPeopleIDCode(char *strTmp, int *strLen) //得到卡号信息
* int GetDepartment(char *strTmp, int *strLen) //得到发证机关信息
* int GetStartDate(char *strTmp, int *strLen) //得到有效开始日期
* int GetEndDate(char *strTmp, int *strLen) //得到有效截止日期
* int CVR_GetSAMID(char * SAMID) //得到安全模块号码
*
* 返 回 值:1:正确 0:错误
*/
int GetPeopleName(byte[] strTmp,byte[] strLen);
int GetPeopleSex(byte[] strTmp,byte[] strLen);
int GetPeopleNation(byte[] strTmp,byte[] strLen);
int GetPeopleBirthday(byte[] strTmp,byte[] strLen);
int GetPeopleAddress(byte[] strTmp,byte[] strLen);
int GetPeopleIDCode(byte[] strTmp,byte[] strLen);
int GetDepartment(byte[] strTmp,byte[] strLen);
int GetStartDate(byte[] strTmp,byte[] strLen);
int GetEndDate(byte[] strTmp,byte[] strLen);
int CVR_GetSAMID(byte[] strTmp,byte[] strLen);
/**
* 获取证件图片
* int GetBMPData (unsigned char *pData, int * pLen)
* 得到头像照片bmp二进制数据,不超过38862字节
* 得到头像照片bmp二进制数据,不超过38862字节
* 得到头像照片bmp二进制数据,不超过38862字节
* int Getbase64BMPData (unsigned char *pData, int * pLen)
* 得到头像照片bmp数据base64编码,不超过38862*2字节
* 得到头像照片bmp数据base64编码,不超过38862*2字节
* 得到头像照片bmp数据base64编码,不超过38862*2字节
* int GetJpgData(unsigned char * jpgData, int * pLen)
* 得到头像照片jpg二进制数据
* 得到头像照片jpg二进制数据
* 得到头像照片jpg二进制数据
* int Getbase64JpgData (unsigned char *pData, int * pLen)
* 得到头像照片jpg数据base64编码,不超过38862*2字节
* 得到头像照片jpg数据base64编码,不超过38862*2字节
* 得到头像照片jpg数据base64编码,不超过38862*2字节
*
*/
int GetBMPData (Pointer pData, IntByReference pLen);
int Getbase64BMPData (Pointer pData, IntByReference pLen);
int GetJpgData (Pointer pData, IntByReference pLen);
int Getbase64JpgData (Pointer pData, IntByReference pLen);
}
方法调用:
注意:
- 此处图片均为base64
- 出生日期需要格式化
public class Cvr100IdCardReader{
private final static byte[] RTN_RES = new byte[4];
//此处1001端口对应的是usb口1 以此类推 1002 usb口2 ...1016 usb口16
private final static int PORT = 1001;
//成功状态码
private static final int SUCCESS = 1;
//失败状态码
private static final int FAIL = 0;
//返回数据的字符编码
private static final String ENCODING = "gb2312";
//长度
private static final IntByReference len = new IntByReference();
/**
* 获取姓名
*
* @return 姓名
*/
private String GetPeopleName() {
try {
byte[] a = new byte[30];
return IdCardSdk.INSTANCE.GetPeopleName(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取性别
*
* @return 性别
*/
private String GetPeopleSex() {
try {
byte[] a = new byte[2];
return IdCardSdk.INSTANCE.GetPeopleSex(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取民族
*
* @return 民族
*/
private String GetPeopleNation() {
try {
byte[] a = new byte[20];
return IdCardSdk.INSTANCE.GetPeopleNation(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取出生日期
*
* @return 出生日期
*/
private String GetPeopleBirthday() {
try {
byte[] a = new byte[16];
return IdCardSdk.INSTANCE.GetPeopleBirthday(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取户籍地址
*
* @return 户籍地址
*/
private String GetPeopleAddress() {
try {
byte[] a = new byte[70];
return IdCardSdk.INSTANCE.GetPeopleAddress(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取证件号码
*
* @return 证件号码
*/
private String GetPeopleIDCode() {
try {
byte[] a = new byte[36];
return IdCardSdk.INSTANCE.GetPeopleIDCode(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取发证机关
*
* @return 发证机关
*/
private String GetDepartment() {
try {
byte[] a = new byte[30];
return IdCardSdk.INSTANCE.GetDepartment(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取有效开始日期
*
* @return 有效开始日期
*/
private String GetStartDate() {
try {
byte[] a = new byte[16];
return IdCardSdk.INSTANCE.GetStartDate(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取有效截止日期
*
* @return 有效截止日期
*/
private String GetEndDate() {
try {
byte[] a = new byte[16];
return IdCardSdk.INSTANCE.GetEndDate(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
/**
* 获取安全模块号码
*
* @return 安全模块号码
*/
private String CVR_GetSAMID() {
try {
byte[] a = new byte[4 * 10];
return IdCardSdk.INSTANCE.CVR_GetSAMID(a, RTN_RES) == 1 ? handleResult(a) : "";
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}
private String Getbase64BMPData() {
String base64 = "";
try {
Pointer bmpBuffer = Pointer.NULL;
bmpBuffer = new Memory(38862 * 2);
IntByReference bmpLen = new IntByReference();
bmpLen.setValue(38862 * 2);
if (IdCardSdk.INSTANCE.Getbase64BMPData(bmpBuffer, bmpLen) == 1) {
byte[] byteArray = bmpBuffer.getByteArray(0, bmpLen.getValue());
base64 = new String(byteArray);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return base64;
}
private String Getbase64JpgData() {
String base64 = "";
try {
Pointer bmpBuffer = Pointer.NULL;
bmpBuffer = new Memory(38862 * 2);
IntByReference bmpLen = new IntByReference();
bmpLen.setValue(38862 * 2);
if (IdCardSdk.INSTANCE.Getbase64JpgData(bmpBuffer, bmpLen) == 1) {
byte[] byteArray = bmpBuffer.getByteArray(0, bmpLen.getValue());
base64 = new String(byteArray);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return base64;
}
/**
* 读卡
*/
public IdCardInfo readIdCard() {
isDisplayWork = false;
IdCardInfo idCard = new IdCardInfo();
try {
//1、初始化连接,打开连接
int initComm = 0;
for (int i = 1001; i < 1003; i++) {
initComm = IdCardSdk.INSTANCE.CVR_InitComm(i);
if (initComm == 1) {
idCard.setResult(true);
idCard.setMsg("读卡器初始化成功");
break;
}
}
if (initComm != SUCCESS) {
idCard.setResult(false);
idCard.setMsg("读卡器连接失败,请检查设备状态");
return idCard;
}
//2、读卡(同一个身份证,只要读取一次,下次读取优先从缓存中读取,并且CVR_Authenticate返回为2,卡认证失败,所以优先读卡一次)
//读取卡
int readStatus = IdCardSdk.INSTANCE.CVR_Read_Content(4);
//2、卡认证,超出两分钟就是本次读卡失败
int authenticate = getAuthenticateStatus(IdCardSdk.INSTANCE, readStatus);
if (authenticate != SUCCESS) {
idCard.setResult(false);
idCard.setMsg("读卡失败,请重新放置卡片");
return idCard;
}
//读取卡
if (readStatus != SUCCESS) {
readStatus = IdCardSdk.INSTANCE.CVR_Read_Content(4);
}
if (readStatus != SUCCESS) {
idCard.setResult(false);
idCard.setMsg("证件信息读取失败,请重新放置证件");
return idCard;
}
String name = GetPeopleName();
String sex = GetPeopleSex();
String nation = GetPeopleNation();
String birthday = GetPeopleBirthday();
String address = GetPeopleAddress();
String idCode = GetPeopleIDCode();
String department = GetDepartment();
String startDate = GetStartDate();
String endDate = GetEndDate();
String samId = CVR_GetSAMID();
String bmpBase64 = Getbase64BMPData();
String jpgBase64 = Getbase64JpgData();
//赋值
idCard.setName(name);
idCard.setSex(sex);
idCard.setNation(nation);
idCard.setBirthday(fmtDate(birthday));
idCard.setAddress(address);
idCard.setIdCard(idCode);
idCard.setDepartment(department);
idCard.setStartDate(fmtDate(startDate));
idCard.setEndDate(fmtDate(endDate));
idCard.setSamId(samId);
idCard.setBmpBase64(bmpBase64);
idCard.setJpgBase64(jpgBase64);
idCard.setResult(true);
idCard.setMsg("读取成功");
} catch (Exception e) {
e.printStackTrace();
} finally {
IdCardSdk.INSTANCE.CVR_CloseComm();
isDisplayWork = true;
}
return idCard;
}
/**
* 卡认证
*
* @param idCardSdk
* @param readStatus
* @return
* @throws InterruptedException
*/
private int getAuthenticateStatus(IdCardSdk idCardSdk, int readStatus) throws InterruptedException {
if (readStatus == SUCCESS) {
return SUCCESS;
}
final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(10L);
int authenticate = FAIL;
//循环读卡,失效时间为10s
while (authenticate != SUCCESS) {
authenticate = idCardSdk.CVR_Authenticate();
if (deadline == SUCCESS) {
continue;
}
if (deadline - System.nanoTime() < 0L) {
break;
}
Thread.sleep(100);//短暂休眠
}
return authenticate;
}
/**
* 处理返回结果字符
*
* @param nameByte
* @return
* @throws UnsupportedEncodingException
*/
private static String handleResult(byte[] nameByte) throws UnsupportedEncodingException {
return new String(nameByte, ENCODING).trim();
}
/**
* 日期格式化
*
* @param str = yyyyMMdd
* @return yyyy-MM-dd
* @throws ParseException
*/
private String fmtDate(String str) throws ParseException {
Date date = new SimpleDateFormat("yyyyMMdd").parse(str);
String strDate = new SimpleDateFormat("yyyy-MM-dd").format(date);
return strDate;
}
}
产出:
得到证件信息