java调用sdtapi.dll读取身份证设备信息的一次记录

本文详细介绍了如何使用Java与JNA库集成设备驱动,实现身份证信息的读取,包括设备安装、API调用和数据解析过程,适合对Java身份证读卡器开发感兴趣的开发者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前端时间写项目写到了排队项目,需要用到身份证读取功能,但是市面找了很久发现读取身份证的基本没有java版本的,不是c#就是c++等,定下心来,决定自己写一个java读取身份证信息的工具类,技术没有难度,采用设备是公司购买的设备,不方便透露,各大厂家应该有自己的设备和读取驱动包。

设备安装

第一步设备安装就不解释了,自己安装设备和驱动。

java项目集成读取功能

本次采用的是通过固定端口,java项目集成jna来实现读取,第一步先添加依赖

 <dependency>
                <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.3.1</version>
        </dependency>
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna-platform</artifactId>
            <version>5.3.1</version>
        </dependency>

然后加载 sdtapi.dll 包,市面流通的sdtapi.dll 全是32位的,所以java项目用32位jdk来运行和启动,不知道有没有64位,我反正没找到

//    public static final String dllPath="D:\\java\\dll\\";
    public static final String dllPath="";
    public static final int port=1001;
    public interface CLibrary extends Library {
        // sdtapi.dll 32位的包,开发过程切换到32位的jdk运行,
        CLibrary INSTANCE = (CLibrary) Native.load(dllPath+"sdtapi", CLibrary.class);
        //读取身份证信息 使用到如下方法
        int SDT_OpenPort(int iPort);
        int SDT_StartFindIDCard( int iPort,
                                 byte[] a,
                                 int iIfOpen );
        int SDT_ReadBaseFPMsg( int iPort ,
                               byte[] pucCHMsg ,
                               IntByReference puiCHMsgLen ,
                               byte[] pucPHMsg ,
                               IntByReference puiPHMsgLen,
                               byte[] pucFPMsg,
                               IntByReference puiFMsgLen,
                               int iIfOpen );
        int SDT_SelectIDCard( int iPort ,
                              byte[] a,
                              int iIfOpen);
        int SDT_ReadBaseMsg(int iPort ,
                            byte[] pucCHMsg ,
                            IntByReference puiCHMsgLen ,
                            byte[] pucPHMsg ,
                            IntByReference puiPHMsgLen,
                            int iIfOpen  );
        int SDT_GetSAMIDToStr( int iPort,
                               byte[] strSAMID ,
                               int iIfOpen );
    }

