【湖南步联科技身份证】 身份证读取与酒店收银系统源码整合———未来之窗行业应用跨平台架构

 一、html5

<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><script type="text/javascript" src="http://51.onelink.ynwlzc.net/o2o/tpl/Merchant/static/js/jquery.min.js"></script><style type="text/css">html {height: 100%;width: 100%;}#readCard {width: 90px;margin: 10px;}#output {width: 500px;height: 200px;}</style></head><body><h1>读身份证示例-湖南步联科技身份证
</h1> <h1>未来之窗星链-推进器测试
</h1><br><input type="button" id="getReader" value="列出设备" style="margin:10px" onclick="getReader();" /><select id="readerList" style="width:250px;margin:10px"></select><!-- 读卡参数<input type="text" id="readParam" value='{"portType": 5}' size="25" style="margin:10px" > --><br/><input type="button" id="readCard" value="读卡" onclick="startReadCard();" /><input type="checkbox" id="autoReadCard" value="autoRead"  >自动读卡<br>阅读次数:<input type="text" id="totalReadCount" name="Num" value="100" size="7">成功次数<input type="text" id="SuccessTimes" value="0" size="7">失败次数<input type="text" id="FailTimes" value="0" size="7">所用时间<input type="text" id="TimeExpand" value="0" size="7">成功率<input type="text" id="Rate" value="0%" size="5">平均耗时<input type="text" id="AvgTime" value="0" size="5"><br>开始时间<input type="text" id="StartTime" value="" size="25">完成时间<input type="text" id="EndTime" value="" size="25">单次用时<input type="text" id="ReadTime" value="111" size="25"><table border="1" cellpadding="0" cellspacing="2" bordercolor="#3333FF"><tr><td><div align="right">姓名:</div></td><td><input name="text_name" type="text" id="text_name" size="20"/></td><td><div align="right">性别代码:</div></td><td><input name="text_genderid" type="text" id="text_genderid" size="5"/></td><td><div align="right">民族代码:</div></td><td><input name="text_nationid" type="text" id="text_nationid" size="5"/></td><td><div align="right">出生日期:</div></td><td><input name="text_birthdate" type="text" id="text_birthdate" size="20"/></td></tr><tr><td><div align="right">身份证号码:</div></td><td><input name="text_idnumber" type="text" id="text_idnumber" size="20"/></td><td><div align="right">签发机关:</div></td><td><input name="text_signorgan" type="text" id="text_signorgan" size="20"/></td><td><div align="right">起始有效期:</div></td><td><input name="text_beginterm" type="text" id="text_beginterm" size="20"/></td><td><div align="right">终止有效期:</div></td><td><input name="text_endterm" type="text" id="text_endterm" size="20"/></td></tr><tr><td><div align="right">住址:</div></td><td colspan="5"><input name="text_address" type="text" id="text_address" size="82"/></td><td><div align="right">民族:</div></td><td><input name="text_nationid" type="text" id="text_nation" size="5"/></td></tr><tr><td height="43"><div align="right">照片编码:</div></td><td colspan="7"><textarea name="text_photobase64" cols="80" rows="5" id="text_photobase64"></textarea></td><td><img name="PhotoDisplay" id="PhotoDisplay" style="width:102px; height:126px;"/></td></tr></table><br/><textarea id="output"></textarea><br/></body>
</html><script type="text/javascript" >var baseUrl = "http://127.0.0.1:6045"
$(document).ready(function(){//解决IE浏览器不支持console,报错未定义问题window.console = window.console || (function () {var c ={};c.log = c.warn = c.debug = c.info = c.error = c.time = c.dir = c.profile= c.clear = c.exception = c.trace = c.assert = function(){};return c;})();
//    alert(location.host)
//    if(location.host){
//        baseUrl = location.protocol + "//" + location.host;
//    }console.log("baseurl "+ baseUrl);});function fixInt(val){if(val<10)return "0"+val;elsereturn val;
}function fmtDate(date){return date.getFullYear()+"-"+fixInt(date.getMonth()+1)+"-"+fixInt(date.getDate())+" "+fixInt(date.getHours())+":"+fixInt(date.getMinutes())+":"+fixInt(date.getSeconds())+":"+fixInt(date.getMilliseconds());
}function clearForm() {$("#output").text("");$("#text_name").val("");$("#text_genderid").val("");$("#text_nationid").val("");$("#text_birthdate").val("");$("#text_address").val("");$("#text_idnumber").val("");$("#text_signorgan").val("");$("#text_beginterm").val("");$("#text_endterm").val("");}function getReader(){$.ajax({type: "get",dataType: "json", timeout:10000,crossDomain: true,url: baseUrl + "/getCardReaderList",success: function(resultInfo) {$("#output").text(JSON.stringify(resultInfo));var list = document.getElementById("readerList");for(var i = list.options.length-1; i >= 0; i--){list.remove(i);}var strArray = resultInfo;for(var i = 0; i < resultInfo.length; i++){var newOption = document.createElement("option");newOption.setAttribute("version", strArray[i].version);newOption.setAttribute("index", strArray[i].index);newOption.appendChild(document.createTextNode(strArray[i].version));list.appendChild(newOption);}},error: function(jqXHR, textStatus, errorThrown) {console.error("getReader request error  ", textStatus, errorThrown );$("#output").text("getReader error status "+ textStatus+" errorThrown "  +errorThrown)}});
}
function parseCardWzxx(wzxx) {var result = {};result['xm'] = wzxx.substr(0, 15);result['xbdm'] = wzxx.substr(15, 1);result['mzdm'] = wzxx.substr(16, 2);result['csrq'] = wzxx.substr(18, 8);result['dzmc'] = wzxx.substr(26, 35);result['gmsfhm'] = wzxx.substr(61, 18);result['qfjgmc'] = wzxx.substr(79, 15);result['qfjgmc'] = wzxx.substr(79, 15);result['yxqqsrq'] = wzxx.substr(94, 8);result['yxqjzrq'] = wzxx.substr(102, 8);result['zjlxbs'] = wzxx.substr(124, 1);switch (result['xbdm']) {case '1': result['xbmc'] = '男'; break;case '2': result['xbmc'] = '女'; break;default: result['xbmc'] = '未知';}if (result['zjlxbs'] == 'J'){result['txzhm'] = wzxx.substr(110, 9);result['qfcs'] = wzxx.substr(119, 2);}switch (result['mzdm']) {case '01': result['mzmc'] = '汉'; break;case '02': result['mzmc'] = '蒙古'; break;case '03': result['mzmc'] = '回'; break;case '04': result['mzmc'] = '藏'; break;case '05': result['mzmc'] = '维吾尔'; break;case '06': result['mzmc'] = '苗'; break;case '07': result['mzmc'] = '彝'; break;case '08': result['mzmc'] = '壮'; break;case '09': result['mzmc'] = '布依'; break;case '10': result['mzmc'] = '朝鲜'; break;case '11': result['mzmc'] = '满'; break;case '12': result['mzmc'] = '侗'; break;case '13': result['mzmc'] = '瑶'; break;case '14': result['mzmc'] = '白'; break;case '15': result['mzmc'] = '土家'; break;case '16': result['mzmc'] = '哈尼'; break;case '17': result['mzmc'] = '哈萨克'; break;case '18': result['mzmc'] = '傣'; break;case '19': result['mzmc'] = '黎'; break;case '20': result['mzmc'] = '傈僳'; break;case '21': result['mzmc'] = '佤'; break;case '22': result['mzmc'] = '畲'; break;case '23': result['mzmc'] = '高山'; break;case '24': result['mzmc'] = '拉祜'; break;case '25': result['mzmc'] = '水'; break;case '26': result['mzmc'] = '东乡'; break;case '27': result['mzmc'] = '纳西'; break;case '28': result['mzmc'] = '景颇'; break;case '29': result['mzmc'] = '柯尔克孜'; break;case '30': result['mzmc'] = '土'; break;case '31': result['mzmc'] = '达翰尔'; break;case '32': result['mzmc'] = '仫佬'; break;case '33': result['mzmc'] = '羌'; break;case '34': result['mzmc'] = '布朗'; break;case '35': result['mzmc'] = '撒拉'; break;case '36': result['mzmc'] = '毛南'; break;case '37': result['mzmc'] = '仡佬'; break;case '38': result['mzmc'] = '锡伯'; break;case '39': result['mzmc'] = '阿昌'; break;case '40': result['mzmc'] = '普米'; break;case '41': result['mzmc'] = '塔吉克'; break;case '42': result['mzmc'] = '怒'; break;case '43': result['mzmc'] = '乌孜别克'; break;case '44': result['mzmc'] = '俄罗斯'; break;case '45': result['mzmc'] = '鄂温克'; break;case '46': result['mzmc'] = '德昂'; break;case '47': result['mzmc'] = '保安'; break;case '48': result['mzmc'] = '裕固'; break;case '49': result['mzmc'] = '京'; break;case '50': result['mzmc'] = '塔塔尔'; break;case '51': result['mzmc'] = '独龙'; break;case '52': result['mzmc'] = '鄂伦春'; break;case '53': result['mzmc'] = '赫哲'; break;case '54': result['mzmc'] = '门巴'; break;case '55': result['mzmc'] = '珞巴'; break;case '56': result['mzmc'] = '基诺'; break;case '59': result['mzmc'] = '穿青人'; break;case '60': result['mzmc'] = '革家人'; break;case '97': result['mzmc'] = '其它'; break;case '98': result['mzmc'] = '入籍'; break;case '99': result['mzmc'] = '其它'; break;default: result['mzmc'] = '';}return result;
}
var totalStartTime;
var totalReadCount;
var SuccessTimes = 0;
var FailTimes = 0;
var totalUsedTime = 0;
function startReadCard(){totalStartTime = new Date();totalReadCount = $("#totalReadCount").val();SuccessTimes = 0;FailTimes = 0;totalUsedTime = 0;readCard();
}function readCard(){   clearForm();var startTime = new Date();$("#StartTime").val(fmtDate(startTime));$("#readCard").attr("disabled", "disabled");var readerIndex = $("#readerList").find("option:selected").attr("index");console.info("read card", readerIndex)$.ajax({type: "get",dataType: "json", timeout:10000,url: baseUrl + "/readIDCard?index="+readerIndex,success: function(resultInfo) {console.info("readIDCard ", resultInfo, status);$("#output").text(JSON.stringify(resultInfo));if( resultInfo.result === 0 ){var textInfo = resultInfo.wzInfo;$("#text_name").val(textInfo.substr(0,15).trim());$("#text_genderid").val(textInfo.substr(15,1).trim());$("#text_nationid").val(textInfo.substr(16,2).trim());$("#text_birthdate").val(textInfo.substr(18,8).trim());$("#text_address").val(textInfo.substr(26,35).trim());$("#text_idnumber").val(textInfo.substr(61,18).trim());$("#text_signorgan").val(textInfo.substr(79,15).trim());$("#text_beginterm").val(textInfo.substr(94,8).trim());$("#text_endterm").val(textInfo.substr(102,8).trim());var wzObj = parseCardWzxx(textInfo);$("#text_nation").val(wzObj.mzmc);console.info("read card success", wzObj) ;$.ajax({type: "get",dataType: "json", timeout:10000,url:baseUrl +"/wltUnpack?wlt="+resultInfo.zpWlt+"&format=bmp",success:function(response){if(response['result'] === 0){var imageBase64 = response['image'];$("#text_photobase64").val(imageBase64);document.all['PhotoDisplay'].src = 'data:image/bmp;base64,' + imageBase64;}else{alert("unpack error " + response['result']);}},complete: function(XMLHttpRequest, textStatus) {}});} var endTime = new Date();$("#EndTime").val(fmtDate(endTime));var usedTime = endTime.getTime()-startTime.getTime();$("#ReadTime").val(usedTime + "ms");if ( $('#autoReadCard').is(":checked") && totalReadCount--> 0){self.setTimeout("readCard()", 1000);totalUsedTime +=  usedTime;$("#TimeExpand").val(totalUsedTime + "ms");if(resultInfo.result == 0){++SuccessTimes; }else{++FailTimes;}$("#SuccessTimes").val(SuccessTimes);$("#FailTimes").val(FailTimes);$("#Rate").val(SuccessTimes*100/(SuccessTimes+FailTimes) + "%");$("#AvgTime").val(totalUsedTime/(SuccessTimes+FailTimes) + "ms");}else{$("#readCard").removeAttr("disabled");}},complete: function(XMLHttpRequest, textStatus) {
//            alert("cloudReadCard/appId complete");console.info("complete");},error: function(jqXHR, textStatus, errorThrown) {console.error("read card request error  ", textStatus, errorThrown );$("#output").text("read card error status "+ textStatus+" errorThrown "  +errorThrown)$("#readCard").removeAttr("disabled");}});
}</script>

二、JAVA

import com.bland.IDReader;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.Base64;import java.io.*;public class demo{static public String race_table[][] ={{"01","汉族"},//   GB/T 3304-1991","Han","HA{"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG{"03","回族"},//   GB/T 3304-1991","Hui","HU{"04","藏族"},//   GB/T 3304-1991","Zang","ZA{"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG{"06","苗族"},//   GB/T 3304-1991","Miao","MH{"07","彝族"},//   GB/T 3304-1991","Yi","YI{"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH{"09","布依族"},//   GB/T 3304-1991","Buyei","BY{"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs{"11","满族"},//   GB/T 3304-1991","Man","MA{"12","侗族"},//   GB/T 3304-1991","Dong","DO{"13","瑶族"},//   GB/T 3304-1991","Yao","YA{"14","白族"},//   GB/T 3304-1991","Bai","BA{"15","土家族"},//   GB/T 3304-1991","Tujia","TJ{"16","哈尼族"},//   GB/T 3304-1991","Hani","HN{"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ{"18","傣族"},//   GB/T 3304-1991","Dai","DA{"19","黎族"},//   GB/T 3304-1991","Li","LI{"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS{"21","佤族"},//   GB/T 3304-1991","Va","VA{"22","畲族"},//   GB/T 3304-1991","She","SH{"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs{"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH{"25","水族"},//   GB/T 3304-1991","Sui","su{"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX{"27","纳西族"},//   GB/T 3304-1991","Naxi","NX{"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP{"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG{"30","土族"},//   GB/T 3304-1991","Tu","TU{"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU{"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML{"33","羌族"},//   GB/T 3304-1991","Qiang","QI{"34","布朗族"},//   GB/T 3304-1991","Blang","BL{"35","撒拉族"},//   GB/T 3304-1991","Salar","SL{"36","毛南族"},//   GB/T 3304-1991","Maonan","MN{"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL{"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB{"39","阿昌族"},//   GB/T 3304-1991","Achang","AC{"40","普米族"},//   GB/T 3304-1991","Pumi","PM{"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA{"42","怒族"},//   GB/T 3304-1991","Nu","NU{"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz{"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS{"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW{"46","德昂族"},//   GB/T 3304-1991","Deang","DE{"47","保安族"},//   GB/T 3304-1991","Bonan","BN{"48","裕固族"},//   GB/T 3304-1991","Yugur","YG{"49","京族"},//   GB/T 3304-1991","Gin","GI{"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT{"51","独龙族"},//   GB/T 3304-1991","Derung","DR{"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR{"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ{"54","门巴族"},//   GB/T 3304-1991","Monba","MB{"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB{"56","基诺族"},//   GB/T 3304-1991","Jino","JN{"",""}};/*** 将民族代码,转换成文本* @param code* @return*/public static String GetRace(String code) {int i;for (i = 0; i < race_table.length; i++) {if (race_table[i][0].compareTo(code) == 0) {return race_table[i][1];}}return "其它";}/*** 显示身份证信息* @param text 文本* @param image 照片*/public static void ViewInfo(String text,byte[] image) {System.out.println(text);try{File imgFile = new File("image.jpg"); FileOutputStream writer = new FileOutputStream(imgFile); writer.write(image); writer.close(); }catch (Exception e){e.printStackTrace(); }}/*** 解析SN* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static int ParseSN(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("errorMsg")) {//System.out.println(jsondata.getString("errorMsg"));return -1;}if( !jsondata.has("data") ) {return -1;}JSONObject content = jsondata.getJSONObject("data");System.out.println("SAM ID: " + content.getString("samid"));if(content.has("sn")) {System.out.println("SN: " + content.getString("sn"));}}catch (Exception e) {e.printStackTrace(); return -1;}return 0;}/*** 解析身份证读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static String ParseIDInfo(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.getString("function").compareTo("readcard") != 0) {return "";//不是读卡消息,直接返回}if(jsondata.has("errorMsg")) {System.out.println(jsondata.getString("errorMsg"));return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {return "";}JSONObject content = jsondata.getJSONObject("data");if(content.getString("type").compareTo("I") == 0) { info = "外国人永久居留证";}else if(content.getString("type").compareTo("J") == 0) { info = "港澳台居住证";}else if(content.getString("type").compareTo(" ") == 0) { info = "居民身份证";}else  {info = "未知";}info = info + "\r\n姓名:" + content.getString("name");info = info + "\r\n身份证号:" + content.getString("number");String gender;if(content.getInt("gender") == 1) {gender = "男";}else if (content.getInt("gender") == 2){gender = "女";}else {gender = "未知";}info = info + "\r\n性别: " + gender;if(content.getString("type").compareTo(" ") == 0) { //只有身份证有民族信息info = info + "\r\n民族: " + GetRace(content.getString("race"));}info = info + "\r\n生日: " + content.getString("birthday");if(content.getString("type").compareTo("I") != 0 ) { //外国人永久居留证没有住址信息info = info + "\r\n住址: " + content.getString("address");}info = info + "\r\n签发机关: " + content.getString("issuer");info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");if(content.getString("type").compareTo("I") == 0) { //外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n版本: " + content.getString("version");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("J") == 0) { //港澳台居住证info = info + "\r\n通行证号码: " + content.getString("pass_number");info = info + "\r\n签发次数: " + content.getString("issue_count");}info = info + "\r\n";img = Base64.getDecoder().decode(content.getString("photo"));ViewInfo(info,img);return "读卡成功!";}catch (Exception e) {e.printStackTrace(); return e.getMessage();}}/*** 解析银行卡读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/public static String ParseBankInfo(String str) {byte[] img;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("errorMsg")) {System.out.println(jsondata.getString("errorMsg"));return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {return "";}JSONObject content = jsondata.getJSONObject("data");info = info + "\r\n银行卡号:" + content.getString("number");info = info + "\r\n有效期截止: " + content.getString("expire");info = info + "\r\n持卡人:" + content.getString("owner");info = info + "\r\n持卡人证件号码: " + content.getString("owner_id");info = info + "\r\n";System.out.println(info);return "读卡成功!";}catch (Exception e) {e.printStackTrace(); return e.getMessage();}}/*** 解析读卡结果的返回值* @param str JSON 格式字符串* @return 返回读卡结果的返回值*/public static int GetRetValue(String str) {try {JSONObject jsondata = new JSONObject(str);if(jsondata.has("ret")) {return jsondata.getInt("ret");}else {return -1;}}catch (Exception e) {e.printStackTrace(); return -1;}}public static void main(String [] args) {String systemType = System.getProperty("os.name");   String systemArch = System.getProperty("os.arch");   IDReader reader = new IDReader();System.out.println("System Type: " + systemType + ", " + systemArch);//提供一个可读写的目录,用于初始化过程中读写配置,解压调用库文件。初始化只能调用一次。reader.Init("./res");System.out.println("demo start!");try{while(true) {Thread.sleep(100);String result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");if(ParseSN(result) == 0) {break;}}}catch (Exception e){e.printStackTrace(); }try{while(true) {String result;result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}");if( GetRetValue(result) == 0) {ParseIDInfo(result);Thread.sleep(1000);continue;}result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}");if( GetRetValue(result) == 0) {//读银行卡号码result = reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\"}");ParseBankInfo(result);Thread.sleep(1000);continue;}Thread.sleep(100);}}catch (Exception e){e.printStackTrace(); }}
}

三、PYTHON

# -*- coding: utf-8 -*-
# import urllib2
import urllib.request
import json
import timerace = ["","汉族","蒙古族","回族","藏族","维吾尔族","苗族","彝族","壮族","布依族","朝鲜族","满族","侗族","瑶族","白族","土家族","哈尼族","哈萨克族","傣族","黎族","傈僳族","佤族","畲族","高山族","拉枯族","水族","东乡族","纳西族","景颇族","柯尔克孜族","土族","达斡尔族","仫佬族","羌族","布朗族","撒拉族","毛南族","仡佬族","锡伯族","阿昌族","普米族","塔吉克族","怒族","乌孜别克族","俄罗斯族","鄂温克族","德昂族","保安族","裕固族","京族","塔塔尔族","独龙族","鄂伦春族","赫哲族","门巴族","珞巴族" ,"基诺族"]
gender = ["未知","男","女","其他"]while 1:time.sleep(1)url = "http://127.0.0.1:7846/api/readCard?utf8=1"response = urllib.request.urlopen(url)page_html = response.read()#print(page_html)result = json.loads(page_html)if result["resultFlag"] == "0":print("读卡成功:\n")print("身份证号码:"+result["resultContent"]["idNum"])print("姓名:"+result["resultContent"]["name"])print("性别:"+gender[int(result["resultContent"]["gender"])])print("民族:"+race[int(result["resultContent"]["nation"])])print("地址:"+result["resultContent"]["address"])print("生日:"+result["resultContent"]["birthday"])print("有效期: "+result["resultContent"]["effectDate"] + "-" + result["resultContent"]["expireDate"] )print("签发机关: "+result["resultContent"]["issueOrg"])continueurl = "http://127.0.0.1:7846/readBankCard"response = urllib.request.urlopen(url)page_html = response.read()#print(page_html)result = json.loads(page_html)if result["result"] == 0 :print("读卡成功:\n")print("银行卡号码:"+result["number"])print("有效期截止:"+result["expire"])print("持卡人:"+result["owner"])print("持卡人证件号码:"+result["owner_id"])

四、VB

Public Class Form1Dim port As reader_serviceLib.sdt = New reader_serviceLib.sdt()Dim card As reader_serviceLib.cardPrivate Sub refreshButton()Dim ret As Integerret = port.opened()If ret = 0 ThenbtOpen.Enabled = TruebtReadCard.Enabled = FalsebtReadBank.Enabled = FalsebtOpen.Text = "打开"ElsebtOpen.Enabled = TruebtReadCard.Enabled = TruebtReadBank.Enabled = TruebtOpen.Text = "关闭"If ret > 1000 ThenTextStatus.Text = "已打开USB端口" & retElseTextStatus.Text = "已打开串口COM" & retEnd IfTextSAMID.Text = port.samid()End IfEnd SubPrivate Sub btReadCard_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btReadCard.ClickDim ret As Integerret = port.find()If ret <> &H9F ThenTextStatus.Text = "找卡失败!"Exit SubEnd Ifret = port.select()If ret <> &H90 ThenTextStatus.Text = "选卡失败!"Exit SubEnd IfTextCardSN.Text = port.cardSN(0)card = port.readcard(0)If card.name = "" ThenTextStatus.Text = "读卡失败!"Exit SubEnd IfTextName.Text = card.nameTextAddress.Text = card.addressTextBirthday.Text = card.birthdayTextGender.Text = card.genderTextIssuer.Text = card.issuerTextRace.Text = card.raceTextNumber.Text = card.numberTextExpired.Text = card.valied & "-" & card.expirePictureBox1.ImageLocation = card.image_pathEnd SubPrivate Sub btOpen_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btOpen.ClickDim ret As IntegerIf ComboPortList.Text = "USB" Thenret = port.open(1001, 115200)ElseIf ComboPortList.Text.StartsWith("COM") Thenret = port.open(Integer.Parse(ComboPortList.Text.Substring(3)), 115200)Elseret = port.open(0, 0)End IfIf ret <> &H90 ThenTextStatus.Text = "端口打开失败!"Exit SubEnd IfCall refreshButton()End SubPrivate Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.LoadrefreshButton()End SubPrivate Sub btReadBank_Click(sender As Object, e As EventArgs) Handles btReadBank.ClickDim uid As reader_serviceLib.iso14443a_uidDim obj()Dim ret As Integerobj = port.iso14443a_find(4)If obj.Length = 0 ThenTextStatus.Text = "找卡失败!"' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Exit SubEnd Ifuid = obj(0)ret = port.iso14443a_select(uid.text, uid.sak)If ret <> &H90 Then' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Call MsgBox("选卡失败!")Exit SubEnd If'参数0代表读身份证,参数1代表读银行卡card = port.readcard(1)If card.number = "" Then' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()Call MsgBox("读卡失败!")Exit SubEnd IfCall MsgBox("银行卡号:" & card.number & ";有效期:" & card.expire & ";持卡人:" & card.name)' 必须要退出 ISO14443A 模式,否则下次无法读取身份证Call port.iso14443a_mode_exit()End Sub
End Class

五、安卓

package com.example.demo;import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;import com.bland.IDReader;
import com.bland.TpNfc;
import com.google.android.material.snackbar.Snackbar;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Message;
import android.os.Handler;
import android.view.View;
import android.app.PendingIntent;
import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.widget.Toast;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import android.content.Intent;
import android.content.IntentFilter;
import com.example.demo.databinding.ActivityMainBinding;import java.util.HashMap;import android.view.Menu;
import android.view.MenuItem;
import android.nfc.tech.NfcB;import org.json.JSONArray;
import org.json.JSONObject;
import 	android.provider.Settings;
import android.content.Context;
import android.nfc.Tag;
import android.nfc.NfcAdapter;
import android.util.Log;
import java.util.HashMap;
import android.util.Base64;
import android.widget.ImageView;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {//用于身份证解码先关变量public String race_table[][] ={{"01","汉族"},//   GB/T 3304-1991","Han","HA{"02","蒙古族"},//   GB/T 3304-1991","Mongol","MG{"03","回族"},//   GB/T 3304-1991","Hui","HU{"04","藏族"},//   GB/T 3304-1991","Zang","ZA{"05","维吾尔族"},//   GB/T 3304-1991","Uygur","uG{"06","苗族"},//   GB/T 3304-1991","Miao","MH{"07","彝族"},//   GB/T 3304-1991","Yi","YI{"08","壮族"},//   GB/T 3304-1991","Zhuang","ZH{"09","布依族"},//   GB/T 3304-1991","Buyei","BY{"10","朝鲜族"},//   GB/T 3304-1991","Chosen","cs{"11","满族"},//   GB/T 3304-1991","Man","MA{"12","侗族"},//   GB/T 3304-1991","Dong","DO{"13","瑶族"},//   GB/T 3304-1991","Yao","YA{"14","白族"},//   GB/T 3304-1991","Bai","BA{"15","土家族"},//   GB/T 3304-1991","Tujia","TJ{"16","哈尼族"},//   GB/T 3304-1991","Hani","HN{"17","哈萨克族"},//   GB/T 3304-1991","Kazak","KZ{"18","傣族"},//   GB/T 3304-1991","Dai","DA{"19","黎族"},//   GB/T 3304-1991","Li","LI{"20","傈僳族"},//   GB/T 3304-1991","Lisu","LS{"21","佤族"},//   GB/T 3304-1991","Va","VA{"22","畲族"},//   GB/T 3304-1991","She","SH{"23","高山族"},//   GB/T 3304-1991","Gaoshan","Gs{"24","拉枯族"},//   GB/T 3304-1991","Lahu","LH{"25","水族"},//   GB/T 3304-1991","Sui","su{"26","东乡族"},//   GB/T 3304-1991","Dongxiang","DX{"27","纳西族"},//   GB/T 3304-1991","Naxi","NX{"28","景颇族"},//   GB/T 3304-1991","Jingpo","JP{"29","柯尔克孜族"},//   GB/T 3304-1991","Kirgiz","KG{"30","土族"},//   GB/T 3304-1991","Tu","TU{"31","达斡尔族"},//   GB/T 3304-1991","Daur","DU{"32","仫佬族"},//   GB/T 3304-1991","Mulao","ML{"33","羌族"},//   GB/T 3304-1991","Qiang","QI{"34","布朗族"},//   GB/T 3304-1991","Blang","BL{"35","撒拉族"},//   GB/T 3304-1991","Salar","SL{"36","毛南族"},//   GB/T 3304-1991","Maonan","MN{"37","仡佬族"},//   GB/T 3304-1991","Gelao","GL{"38","锡伯族"},//   GB/T 3304-1991","Xibe","XB{"39","阿昌族"},//   GB/T 3304-1991","Achang","AC{"40","普米族"},//   GB/T 3304-1991","Pumi","PM{"41","塔吉克族"},//   GB/T 3304-1991","Tajik","TA{"42","怒族"},//   GB/T 3304-1991","Nu","NU{"43","乌孜别克族"},//   GB/T 3304-1991","Uzbek","Uz{"44","俄罗斯族"},//   GB/T 3304-1991","Russ","RS{"45","鄂温克族"},//   GB/T 3304-1991","Ewenki","EW{"46","德昂族"},//   GB/T 3304-1991","Deang","DE{"47","保安族"},//   GB/T 3304-1991","Bonan","BN{"48","裕固族"},//   GB/T 3304-1991","Yugur","YG{"49","京族"},//   GB/T 3304-1991","Gin","GI{"50","塔塔尔族"},//   GB/T 3304-1991","Tatar","TT{"51","独龙族"},//   GB/T 3304-1991","Derung","DR{"52","鄂伦春族"},//   GB/T 3304-1991","Oroqen","OR{"53","赫哲族"},//   GB/T 3304-1991","Hezhen","HZ{"54","门巴族"},//   GB/T 3304-1991","Monba","MB{"55","珞巴族"},//   GB/T 3304-1991","Lhoba","LB{"56","基诺族"},//   GB/T 3304-1991","Jino","JN{"",""}};private static final int SDK_NFC_FLAG = 3;private static final int SDK_READER_FLAG = 4;private static final int SDK_DEVICE_FLAG = 5;private static final int SDK_CLIENT_FLAG = 6;private static final int SDK_ICCARD_FLAG = 7;private static final int SDK_BANKCARD_FLAG = 8;//用于 OTG 阅读器相关变量public IDReader reader;public UsbManager usbManager;private static final String ACTION_USB_PERMISSION = "com.android.usb.USB_PERMISSION";private boolean id_card_exist = false;      // 标记上一次读卡时,身份证是否存在private String samid = "";                      // 标记阅读器是否连接,以及SAM ID是多少private String last_idcard_text = "";           // 最近一次身份证读卡信息,方便判断身份证是否变化private String last_iccard_text = "";           // 最近一次Mifare one读卡数据信息private String last_iccard_uid = "";           // 最近一次Mifare one 读卡UID信息private int last_iccard_sak = 0;           // 最近一次Mifare one 读卡SAK信息//用于手机本机 NFC 相关变量public TpNfc tpnfc;NfcAdapter mNfcAdapter;PendingIntent pIntent;//其他变量private AppBarConfiguration appBarConfiguration;private ActivityMainBinding binding;/*** 将民族代码,转换成文本* @param code* @return*/public String GetRace(String code) {int i;for (i = 0; i < race_table.length; i++) {if (race_table[i][0].compareTo(code) == 0) {return race_table[i][1];}}return "其它";}/*** 在 UI 上显示身份证信息* @param text 文本* @param image 照片*/void ViewInfo(String text,Bitmap image) {TextView tv = (TextView) findViewById(R.id.textview_first);ImageView iv = (ImageView) findViewById(R.id.imageView);tv.setText(text.toCharArray(), 0, text.toCharArray().length);iv.setImageBitmap(image);}/*** 解析身份证读卡结果* @param str JSON 格式字符串* @return 返回错误或成功信息*/String ParseInfo(String str) {Bitmap decodedByte = null;String info = "";try {JSONObject jsondata = new JSONObject(str);if(jsondata.getString("function").compareTo("readcard") != 0) {return "";//不是读卡消息,直接返回}if(jsondata.has("errorMsg")) {ViewInfo(info,decodedByte);  //卡片已拿走或其他错误,清空信息return jsondata.getString("errorMsg");}if( !jsondata.has("data") ) {//异常情况,不应该出现,清空信息ViewInfo(info,decodedByte);return "";}JSONObject content = jsondata.getJSONObject("data");if(content.getString("type").compareTo("I") == 0) {info = "2017版外国人永久居留证";}else if(content.getString("type").compareTo("Y") == 0) {info = "新版外国人永久居留证";}else if(content.getString("type").compareTo("J") == 0) {info = "港澳台居住证";}else if(content.getString("type").compareTo(" ") == 0) {info = "居民身份证";}else  {info = "未知";}info = info + "\r\n姓名:" + content.getString("name");info = info + "\r\n身份证号:" + content.getString("number");String gender;if(content.getInt("gender") == 1) {gender = "男";}else if (content.getInt("gender") == 2){gender = "女";}else {gender = "未知";}info = info + "\r\n性别: " + gender;if(content.getString("type").compareTo(" ") == 0) {//只有身份证有民族信息info = info + "\r\n民族: " + GetRace(content.getString("race"));}info = info + "\r\n生日: " + content.getString("birthday");if(content.getString("type").compareTo("I") != 0 ) {//外国人永久居留证没有住址信息info = info + "\r\n住址: " + content.getString("address");}info = info + "\r\n签发机关: " + content.getString("issuer");info = info + "\r\n有效期限: " + content.getString("valied") + "-" + content.getString("expire");if(content.getString("type").compareTo("I") == 0) {//2017版外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n版本: " + content.getString("version");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("Y") == 0) {//新版外国人永久居留证info = info + "\r\n中文名称: " + content.getString("cn_name");info = info + "\r\n换证次数: " + content.getString("renewal_count");info = info + "\r\n关联号码: " + content.getString("relational_number");info = info + "\r\n国籍: " + content.getString("nation");}else if(content.getString("type").compareTo("J") == 0) {//港澳台居住证info = info + "\r\n通行证号码: " + content.getString("pass_number");info = info + "\r\n签发次数: " + content.getString("issue_count");}byte[] img = Base64.decode(content.getString("photo"),Base64.DEFAULT);decodedByte = BitmapFactory.decodeByteArray(img, 0, img.length);ViewInfo(info,decodedByte);return "读卡成功!";}catch (Exception e) {return e.getMessage();}}/*** 处理身份证阅读消息,或者 OTG 阅读器插入拔出消息*/@SuppressLint("HandlerLeak")private Handler mHandler = new Handler(){@Overridepublic  void handleMessage(Message msg) {String err = "";switch (msg.what) {case SDK_NFC_FLAG: {err = ParseInfo((String)msg.obj);break;}case SDK_READER_FLAG: {err = ParseInfo((String)msg.obj);break;}case SDK_DEVICE_FLAG:{if(samid == "" ) {err = "阅读器已拔出!";}else {err = "阅读器已连接:" + samid;}break;}case SDK_CLIENT_FLAG: {ViewInfo((String)msg.obj,null);break;}case SDK_ICCARD_FLAG: {if(last_iccard_uid != "") {ViewInfo("uid: " + last_iccard_uid + "\r\ndata: " + last_iccard_text, null);}else {ViewInfo("",null);}break;}case SDK_BANKCARD_FLAG: {if(last_iccard_uid != "") {ViewInfo("uid: " + last_iccard_uid + "\r\n" + (String)msg.obj, null);}else {ViewInfo("",null);}break;}}if (err != "") {Snackbar.make(findViewById(R.id.fab), err, Snackbar.LENGTH_LONG).setAction("Action", null).show();}}};/*** 申请 USB OTG 阅读器访问权限* @param usbManager* @return*/public int UsbPermission(UsbManager usbManager) {//单独申请USB权限PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE);HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();for (UsbDevice usbDevice : deviceList.values()) {if( reader.CompareReaderID(usbDevice.getVendorId(),usbDevice.getProductId()) ) {if(!usbManager.hasPermission(usbDevice)) {usbManager.requestPermission(usbDevice, permissionIntent);}else {}Log.e("id_reader","Reader found!");break;}else {}Log.e("id_reader","Name: " + usbDevice.getManufacturerName() + " " + usbDevice.getProductName() + ", VID: " + usbDevice.getVendorId() + ",PID: " + usbDevice.getProductId());}return 0;}/*** 发送消息到 UI* @param str*/public void SendMsg(String str,int type) {Message msg = new Message();msg = new Message();if(mHandler != null) {msg.what = type;msg.obj = str;mHandler.sendMessage(msg);}}/*** 发送 OTG 阅读器连接或拔出的消息到 UI* @param samid*/public void SendDeviceMsg(String samid) {SendMsg(samid,SDK_DEVICE_FLAG);}/*** 发送身份证读卡结果消息到 UI* @param result 身份证读卡结果,JSON格式* @param type*/public void SendCardInfoMsg(String result,int type) {//tpnfc.SetLastRead(result);SendMsg(result,type);}/*** 判断 OTG 阅读器身份证读卡结果是否有变化,以决定是否需要发送消息到 UI* @param result* @return 返回身份证是否存在于OTG 阅读器*/public boolean OnIDCardResult(String result) {try {boolean cur_exist;JSONObject jsondata = new JSONObject(result);if(jsondata.getInt("ret") != 0 ) {if (jsondata.getInt("ret") == 2) {//阅读器设备状态改变,变为不存在,发送通知消息samid = "";SendDeviceMsg(samid);}last_idcard_text = "";cur_exist = false;}else {cur_exist = true;}if(jsondata.has("data")) {JSONObject data = jsondata.getJSONObject("data");if(data.has("text")) {String cur_text = data.getString("text");if (cur_text.compareTo(last_idcard_text) != 0) {//卡片信息发生改变,发送通知消息id_card_exist = true;last_idcard_text = cur_text;SendCardInfoMsg(result, SDK_READER_FLAG);return id_card_exist;}}}if(cur_exist != id_card_exist) {//卡片状态发生改变,发送通知消息id_card_exist = cur_exist;SendCardInfoMsg(result, SDK_READER_FLAG);return id_card_exist;}}catch (Exception e) {id_card_exist = false;}return id_card_exist;}/*** 判断 OTG Mifare one 读卡结果是否有变化,以决定是否需要发送消息到 UI* @param result* @return 返回Mifare one 卡是否存在*/public boolean OnICCardResult(String result) {try {JSONObject jsondata = new JSONObject(result);if(jsondata.getInt("ret") != 0 ) {if (jsondata.getInt("ret") == 2) {//阅读器设备状态改变,变为不存在,发送通知消息samid = "";SendDeviceMsg(samid);}last_iccard_text = "";last_iccard_sak = 0;}String cmd = jsondata.getString("function");if(jsondata.has("data")) {JSONObject data = jsondata.getJSONObject("data");if( cmd.compareTo("iso14443a_find") == 0) {//处理找卡结果JSONArray uid = data.getJSONArray("uid");if(uid.length()>0) {last_iccard_uid = uid.getJSONObject(0).getString("text");last_iccard_sak = uid.getJSONObject(0).getInt("sak");return true;}else {}}else if(cmd.compareTo("pboc_read") == 0 && data.has("number") ) {if(last_iccard_text.compareTo(data.getString("number")) !=0 ) {last_iccard_text = data.getString("number");String bankInfo = "银行卡号:"+data.getString("number") + "\r\n";bankInfo += "有效期截止:" + data.getString("expire") + "\r\n";bankInfo += "持卡人:" + data.getString("owner") + "\r\n";bankInfo += "持卡人证件号码:" + data.getString("owner_id") + "\r\n";SendCardInfoMsg(bankInfo, SDK_BANKCARD_FLAG);}return true;}else if( data.has("hex") ){//处理读到的数据if(last_iccard_text.compareTo(data.getString("hex")) !=0 ) {reader.WebSocketAPI("{\"module\":\"common\",\"msgid\":\"0\",\"function\":\"beep\",\"data\":{\"length\":200}}");last_iccard_text = data.getString("hex");SendCardInfoMsg(result, SDK_ICCARD_FLAG);}return true;}}if(last_iccard_text != "" || last_iccard_uid != "") {//卡片状态发生改变,发送通知消息last_iccard_uid = "";last_iccard_text = "";last_iccard_sak = 0;SendCardInfoMsg(result, SDK_ICCARD_FLAG);}return false;}catch (Exception e) {return false;}}/*** 清除读卡结果,并发送消息到 UI*/public void ClearReaderResult() {if( samid.compareTo("") != 0 ){samid = "";SendDeviceMsg(samid);}if(id_card_exist) {id_card_exist = false;SendCardInfoMsg("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\",\"errorMsg\":\"设备不存在\",\"ret\":2}", SDK_READER_FLAG);}last_idcard_text = "";}/*** 读取 OTG 阅读器的 SAM ID,并返回 OTG 阅读器是否存在* @return 返回 OTG 阅读器是否存在*/public boolean CheckSamID() {String result;JSONObject jsondata;try {if(samid == "" ) {result = reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"getsam\"}");jsondata = new JSONObject(result);if(jsondata.has("errorMsg") ) {if(jsondata.has("ret") && jsondata.getInt("ret") == 2) {//设备不存在}return false;}if(!jsondata.has("data") ) {return false;}JSONObject data = jsondata.getJSONObject("data");if(!data.has("samid") ) {return false;}samid = data.getString("samid");if(samid == "" ) {return false;}SendDeviceMsg(samid);}return true;}catch(Exception e) {return false;}}/*** 使用 OTG 阅读器读取身份证,处理读取结果并返回身份证是否存在* @return 返回身份证是否存在*/public boolean ReadIDCard() {try {if(!id_card_exist) {//还没有检测到卡片存在的情况下,可以先找卡和选卡。 这段代码不是必须,可以去掉,一样正常使用if( ! OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"findcard\"}") ) ){return false;}if( !OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"selectcard\"}") ) ) {return false;}}return OnIDCardResult( reader.WebSocketAPI("{\"module\":\"idcard\",\"msgid\":\"0\",\"function\":\"readcard\"}") );}catch(Exception e) {return false;}}/*** 使用 OTG 阅读器读取Mifare one卡* @return 返回Mifare one卡是否存在*/public boolean ReadICCard() {String cmd,pre_uid;if(id_card_exist) {//确认身份证卡片已存在的情况下,不读IC卡,避免冲突return false;}try {pre_uid = last_iccard_uid;if (!OnICCardResult(reader.WebSocketAPI("{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"iso14443a_find\"}"))) {return false;}if( last_iccard_uid.compareTo(pre_uid) == 0) {//卡没有发生变化,不重复读了return true;}if((last_iccard_sak & 0x20) == 0x20 ) {//构造读取银行卡号码的指令cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"pboc_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\"} }";}else {//构造读取 IC 卡的第 0 个Block 的指令int type = 0x60;  //密钥A:0x60 , 密钥B:0x61String key = "FFFFFFFFFFFF";int block = 0;cmd = "{\"module\":\"iccard\",\"msgid\":\"0\",\"function\":\"mifare_read\",\"data\": {\"uid\":\""+ last_iccard_uid + "\",\"block\":"+block+",\"type\":"+ type + ",\"key\":\""+key+"\"} }";}return OnICCardResult( reader.WebSocketAPI(cmd) );}catch(Exception e) {return false;}}/*** OTG 阅读器读取身份证信息线程*/Runnable runnable = new Runnable() {@Overridepublic void run() {while(true) {int  msgid = 0;try {if( reader.Connected(usbManager) ) {// 使用串口转网口模块时, reader.Connected(usbManager) 改为 true,直接 if(true) {if(!CheckSamID()) {Thread.sleep(1000);continue;}if( ReadIDCard() || ReadICCard()) {Thread.sleep(100);continue;}Thread.sleep(100);}else {ClearReaderResult();Thread.sleep(200);continue;}}catch (Exception e) {String error = e.toString();Log.e("id_reader",error);}}}};/***  感应到身份证时触发该事件。实现手机本机 NFC 读身份证。* @param intent*/@Overrideprotected void onNewIntent(Intent intent){super.onNewIntent(intent);setIntent(intent);Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);if(tag == null ) {return ;}//sendCardInfoMsg("{\"module\" : \"tpnfc\",\"function\" : \"card\", \"data\": {\"id\":\"" + byte2hex(tag.getId()) + "\"},\"ret\":0}",SDK_NFC_FLAG);NfcB card = NfcB.get(tag);if(card == null ) {return;}try {card.connect();String result = tpnfc.LocalNfcRead(card);card.close();JSONObject content = new JSONObject(result);if(content.has("errorMsg")) {String error = content.getString("errorMsg");String s = new String(error.getBytes("ISO-8859-1"), "UTF-8");String info = "\nerror: " + s + "\n";}SendCardInfoMsg(result,SDK_NFC_FLAG);}catch (java.io.IOException e){String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";SendCardInfoMsg(result,SDK_NFC_FLAG);}catch (Exception e){String result = "{\"module\" : \"idcard\",\"function\" : \"readcard\",\"errorMsg\":\"" + e.getMessage() + "\",\"errorNo\":34, \"server_error_code\": 0 ,\"server_error_string\": \"\"}";SendCardInfoMsg(result,SDK_NFC_FLAG);}}/*** 初始化手机本机 NFC 读身份证的相关变量和事件* @param path 提供可读写的路径,用于保存会话信息*/public void InitNfc(String path){TpNfc.Init(path);tpnfc = new TpNfc();mNfcAdapter = NfcAdapter.getDefaultAdapter(this);if (null == mNfcAdapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();TpNfc.nfc_support = 0;} else if (!mNfcAdapter.isEnabled()) {TpNfc.nfc_support = 0;Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);// 根据包名打开对应的设置界面startActivity(intent);}else {TpNfc.nfc_support = 1;}pIntent = PendingIntent.getActivity(this, 0,//在Manifest里或者这里设置当前activity启动模式,否则每次向阳NFC事件,activity会重复创建// 当然也要按照具体情况来,你设置成singleTask也不是不行,new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),PendingIntent.FLAG_MUTABLE);}/*** 初始化 OTG 阅读器相关的变量、事件、权限等等* @param path 提供可读写的路径,用于保存配置*/public void InitReader(String path){IDReader.ServiceStart(path);reader = new IDReader();usbManager = (UsbManager) getSystemService(Context.USB_SERVICE);UsbPermission(usbManager);new Thread(runnable).start();}/*** 修改手机本机 NFC 的相关设置*/@Overrideprotected void onResume() {super.onResume();if (mNfcAdapter != null) {//添加intent-filterIntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);IntentFilter tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);IntentFilter[] filters = new IntentFilter[]{ndef, tag, tech};String[][] techList = new String[][]{new String[]{"android.nfc.tech.Ndef","android.nfc.tech.NfcA","android.nfc.tech.NfcB","android.nfc.tech.NfcF","android.nfc.tech.NfcV","android.nfc.tech.NdefFormatable","android.nfc.tech.MifareClassic","android.nfc.tech.MifareUltralight","android.nfc.tech.NfcBarcode"}};mNfcAdapter.enableForegroundDispatch(this, pIntent, filters, techList);}}@Overrideprotected void onPause() {super.onPause();if (mNfcAdapter != null) {mNfcAdapter.disableForegroundDispatch(this);}}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);binding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(binding.getRoot());String path = getFilesDir().toString();InitNfc(path);InitReader(path);setSupportActionBar(binding.toolbar);NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);binding.fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {if(tpnfc == null ) {return ;}/*使用手机本机 NFC 阅读身份证时,需要先将手机与账号绑定。步骤如下:1. 官网注册账号2. 使用 tpnfc.SendBindRequest 向账号发送绑定请求3. 官网登录账号,接受绑定请求3. 调用 tpnfc.ClientInfo() 获取信息,判断是否绑定成功。4. 绑定成功功后,即可正常使用手机NFC读取身份证信息*/String info = "";String user = "18118742537"; //用户账号try {JSONObject jsondata = new JSONObject(tpnfc.ClientInfo());if (jsondata.has("secret") && jsondata.has("limit") && jsondata.has("expire")) {//已经绑定账号info = "NFC客户端\n有效期:" + jsondata.getString("expire") + "\n次数限制:" + jsondata.getInt("decode") + "/" + jsondata.getInt("limit");if(jsondata.getString("secret").compareTo("ok") != 0) {//客户端认证失败,需要解除绑定后,再重新绑定info += "\n密钥:密钥丢失,需要重新绑定";info += "\n解除绑定:" + ParseServerError(tpnfc.Unbind(jsondata.getString("id"), user)); //解除绑定}else {}} else {//还未绑定账号, 发送绑定请求, tpnfc.SendBindRequest 第一个参数为 客户端名称, 第二个参数是用户账号(手机号码)info += "发送绑定请求:";info += ParseServerError(tpnfc.SendBindRequest("测试NFC客户端", user));}}catch ( Exception e) {info = e.getMessage();}SendMsg(info,SDK_CLIENT_FLAG);}});}public String ParseServerError(String result) {String err = "";try {JSONObject ret = new JSONObject(result);if (ret.has("errorMsg")) {if (ret.getInt("errorNo") == 43) {err = "操作失败:" + ret.getString("server_error_string");} else {err = "操作失败:" + ret.getString("errorMsg");}} else {err = "操作成功!";}}catch (Exception e) {err = e.getMessage();}return err;}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {// Handle action bar item clicks here. The action bar will// automatically handle clicks on the Home/Up button, so long// as you specify a parent activity in AndroidManifest.xml.int id = item.getItemId();//noinspection SimplifiableIfStatementif (id == R.id.action_settings) {//测试重启服务reader.ServiceStop();reader.ServiceStart(getFilesDir().toString());return true;}return super.onOptionsItemSelected(item);}@Overridepublic boolean onSupportNavigateUp() {NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);return NavigationUI.navigateUp(navController, appBarConfiguration)|| super.onSupportNavigateUp();}}

六、C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace webapi_http
{public partial class Form1 : Form{public Form1(){InitializeComponent();}private void btReadCard_Click(object sender, EventArgs e){string result;string url = "http://127.0.0.1:7846/api/readCard?utf8=1";try{HttpWebRequest wbRequest = (HttpWebRequest)WebRequest.Create(url);wbRequest.Proxy = null;wbRequest.Method = "GET";HttpWebResponse wbResponse = (HttpWebResponse)wbRequest.GetResponse();using (Stream responseStream = wbResponse.GetResponseStream()){using (StreamReader sReader = new StreamReader(responseStream)){result = sReader.ReadToEnd();}}}catch (Exception ex){result = ex.Message;     //输出捕获到的异常,用OUT关键字输出}textResult.Text = result;}}
}

七、C

#include <stdio.h>
#include <sdtapi.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>#ifndef WIN32
#include <sys/time.h>
#include <sys/stat.h>
#include <dirent.h>void Sleep(unsigned int x)  
{ struct timespec xsleep; \xsleep.tv_sec = x / 1000; \xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \nanosleep(&xsleep, NULL); \
}
#else
#include <windows.h>
#include <winnls.h>#endif#include "bland.h"#ifndef WIN32
void print_com_list()//for linux
{struct dirent *pDirent;DIR *pDir;int i,index;struct stat st;char path[512] = {0};pDir = opendir("/sys/class/tty");if (pDir == NULL) {return ;}for (i=0,index=1;;i++) {pDirent = readdir(pDir);if(pDirent == NULL) {break;}snprintf(path,sizeof(path)-1,"/sys/class/tty/%s/device",pDirent->d_name);if (lstat(path, &st) < 0) {continue;}printf("COM%d: %s\n",index,path);index++;}closedir(pDir);
}//使用 UTF-8 字符编码
#define GetName			GetNameUtf8
#define GetGender		GetGenderUtf8
#define GetBirthday		GetBirthdayUtf8
#define GetAddress		GetAddressUtf8
#define GetRace			GetRaceUtf8
#define GetIDNum		GetIDNumUtf8
#define GetIssuer		GetIssuerUtf8
#define GetValidFrom	GetValidFromUtf8
#define GetExpireDate	GetExpireDateUtf8
#define GetPassNum		GetPassNumUtf8
#define GetIssueCount	GetIssueCountUtf8
#define GetNationCode	GetNationCodeUtf8
#define GetCnName		GetCnNameUtf8#endifvoid print_info2(char * text)
{char str[256] = {0};char str2[256] = {0};int ret,type;type = GetType(text);ret = GetName(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("name: %s\n",str);ret = GetGender(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("gender: %s\n",str);if(type == ' ') {//只有身份证有此项ret = GetRace(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("race: %s\n",str);}ret = GetBirthday(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("birthday: %s\n",str);if(type != 'I' && type != 'Y') {//外国人永久居留证没有此项ret = GetAddress(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("address: %s\n",str);}ret = GetIDNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("IDNum: %s\n",str);ret = GetIssuer(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("issuer: %s\n",str);ret = GetValidFrom(text,str,sizeof(str));if(ret < 0) {goto info_error;}ret = GetExpireDate(text,str2,sizeof(str2));if(ret < 0) {goto info_error;}printf("valid: %s-%s\n",str,str2);if(type == 'J') {ret = GetPassNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("passNum: %s\n",str);ret = GetIssueCount(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("IssueCount: %s\n",str);}else if(type == 'I' || type == 'Y') {ret = GetNationCode(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("nation: %s\n",str);ret = GetCnName(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("cnName: %s\n",str);if(type == 'I') {//2017版外国人永久居留证ret = GetCardVersion(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("version: %s\n",str);}else {ret = GetRelationalNum(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("relational number: %s\n",str);ret = GetRenewalCount(text,str,sizeof(str));if(ret < 0) {goto info_error;}printf("renewal count: %s\n",str);}}printf("\n");info_error:return ;
}unsigned int get_sector_num(unsigned int block_num)
{int sector;if (block_num < 128){sector = block_num / 4;}else{sector = ((block_num - 128) / 16) + 32;}return sector;
}#define MAX_UID_FIND	6//读取银行卡卡号等信息
int ReadBankCard(int iPort, ISO14443A_UID_T * card)
{int ret;char number[256] = {0};char info[sizeof(number)] = {0};ret = ReadPbocCardNumA(iPort,card->UID,card->UIDLen,number,info,sizeof(number));if(ret>0) {printf("Bank Card Number:\t%s\n",number);printf("Other Information:\t%s\n",info);return ret;}else {return -1;}
}//读取 Mifare IC卡
int ReadMifare(int iPort, ISO14443A_UID_T * card)
{int ret;unsigned int j,i;int max_block,sector;int type = 0x60; // 0x60 为密钥A 认证, 0x61 为密钥B认证unsigned char data[256][16] = {0};unsigned char key[6] = {0xff,0xff,0xff,0xff,0xff,0xff};//read card if(card->SAK == 0x18){max_block = 256;}else {max_block = 64;}for (i = 0, sector=-1 ;i< max_block;i++){if(get_sector_num(i) != sector ){//扇区发生变化,需要重新认证//需要先HALT一下卡片,必要的,但暂不清楚原因ISO14443A_Halt(iPort, 0);sector = get_sector_num(i);ret = MIFARE1_AuthBlock(iPort, card->UID, card->UIDLen, i, type, key, 0);if (ret != 0x90){printf("Mifare Auth block %d Failed!\n",i);return -1;}}ret = MIFARE1_ReadBlock(iPort, i, data[i], 0);if (ret != 0x90) {printf("Read block %d failed!\n",i);return -1;}}/* //write blockmemset(data,rand(),16);ISO14443A_Halt(iPort, 0);MIFARE1_AuthBlock(iPort, uid[0].UID, uid[0].UIDLen, 1, type, key, 0);ret = MIFARE1_WriteBlock(iPort,1,data,0);if(ret != 0x90) {printf("Write block 1 failed!\n");return -1;}*///for (i = 0;i< max_block && i<8;i++) //只显示一部分数据,否则内容太多刷屏了{for(j=0;j<16;j++) {if(j==8) {printf(" ");}printf("%02X ",data[i][j]);}printf("\n");}return max_block;
}static unsigned char passport_data[128*1024];
static unsigned char passport_photo[256*1024];void ReadPassport(int iPort,const char * pass_num, const char * birthday, const char * expire)
{int ret;FILE * fp;//读护照char auth[90] = {0};char MRZ[256];//生成认证码 authGetICAO9303AuthCode(pass_num,birthday,expire,auth);//读取护照ret = ReadICAO9303All(iPort,auth,passport_data,sizeof(passport_data));if(ret<=0) {return ;}ret = GetICAO9303MRZ(passport_data,MRZ,sizeof(MRZ));if(ret<0) {return ;}//读取护照/港澳通行证成功printf("MRZ: %s\n",MRZ);ret = GetICAO9303JpgData(passport_data,passport_photo,sizeof(passport_photo));if(ret>0) {fp = fopen("image.jpg","wb+");if(fp) {fwrite(passport_photo,1,ret,fp);fclose(fp);}}
}void ReadOtherCard(int iPort)
{int ret;unsigned int j,i,cnt = 0;ISO14443A_UID_T uid[MAX_UID_FIND];//find cardret = ISO14443A_FindCard(iPort,uid,MAX_UID_FIND,&cnt,0);if(ret != 0x90) {goto finished;}if(cnt <= 0) {goto finished;}for(i=0;i<cnt;i++) {	if(uid[i].SAK == 0x8) {printf("Mifare S50:\t");}else if(uid[i].SAK == 0x18) {printf("Mifare S70:\t");}else {printf("Unknow:\t");}for(j=0;j<uid[i].UIDLen;j++) {printf("%02X",uid[i].UID[j]);}printf("\n");}if(uid[0].SAK & 0x8) {//尝试作为 Mifare IC卡读取ret = ReadMifare(iPort,&uid[0]);if(ret>=0) {ISO14443A_Halt(iPort,0);SDT_ReaderBeep(iPort,100,0);Sleep(1000);}ISO14443A_ModeExit(iPort,0); //退出模式(短暂关闭天线),并Sleep一段时间,解决部分银行卡作为Mifare卡读过之后,就不能读取银行卡号的问题Sleep(200);}if(uid[0].SAK & 0x20) {//尝试作为银行卡读取ret = ReadBankCard(iPort,&uid[0]);if(ret>=0) {SDT_ReaderBeep(iPort,100,0);Sleep(1000);goto finished;}}if(uid[0].SAK & 0x20) {//尝试作为护照/港澳通行证读取ISO14443A_ModeExit(iPort,0);//  接口要求需要先退出type a模式Sleep(10);// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入// 所以此处传入的 "C06765690", "131116", "191125" 只是示例, 需要根据实际情况修改ReadPassport(iPort,"C06765690","131116","191125");}finished:// 从 ISO14443A 模式切回 ISO14443B模式(读取身份证模式),这样可以继续读取身份证,还起到了重置 ISO14443A 类型卡片的作用ISO14443A_ModeExit(iPort,0);Sleep(50);
}int main(int argc, char * argv[])
{int port = 1001;int ret;unsigned char ManaInfo[4];unsigned char ManaMsg[8];unsigned char text[256];unsigned char image[1024];unsigned char finger[1024];unsigned char AppInfo[1024];unsigned char bmp[65536];unsigned int textLen,imageLen,fingerLen,AppInfoLen;unsigned int ID[4];char str[1024];FILE * fp;if(argc > 1) {port = atoi(argv[1]);}
#ifndef WIN32print_com_list();
#endifwhile(1) {ret = SDT_GetSAMStatus(port,1);if(ret != 0x90 ) {Sleep(200);continue;}
/*SDT.ResetSAM(port,1);Sleep(1000);continue;
*/ret = SDT_OpenPort(port);if(ret != 0x90 ) {Sleep(200);continue;}printf("reader detected!\n");ret = SDT_GetSAMID(port,(unsigned char *)ID,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}ret = SDT_GetSAMID(port,(unsigned char *)ID,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}printf("SAMID: %02d.%02d-%08d-%010d-%010d\n",ID[0]&0xffff,ID[0]>>16,ID[1],ID[2],ID[3]);ret = SDT_GetSAMIDToStr(port,str,0);if(ret!= 0x90) {SDT_ClosePort(port);continue;}printf("SAMID: %s\n",str);while(1) {ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);if(ret == 0x90) {printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);goto success;}else if(ret < 0x21 ){break;}ret = SDT_StartFindIDCard(port,ManaInfo,0);if(ret == 0x9f) {printf("find card success!\n");}else  if(ret < 0x21 ){break;}else {//读取其他类型的卡片ReadOtherCard(port);Sleep(100);continue;}ret = SDT_SelectIDCard(port,ManaMsg,0);if(ret == 0x90) {printf("select card success!\n");}else  if(ret < 0x21 ){break;}else {printf("select failed!(ret=0x%02X)\n",ret);Sleep(1000);continue;}ret = SDT_ReadBaseFPMsg(port,text,&textLen,image,&imageLen,finger,&fingerLen,0);if(ret == 0x90) {printf("read card success!(%d,%d,%d)\n",textLen,imageLen,fingerLen);goto success;}else  if(ret < 0x21 ){break;}else  {printf("read card failed!(ret=0x%02X)\n",ret);// 读取护照的参数需要通过OCR文字识别,获得护照(或港澳通行证)的号码,生日,过期时间, 并作为参数传入// 所以此处传入的 "E18314949", "870623", "240615" 只是示例, 需要根据实际情况修改ReadPassport(port,"E18314949","870623","240615");//身份证读取失败了,尝试读取护照/港澳通行证Sleep(1000);continue;}success:AppInfoLen = 0;ret = SDT_ReadNewAppMsg(port,AppInfo,&AppInfoLen,0);if(ret == 0x90){printf("read address success!(%d)\n",AppInfoLen);}else {printf("no address!(0x%x)\n",ret);}ret = SDT_ReadBaseFPMsgToFile(port,"text.txt",&textLen,"image.wlt",&imageLen,"finger.bin",&fingerLen,0);print_info2((char*)text);ret = GetBmpData(image,bmp,sizeof(bmp));if(ret > 0 ) {fp = fopen("image.bmp","wb+");if(fp) {fwrite(bmp,1,ret,fp);fclose(fp);}}Sleep(1000);}printf("reader removed!\n");SDT_ClosePort(port);}return 0;
}

八、Delphi

object Form1: TForm1Left = 212Top = 147Width = 1740Height = 900Caption = #27493#32852#31185#25216' '#36523#20221#35777#38405#35835#28436#31034#31243#24207Color = clBtnFaceFont.Charset = DEFAULT_CHARSETFont.Color = clWindowTextFont.Height = -13Font.Name = 'MS Sans Serif'Font.Style = []OldCreateOrder = FalseOnCreate = OnCreatePixelsPerInch = 120TextHeight = 16object Label1: TLabelLeft = 16Top = 32Width = 48Height = 16Caption = #31471#21475#21495#65306endobject Label2: TLabelLeft = 16Top = 136Width = 36Height = 16Caption = #22995#21517#65306endobject Label3: TLabelLeft = 16Top = 176Width = 36Height = 16Caption = #24615#21035#65306endobject Label4: TLabelLeft = 184Top = 176Width = 36Height = 16Caption = #27665#26063#65306endobject Label5: TLabelLeft = 16Top = 208Width = 60Height = 16Caption = #20986#29983#26085#26399#65306endobject Label6: TLabelLeft = 16Top = 240Width = 36Height = 16Caption = #20303#22336#65306endobject Label7: TLabelLeft = 16Top = 328Width = 72Height = 16Caption = #36523#20221#35777#21495#30721#65306endobject Label8: TLabelLeft = 16Top = 368Width = 60Height = 16Caption = #31614#21457#26426#20851#65306endobject Label9: TLabelLeft = 16Top = 400Width = 60Height = 16Caption = #26377#25928#26399#38480#65306endobject Label10: TLabelLeft = 16Top = 72Width = 54Height = 16Caption = 'SAMID'#65306endobject Label11: TLabelLeft = 16Top = 104Width = 60Height = 16Caption = #21345#29255#24207#21495#65306endobject Image1: TImageLeft = 296Top = 104Width = 105Height = 105endobject txtName: TEditLeft = 136Top = 136Width = 137Height = 24ReadOnly = TrueTabOrder = 0endobject txtGender: TEditLeft = 136Top = 168Width = 41Height = 24ReadOnly = TrueTabOrder = 1endobject btRead: TButtonLeft = 392Top = 32Width = 75Height = 25Caption = #35835#21345TabOrder = 2OnClick = btReadClickendobject btOpen: TButtonLeft = 280Top = 32Width = 97Height = 25Caption = #25171#24320#31471#21475TabOrder = 3OnClick = btOpenClickendobject cbPort: TComboBoxLeft = 136Top = 32Width = 129Height = 24ItemHeight = 16TabOrder = 4Text = '0'endobject txtBirthday: TEditLeft = 136Top = 200Width = 137Height = 24ReadOnly = TrueTabOrder = 5endobject txtAddress: TEditLeft = 136Top = 232Width = 209Height = 24ReadOnly = TrueTabOrder = 6endobject txtNumber: TEditLeft = 136Top = 328Width = 209Height = 24ReadOnly = TrueTabOrder = 7endobject txtIssuer: TEditLeft = 136Top = 360Width = 209Height = 24ReadOnly = TrueTabOrder = 8endobject txtValid: TEditLeft = 136Top = 392Width = 209Height = 24ReadOnly = TrueTabOrder = 9endobject txtSAMID: TEditLeft = 136Top = 64Width = 241Height = 24ReadOnly = TrueTabOrder = 10endobject StatusBar1: TStatusBarLeft = 0Top = 834Width = 1722Height = 19Panels = <itemWidth = 250enditemWidth = 450end>endobject txtRace: TEditLeft = 232Top = 168Width = 41Height = 24ReadOnly = TrueTabOrder = 12endobject txtCardSn: TEditLeft = 136Top = 104Width = 137Height = 24ReadOnly = TrueTabOrder = 13end
end

九、阿雪技术观


拥抱开源与共享,见证科技进步奇迹,畅享人类幸福时光!

让我们积极投身于技术共享的浪潮中,不仅仅是作为受益者,更要成为贡献者。无论是分享自己的代码、撰写技术博客,还是参与开源项目的维护和改进,每一个小小的举动都可能成为推动技术进步的巨大力量

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/433830.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NSSCTF [HUBUCTF 2022 新生赛]simple_RE(变种base64编码)

文件无壳 拖入IDA中 shiftF12查看可疑字符串 发现两串字符串 一看这两个等于号就猜测是base64编码 进入主函数看看 这段代码是一个简单的 C 语言程序&#xff0c;主要功能是接受用户输入的字符串作为“flag”&#xff0c;然后通过对输入的字符串进行一些处理和比较来验证是否输…

深圳龙链科技:全球区块链开发先锋,领航Web3生态未来

【深圳龙链科技】是全球领先的Web3区块链技术开发公司&#xff0c;专注于为全球客户提供创新高效的区块链解决方案。 深圳龙链科技由币安资深股东携手香港领先的Web3创新枢纽Cyberport联袂打造&#xff0c;立足于香港这一国际金融中心&#xff0c;放眼全球&#xff0c;汇聚了华…

Python获取百度翻译的两种方法

一、引言 百度是我们常用的搜索工具&#xff0c;其翻译是与爱词霸合作&#xff0c;总体看其反应速度较快&#xff0c;可以作为项目中重要的翻译工具。根据大家的需要&#xff0c;现提供两种Python获取百度翻译的两种办法&#xff1a; 二、requests法 我们引用requests模块&a…

智能Ai语音机器人的应用价值有哪些?

随着时间的推移&#xff0c;人工智能的发展越来越成熟&#xff0c;智能时代也离人们越来越近&#xff0c;近几年人工智能越来越火爆&#xff0c;人工智能的应用已经开始渗透到各行各业&#xff0c;与生活交融&#xff0c;成为人们无法拒绝&#xff0c;无法失去的一个重要存在。…

SQL进阶技巧:如何获取状态一致的分组? | 最大、最小值法

目录 0 需求描述 1 数据准备 2 问题分析 方法1&#xff1a;最大、最小值法&#xff08;技巧&#xff09; 方法2&#xff1a;常规思路 3 小结 如果觉得本文对你有帮助&#xff0c;那么不妨也可以选择去看看我的博客专栏 &#xff0c;部分内容如下&#xff1a; 数字化建设通…

Trie树之字符串统计问题

这是C算法基础-数据结构专栏的第二十七篇文章&#xff0c;专栏详情请见此处。 引入 Trie树&#xff0c;即字典树&#xff0c;顾名思义&#xff0c;就是用类似字典的方式存储数据&#xff0c;而Trie树最经典也是最简单的一个应用就是字符串统计问题。 字符串统计问题就是维护一个…

【微服务即时通讯系统】——etcd一致性键值存储系统、etcd的介绍、etcd的安装、etcd使用和功能测试

文章目录 etcd1. etcd的介绍1.1 etcd的概念 2. etcd的安装2.1 安装etcd2.2 安装etcd客户端C/C开发库 3. etcd使用3.1 etcd接口介绍 4. etcd使用测试4.1 原生接口使用测试4.2 封装etcd使用测试 etcd 1. etcd的介绍 1.1 etcd的概念 Etcd 是一个基于GO实现的 分布式、高可用、一致…

分库分表还是分布式?如何用 OceanBase的单机分布式一体化从根本上解决问题

随着企业业务规模的不断增长&#xff0c;单机集中式的数据库系统逐渐难以承载企业日益增长的数据存储与处理需求。因此&#xff0c;MySQL 的分库分表方案成为了众多企业应对数据存储量激增及数据处理能力需求扩张的“止痛药”。尽管这一方案短期内有效缓解了企业面临的大规模数…

在新ARM板上移植U-Boot和Linux指南

序言 从支持一个定制板子在U-Boot和Linux中的过程中得到经验以一个带有知名SoC&#xff08;i.MX6&#xff09;且IP已经得到支持的板子为例&#xff0c;这次讨论几乎不涉及编码技能&#xff0c;更多地聚焦在U-Boot部分 一般原则 如果您有您的BSP&#xff08;板级支持包&#…

【全新课程】正点原子《基于GD32 ARM32单片机项目实战入门》培训课程上线!

正点原子《基于GD32 ARM32单片机项目实战入门》全新培训课程上线啦&#xff01;正点原子工程师手把手教你学&#xff01;彻底解决ARM32单片机项目入门难的问题&#xff01; 一、课程介绍 本课程专为ARM32单片机的入门学习者设计&#xff0c;涵盖了环境搭建、编程软件使用、模…

【数学分析笔记】第3章第4节闭区间上的连续函数(2)

3. 函数极限与连续函数 3.4 闭区间上的连续函数 3.4.4 中间值定理 【定理3.4.4】若 f ( x ) f(x) f(x)在 [ a , b ] [a,b] [a,b]上连续&#xff0c;则它一定能取到最大值 M M M与最小值 m m m之间的任何一个值。 M max ⁡ f ( x ) , x ∈ [ a , b ] , m min ⁡ f ( x ) , …

【前端框架对比和选择】React 与 Vue 框架设计思路对比

框架总览 前端框架繁多&#xff0c;在学习的时候也会陷入困惑&#xff0c;我们应该抓住最主流的内容 Vue/React&#xff0c;深入底层&#xff0c;尝试揣摩框架作者的设计思路&#xff0c;开阔前端培训自己的视野&#xff0c;大家也不要把自己限制在框架之中&#xff0c;认为工…

常见区块链数据模型介绍

除了加密技术和共识算法&#xff0c;区块链技术还依赖于一种数据模型&#xff0c;它决定了信息如何被结构化、验证和存储。数据模型定义了账户如何管理&#xff0c;状态转换如何发生&#xff0c;以及用户和开发者如何与系统交互。 在区块链技术的短暂历史中&#xff0c;数据…

数据治理005-血缘关系

数据血缘是元数据产品的核心能力&#xff0c;但数据血缘是典型的看起来很美好但用起来门槛很高的技术&#xff0c;只要你采买过元数据产品就知道了。这篇文章对数据血缘的特征、价值、用途和方法做了系统阐述&#xff1a; 1、特征&#xff1a;归属性、多源性、可追溯及层次性 2…

SAP已知事务码查询关联角色

运维期间客户就出现没有某些事务码的权限&#xff0c;要求添加&#xff1b; 想要添加事务码就必须知道这个事务码属于哪个角色&#xff1b;使用SUIM-角色-按菜单中的事务分配&#xff0c;输入事务码&#xff0c;点击执行就可以查看 找到相关的角色之后&#xff0c;用SU01添加至…

动态规划算法:12.简单多状态 dp 问题_打家劫舍_C++

目录 题目链接&#xff1a;LCR 089. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 一、题目解析 题目&#xff1a; 解析&#xff1a; 二、算法原理 1、状态表示 状态表示&#xff1a; 2、状态转移方程 状态转移方程推理&#xff1a; 3、初始化 dp表初始化: 特殊…

【抓包工具】如何下载抓包工具Fiddler

目录 Fiddler简介 Fiddler下载步骤 Fiddler安装步骤 配置Fiddler抓取HTTPS Fiddler简介 Fiddler是一个http协议调试代理工具&#xff0c;它能够记录并检查所有你的电脑和互联网之间的http通讯&#xff0c;设置断点&#xff0c;查看所有的“进出”Fiddler的数据&#xff08…

【BurpSuite】SQL注入 | SQL injection(1-2)

&#x1f3d8;️个人主页&#xff1a; 点燃银河尽头的篝火(●’◡’●) 如果文章有帮到你的话记得点赞&#x1f44d;收藏&#x1f497;支持一下哦 【BurpSuite】SQL注入 | SQL injection&#xff08;1-2&#xff09; 实验一 Lab: SQL injection vulnerability in WHERE clause…

大数据新视界 --大数据大厂之数据压缩算法比较与应用:节省存储空间

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

2-105 基于matlab的GA-WNN预测算法

基于matlab的GA-WNN预测算法。遗传算法优化小波神经网络的步骤&#xff1a;1设种群规模为M。随机生成初始种群N , 采用实数编码对个体Ni编码。2、用1中的种群N训练, WNN参数由初始化获得。3、计算种群N中个体适应度值。满足终止条件则跳至6, 不满足执行4。4、适应度大的个体, 选…