先将如上方法定义到内部类中去,这些方法对应的就是sdtapi.dll 提供的方法,下面讲解具体用法。如果是本地测试将sdtapi.dll放到项目根目录,如果是部署,路径我是写死的。以下是身份证读取的方法和过程。

 /**
     * 读取身份证信息:返回为空表示读取失败
     * @return
     */
    public static synchronized IdcordBean readIdCord(){
        //打开端口
        int value = CLibrary.INSTANCE.SDT_OpenPort(port);
        System.out.println(Integer.toHexString(value));

        byte[] strSAMID = new byte[65] ;
        int samid= CLibrary.INSTANCE.SDT_GetSAMIDToStr(port, strSAMID,1);
        System.out.println("读取samid:"+Integer.toHexString(samid));
        String s = new String(strSAMID);
        System.out.println(s);
        byte[] bytes = new byte[16];

        //查找身份证
        int select = CLibrary.INSTANCE.SDT_StartFindIDCard(port, bytes,1);
        System.out.println("寻卡:"+Integer.toHexString(select));
        String s1 = new String(bytes);
        System.out.println(s1);
        //选卡
        int selectCode= CLibrary.INSTANCE.SDT_SelectIDCard(port, bytes,1);

        System.out.println("选卡:"+Integer.toHexString(selectCode));
        String s2 = new String(bytes);
        System.out.println(s2);

        byte[] pucCHMsg=new byte[256 + 1] ,pucPHMsg=new byte[1024 + 1],pucFPMsg=new byte[1024 + 1];
        IntByReference puiCHMsgLen=new IntByReference(0) , puiPHMsgLen=new IntByReference(0),puiFMsgLen=new IntByReference(0);
        //第一次读卡,带指纹的
//        int readOld= CLibrary.INSTANCE.SDT_ReadBaseFPMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,pucFPMsg,puiFMsgLen,1);
//        System.out.println("读卡1:"+Integer.toHexString(readOld)+":");
        //第二次读卡,不带指纹
        int read= CLibrary.INSTANCE.SDT_ReadBaseMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,1);
        System.out.println("读卡2:"+Integer.toHexString(read)+":");
        if(Integer.toHexString(read).equals(90+"")){
            byte[] byName = new byte[30];
            byte[] bySex = new byte[2];
            byte[] byRace = new byte[4];
            byte[] byBirth = new byte[16];
            byte[] byAddress = new byte[70];
            byte[] byID = new byte[36];
            byte[] byCompany = new byte[30];
            byte[] byBeginDate = new byte[16];
            byte[] byEndDate = new byte[16];

            System.arraycopy(pucCHMsg, 0, byName, 0, 30);
            System.arraycopy(pucCHMsg, 30, bySex, 0, 2);
            System.arraycopy(pucCHMsg, 32, byRace, 0, 4);
            System.arraycopy(pucCHMsg, 36, byBirth, 0, 16);
            System.arraycopy(pucCHMsg, 52, byAddress, 0, 70);
            System.arraycopy(pucCHMsg, 122, byID, 0, 36);
            System.arraycopy(pucCHMsg, 158, byCompany, 0, 30);
            System.arraycopy(pucCHMsg, 188, byBeginDate, 0, 16);
            System.arraycopy(pucCHMsg, 204, byEndDate, 0, 16);
            //解析身份证数据
            IdcordBean idcordBean=new IdcordBean();
            try {
                System.out.println(Arrays.toString(byName));
                System.out.println(Arrays.toString(byCompany));
                System.out.println(Arrays.toString(byAddress));
                byte[] namebytes=toByte(byName);
                byte[] companyBytes=toByte(byCompany);
                byte[] addressbytes=toByte(byAddress);
                String name = new String(namebytes, "UNICODE");
                String company = new String(companyBytes, "UNICODE");
                String address = new String(addressbytes, "UNICODE");
                idcordBean.setByName(name).setByCompany(company).setByAddress(address);
                //打印身份证信息
                System.out.println(name);
                System.out.println(company);
                System.out.println(address);

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            idcordBean.setBySex(new String(bySex).replaceAll("\\u0000",""))
                    .setByID(new String(byID).replaceAll("\\u0000",""))
                    .setByRace(new String(byRace).replaceAll("\\u0000",""))
                    .setByBirth(new String(byBirth).replaceAll("\\u0000",""))
                    .setByBeginDate(new String(byBeginDate).replaceAll("\\u0000",""))
                    .setByEndDate(new String(byEndDate).replaceAll("\\u0000",""));
//            System.out.println(new String(bySex));
//            System.out.println(new String(byRace));
//            System.out.println(new String(byBirth));
//            System.out.println(new String(byID));
//            System.out.println(new String(byBeginDate));
//            System.out.println(new String(byEndDate));
            return idcordBean;

        }
        return null;
    }
    //身份证汉字编码解码
    public static byte[] toByte(byte [] source){
        int length=0;
        for (int i = 0; i < source.length; i++) {
            if(source[i]==32&&source[i+1]==0){
                length=i;
                break;
            }
        }
        System.out.println(length);
        byte[] obj=new byte[length+2];
        obj[0]=-2;
        obj[1]=-1;
        for (int i = 0; i < length; i++) {
            if(i%2==0){
                obj[i+3]=source[i];
            }else{
                obj[i+1]=source[i];
            }
        }
        return obj;
    }

readIdCord 方法是读取身份证的方法和过程,toByte 是对汉字进行转码解析的一个方法。接下来我说以下我写的过程。

先看一下结果,其他信息涉及隐私就不显示了:

第一步先调用打开设备的方法,读取一下设备信息,寻找设备上是否有卡(身份证),返回状态马是16进制的,记得比较的时候进行转换。

  //打开端口
        int value = CLibrary.INSTANCE.SDT_OpenPort(port);
        System.out.println(Integer.toHexString(value));

        byte[] strSAMID = new byte[65] ;
        int samid= CLibrary.INSTANCE.SDT_GetSAMIDToStr(port, strSAMID,1);
        System.out.println("读取samid:"+Integer.toHexString(samid));
        String s = new String(strSAMID);
        System.out.println(s);
        byte[] bytes = new byte[16];

        //查找身份证
        int select = CLibrary.INSTANCE.SDT_StartFindIDCard(port, bytes,1);
        System.out.println("寻卡:"+Integer.toHexString(select));
        String s1 = new String(bytes);
        System.out.println(s1);

然后选择卡片进行卡片的数据读取(提前定义一个数组,参数用内存的方式写入

IntByReference 类型传值。

调用方法的时候传入进去,然后方法内部会向设备进行一个字节码写入)

//选卡
        int selectCode= CLibrary.INSTANCE.SDT_SelectIDCard(port, bytes,1);

        System.out.println("选卡:"+Integer.toHexString(selectCode));
        String s2 = new String(bytes);
        System.out.println(s2);

        byte[] pucCHMsg=new byte[256 + 1] ,pucPHMsg=new byte[1024 + 1],pucFPMsg=new byte[1024 + 1];
        IntByReference puiCHMsgLen=new IntByReference(0) , puiPHMsgLen=new IntByReference(0),puiFMsgLen=new IntByReference(0);
        //第一次读卡,带指纹的
//        int readOld= CLibrary.INSTANCE.SDT_ReadBaseFPMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,pucFPMsg,puiFMsgLen,1);
//        System.out.println("读卡1:"+Integer.toHexString(readOld)+":");
        //第二次读卡,不带指纹
        int read= CLibrary.INSTANCE.SDT_ReadBaseMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,1);
        System.out.println("读卡2:"+Integer.toHexString(read)+":");

然后对读取结果进行处理,我这个设备结果16进制的90是成功状态

if(Integer.toHexString(read).equals(90+"")){
            byte[] byName = new byte[30];
            byte[] bySex = new byte[2];
            byte[] byRace = new byte[4];
            byte[] byBirth = new byte[16];
            byte[] byAddress = new byte[70];
            byte[] byID = new byte[36];
            byte[] byCompany = new byte[30];
            byte[] byBeginDate = new byte[16];
            byte[] byEndDate = new byte[16];

            System.arraycopy(pucCHMsg, 0, byName, 0, 30);
            System.arraycopy(pucCHMsg, 30, bySex, 0, 2);
            System.arraycopy(pucCHMsg, 32, byRace, 0, 4);
            System.arraycopy(pucCHMsg, 36, byBirth, 0, 16);
            System.arraycopy(pucCHMsg, 52, byAddress, 0, 70);
            System.arraycopy(pucCHMsg, 122, byID, 0, 36);
            System.arraycopy(pucCHMsg, 158, byCompany, 0, 30);
            System.arraycopy(pucCHMsg, 188, byBeginDate, 0, 16);
            System.arraycopy(pucCHMsg, 204, byEndDate, 0, 16);
            //解析身份证数据
            IdcordBean idcordBean=new IdcordBean();
            try {
                System.out.println(Arrays.toString(byName));
                System.out.println(Arrays.toString(byCompany));
                System.out.println(Arrays.toString(byAddress));
                byte[] namebytes=toByte(byName);
                byte[] companyBytes=toByte(byCompany);
                byte[] addressbytes=toByte(byAddress);
                String name = new String(namebytes, "UNICODE");
                String company = new String(companyBytes, "UNICODE");
                String address = new String(addressbytes, "UNICODE");
                idcordBean.setByName(name).setByCompany(company).setByAddress(address);
                //打印身份证信息
                System.out.println(name);
                System.out.println(company);
                System.out.println(address);

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            idcordBean.setBySex(new String(bySex).replaceAll("\\u0000",""))
                    .setByID(new String(byID).replaceAll("\\u0000",""))
                    .setByRace(new String(byRace).replaceAll("\\u0000",""))
                    .setByBirth(new String(byBirth).replaceAll("\\u0000",""))
                    .setByBeginDate(new String(byBeginDate).replaceAll("\\u0000",""))
                    .setByEndDate(new String(byEndDate).replaceAll("\\u0000",""));
//            System.out.println(new String(bySex));
//            System.out.println(new String(byRace));
//            System.out.println(new String(byBirth));
//            System.out.println(new String(byID));
//            System.out.println(new String(byBeginDate));
//            System.out.println(new String(byEndDate));
            return idcordBean;

        }

注意:我的设备读取出来的身份证设备的汉字的字节码需要进行转换,我提供一下我的汉字编码信息(姓名,发证机关,住址,有兴趣的可以进行解码试试),汉字编码是 UNICODE编码,其他信息将 UNICODE编码的空格给替换掉  "".replaceAll("\\u0000","")

[115, -105, 122, 102, 58, 95, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0]
[-26, 121, -119, 91, -65, 83, 108, 81, -119, 91, 64, 92, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0]
[24, 117, -125, -128, 1, 119, -26, 121, -119, 91, -65, 83, -10, 83, 33, 88, 71, -107, -80, 101, 84, -128, 81, 103, 50, 0, -9, 83, -13, 119, -126, -126, -60, 126, 18, -1, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0, 32, 0]

 解码方法:

//身份证汉字编码解码
    public static byte[] toByte(byte [] source){
        int length=0;
        for (int i = 0; i < source.length; i++) {
            if(source[i]==32&&source[i+1]==0){
                length=i;
                break;
            }
        }
        System.out.println(length);
        byte[] obj=new byte[length+2];
        obj[0]=-2;
        obj[1]=-1;
        for (int i = 0; i < length; i++) {
            if(i%2==0){
                obj[i+3]=source[i];
            }else{
                obj[i+1]=source[i];
            }
        }
        return obj;
    }

最后给一份完整的代码

public class UsbIdCordRead {

//    public static final String dllPath="D:\\java\\dll\\";
    public static final String dllPath="";
    public static final int port=1001;
    public interface CLibrary extends Library {
        // sdtapi.dll 32位的包,开发过程切换到32位的jdk运行,
        CLibrary INSTANCE = (CLibrary) Native.load(dllPath+"sdtapi", CLibrary.class);
        //读取身份证信息 使用到如下方法
        int SDT_OpenPort(int iPort);
        int SDT_StartFindIDCard( int iPort,
                                 byte[] a,
                                 int iIfOpen );
        int SDT_ReadBaseFPMsg( int iPort ,
                               byte[] pucCHMsg ,
                               IntByReference puiCHMsgLen ,
                               byte[] pucPHMsg ,
                               IntByReference puiPHMsgLen,
                               byte[] pucFPMsg,
                               IntByReference puiFMsgLen,
                               int iIfOpen );
        int SDT_SelectIDCard( int iPort ,
                              byte[] a,
                              int iIfOpen);
        int SDT_ReadBaseMsg(int iPort ,
                            byte[] pucCHMsg ,
                            IntByReference puiCHMsgLen ,
                            byte[] pucPHMsg ,
                            IntByReference puiPHMsgLen,
                            int iIfOpen  );
        int SDT_GetSAMIDToStr( int iPort,
                               byte[] strSAMID ,
                               int iIfOpen );
    }

    /**
     * 读取身份证信息:返回为空表示读取失败
     * @return
     */
    public static synchronized IdcordBean readIdCord(){
        //打开端口
        int value = CLibrary.INSTANCE.SDT_OpenPort(port);
        System.out.println(Integer.toHexString(value));

        byte[] strSAMID = new byte[65] ;
        int samid= CLibrary.INSTANCE.SDT_GetSAMIDToStr(port, strSAMID,1);
        System.out.println("读取samid:"+Integer.toHexString(samid));
        String s = new String(strSAMID);
        System.out.println(s);
        byte[] bytes = new byte[16];

        //查找身份证
        int select = CLibrary.INSTANCE.SDT_StartFindIDCard(port, bytes,1);
        System.out.println("寻卡:"+Integer.toHexString(select));
        String s1 = new String(bytes);
        System.out.println(s1);
        //选卡
        int selectCode= CLibrary.INSTANCE.SDT_SelectIDCard(port, bytes,1);

        System.out.println("选卡:"+Integer.toHexString(selectCode));
        String s2 = new String(bytes);
        System.out.println(s2);

        byte[] pucCHMsg=new byte[256 + 1] ,pucPHMsg=new byte[1024 + 1],pucFPMsg=new byte[1024 + 1];
        IntByReference puiCHMsgLen=new IntByReference(0) , puiPHMsgLen=new IntByReference(0),puiFMsgLen=new IntByReference(0);
        //第一次读卡,带指纹的
//        int readOld= CLibrary.INSTANCE.SDT_ReadBaseFPMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,pucFPMsg,puiFMsgLen,1);
//        System.out.println("读卡1:"+Integer.toHexString(readOld)+":");
        //第二次读卡,不带指纹
        int read= CLibrary.INSTANCE.SDT_ReadBaseMsg(port, pucCHMsg,puiCHMsgLen,pucPHMsg,puiPHMsgLen,1);
        System.out.println("读卡2:"+Integer.toHexString(read)+":");
        if(Integer.toHexString(read).equals(90+"")){
            byte[] byName = new byte[30];
            byte[] bySex = new byte[2];
            byte[] byRace = new byte[4];
            byte[] byBirth = new byte[16];
            byte[] byAddress = new byte[70];
            byte[] byID = new byte[36];
            byte[] byCompany = new byte[30];
            byte[] byBeginDate = new byte[16];
            byte[] byEndDate = new byte[16];

            System.arraycopy(pucCHMsg, 0, byName, 0, 30);
            System.arraycopy(pucCHMsg, 30, bySex, 0, 2);
            System.arraycopy(pucCHMsg, 32, byRace, 0, 4);
            System.arraycopy(pucCHMsg, 36, byBirth, 0, 16);
            System.arraycopy(pucCHMsg, 52, byAddress, 0, 70);
            System.arraycopy(pucCHMsg, 122, byID, 0, 36);
            System.arraycopy(pucCHMsg, 158, byCompany, 0, 30);
            System.arraycopy(pucCHMsg, 188, byBeginDate, 0, 16);
            System.arraycopy(pucCHMsg, 204, byEndDate, 0, 16);
            //解析身份证数据
            IdcordBean idcordBean=new IdcordBean();
            try {
                System.out.println(Arrays.toString(byName));
                System.out.println(Arrays.toString(byCompany));
                System.out.println(Arrays.toString(byAddress));
                byte[] namebytes=toByte(byName);
                byte[] companyBytes=toByte(byCompany);
                byte[] addressbytes=toByte(byAddress);
                String name = new String(namebytes, "UNICODE");
                String company = new String(companyBytes, "UNICODE");
                String address = new String(addressbytes, "UNICODE");
                idcordBean.setByName(name).setByCompany(company).setByAddress(address);
                //打印身份证信息
                System.out.println(name);
                System.out.println(company);
                System.out.println(address);

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            idcordBean.setBySex(new String(bySex).replaceAll("\\u0000",""))
                    .setByID(new String(byID).replaceAll("\\u0000",""))
                    .setByRace(new String(byRace).replaceAll("\\u0000",""))
                    .setByBirth(new String(byBirth).replaceAll("\\u0000",""))
                    .setByBeginDate(new String(byBeginDate).replaceAll("\\u0000",""))
                    .setByEndDate(new String(byEndDate).replaceAll("\\u0000",""));
//            System.out.println(new String(bySex));
//            System.out.println(new String(byRace));
//            System.out.println(new String(byBirth));
//            System.out.println(new String(byID));
//            System.out.println(new String(byBeginDate));
//            System.out.println(new String(byEndDate));
            return idcordBean;

        }
        return null;
    }
    //身份证汉字编码解码
    public static byte[] toByte(byte [] source){
        int length=0;
        for (int i = 0; i < source.length; i++) {
            if(source[i]==32&&source[i+1]==0){
                length=i;
                break;
            }
        }
        System.out.println(length);
        byte[] obj=new byte[length+2];
        obj[0]=-2;
        obj[1]=-1;
        for (int i = 0; i < length; i++) {
            if(i%2==0){
                obj[i+3]=source[i];
            }else{
                obj[i+1]=source[i];
            }
        }
        return obj;
    }

    public static void main(String[] args) {
        readIdCord();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值