diff --git a/src/main/java/com/dpkj/modules/cardReader/constant/StatusConstant.java b/src/main/java/com/dpkj/modules/cardReader/constant/StatusConstant.java new file mode 100644 index 0000000..97baab7 --- /dev/null +++ b/src/main/java/com/dpkj/modules/cardReader/constant/StatusConstant.java @@ -0,0 +1,69 @@ +package com.dpkj.modules.cardReader.constant; + +public interface StatusConstant { + // 执行成功 + String IFD_OK = "0"; + + // 卡片类型不对 + String IFD_ICC_TypeError = "-1"; + + // 无卡 + String IFD_ICC_NoExist = "-2"; + + // 有卡未上电 + String IFD_ICC_NoPower = "-3"; + + // 卡片无应答 + String IFD_ICC_NoResponse = "-4"; + + // 卡片状态异常 + String IFD_ICC_StatusErr = "-5"; + + // 读写器执行指令失败 + String IFD_ICC_ExecuteErr = "-6"; + + // 读卡器连接错 + String IFD_ConnectError = "-11"; + + // 未建立连接(没有执行打开设备函数) + String IFD_UnConnected = "-12"; + + // (动态库)不支持该命令 + String IFD_BadCommand = "-13"; + + // (发给动态库的)命令参数出错 + String IFD_ParameterError = "-14"; + + // 信息校验和出错 + String IFD_CheckSumError = "-15"; + + // 超时 + String IFD_TimeOut = "-16"; + + // 读取固件信息错误 + String IFD_ReadErr = "-17"; + + // 底层返回数据长度错误 + String IFD_DeviceDataLen = "-18"; + + // 卡片数据异常错误 + String IFD_CardDataErr = "-19"; + + // 标志位不支持 + String IFD_TAGNoExist = "-20"; + + // 读取文件异常 + String IFD_FileDataErr = "-21"; + + // 设备返回数据异常 + String IFD_DeviceDataErr = "-22"; + + // 加载动态库失败 + String IFD_LoadDllError = "-23"; + + // 用户取消操作 + String IFD_UserCancel = "-24"; + + // 密码长度错误 + String IFD_KeyLengthErr = "-25"; +} diff --git a/src/main/java/com/dpkj/modules/cardReader/controller/CardReaderController.java b/src/main/java/com/dpkj/modules/cardReader/controller/CardReaderController.java new file mode 100644 index 0000000..3619a3b --- /dev/null +++ b/src/main/java/com/dpkj/modules/cardReader/controller/CardReaderController.java @@ -0,0 +1,37 @@ +package com.dpkj.modules.cardReader.controller; + +import com.dpkj.common.vo.Result; +import com.dpkj.modules.cardReader.service.CardReaderService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +/** + * 多合一读卡器 + */ +@Slf4j +@RestController +@RequestMapping("cardReader") +public class CardReaderController { + @Autowired + private CardReaderService cardReaderService; + + /** + * 连接设备 + * @return + */ + @GetMapping("connectedDevice") + public Result connectedDevice(@RequestParam(name = "devName") String devName) { + try { + return cardReaderService.connectedDevice(devName); + } catch (Exception e) { + e.printStackTrace(); + log.info("设备连接失败 {}", e.getMessage()); + return Result.error("设备连接失败"); + } + } + +} diff --git a/src/main/java/com/dpkj/modules/cardReader/service/CardReaderService.java b/src/main/java/com/dpkj/modules/cardReader/service/CardReaderService.java new file mode 100644 index 0000000..b3ea291 --- /dev/null +++ b/src/main/java/com/dpkj/modules/cardReader/service/CardReaderService.java @@ -0,0 +1,9 @@ +package com.dpkj.modules.cardReader.service; + + +import com.dpkj.common.vo.Result; + +public interface CardReaderService { + + Result connectedDevice(String devName); +} diff --git a/src/main/java/com/dpkj/modules/cardReader/service/impl/CardReaderServiceImpl.java b/src/main/java/com/dpkj/modules/cardReader/service/impl/CardReaderServiceImpl.java new file mode 100644 index 0000000..8f3bbd1 --- /dev/null +++ b/src/main/java/com/dpkj/modules/cardReader/service/impl/CardReaderServiceImpl.java @@ -0,0 +1,25 @@ +package com.dpkj.modules.cardReader.service.impl; + +import com.dpkj.common.vo.Result; +import com.dpkj.modules.cardReader.service.CardReaderService; +import com.dpkj.modules.cardReader.utils.CardReaderUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +@Slf4j +@Service +public class CardReaderServiceImpl implements CardReaderService { + + private CardReaderUtil.CardReaderSdk cardReaderSdk = CardReaderUtil.getCardReaderSDK(); + + public CardReaderServiceImpl() throws CardReaderUtil.CardReaderRegistrationException { + } + + @Override + public Result connectedDevice(String devName) { + Long aLong = cardReaderSdk.ICCReaderOpen(devName); + log.info("连接状态{}", aLong); + return Result.ok(aLong); + } +} diff --git a/src/main/java/com/dpkj/modules/cardReader/utils/CardReaderUtil.java b/src/main/java/com/dpkj/modules/cardReader/utils/CardReaderUtil.java new file mode 100644 index 0000000..f6ae139 --- /dev/null +++ b/src/main/java/com/dpkj/modules/cardReader/utils/CardReaderUtil.java @@ -0,0 +1,412 @@ +package com.dpkj.modules.cardReader.utils; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class CardReaderUtil { + + /** + * 获取 多合一读卡器 实例,同时注册 CardReaderSdk 控件。 + * + * @return CardReaderSdk 实例 + * @throws CardReaderRegistrationException 如果注册控件失败,抛出此异常 + */ + public static CardReaderSdk getCardReaderSDK() throws CardReaderRegistrationException { + try { + return Native.load("UnPack", CardReaderSdk.class); + } catch (UnsatisfiedLinkError e) { + log.info("[CardReader][CardReaderUtil.getCardReaderSDK] SDK注册失败 {}", e.getMessage()); + throw new CardReaderRegistrationException("Failed to load CardReaderSdk library: ", e); + } + } + + public static void convertAndPassStringAsJCharArray(String filePath) { + // 将字符串转换为char[] + char[] chars = filePath.toCharArray(); + } + + /** + * 定义接口映射本地库中的函数。 + */ + public interface CardReaderSdk extends Library { + /** + * 连接指定设备与电脑端口,即打开端口 + * @param devName 接口名称,如”USB1” + * @return >0成功,<=0失败 + */ + Long ICCReaderOpen(String devName); + + + + /** + * 关闭已打开的电脑接口 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return =0成功,非0失败 + */ + Long ICCReaderClose(Long ReaderHandle); + + + /** + * 读写器产生蜂鸣 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param time 蜂鸣时间,以毫秒为单位 + * @return =0成功,非0失败 + */ + Long ICCPosBeep(Long ReaderHandle, Long time); + + + /** + * 获取动态库及设备版本信息 + * @return 设备及动态库版本信息 =0成功,非0失败 + */ + Long ICCReaderLibinfo(); + + + /** + * 从EEPROM读取数据 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param offset 偏移地址(起始地址) + * @param length 要读取的数据的长度 + * @return 读取的数据 =0成功,非0失败 + */ + Long ICCReaderReadEEPROM(Long ReaderHandle, int offset, int length); + + + /** + * 往EEPROM写入数据 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param offset 偏移地址(起始地址) + * @param length 要写入的数据的长度 + * @param buffer 待写入的数据 + * @return =0成功,非0失败 + */ + Long ICCReaderWriteEEPROM(Long ReaderHandle, int offset, int length, String buffer); + + + /** + * 播放语音 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param voiceType 语音类型: + * 1、请插卡 + * 2、请刷卡 + * 3、读卡错误 + * 4、请输入密码 + * 5、密码错误 + * 6、操作成功 + * 7、操作超时 + * 8、操作失败 + * 9、请取回卡 + * 10、请重新输入密码 + * 11、请再次输入密码 + * 12、请输入新密码 + * 13、请输入旧密码 + * 14、请确认新密码 + * @return =0成功,非0失败 + */ + Long WINAPIICCReaderDispSound(Long ReaderHandle, String voiceType); + + + /** + * 接触 CPU 卡上电复位,返回值数据格式为十六进制字符串 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param ICCSlotNo ICC插槽号 0x01 :大卡座 ; + * 0x02 :副卡座 ; + * 0x11:SAM1卡座; + * 0x12:SAM2卡座; + * 0x13:SAM3卡座; + * 0x14:SAM4卡座 + * 0x3x:非接CPU卡 + * @return 上电返回ATR值,数据格式为十六进制字符串 + */ + Long ICCReaderPowerOnHEX(Long ReaderHandle, String ICCSlotNo); + + + /** + * CPU 卡下电 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param ICCSlotNo ICC插槽号 0x01 :大卡座 ; + * 0x02 :副卡座 ; + * 0x11:SAM1卡座; + * 0x12:SAM2卡座; + * 0x13:SAM3卡座; + * 0x14:SAM4卡座 + * 0x3x:非接CPU卡 + * @return =0成功,非0失败 + */ + Long ICCReaderPowerOff(Long ReaderHandle, String ICCSlotNo); + + + /** + * 获取卡座状态 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param ICCSlotNo ICC插槽号 0x01 :大卡座 ; + * 0x02 :副卡座 ; + * 0x11:SAM1卡座; + * 0x12:SAM2卡座; + * 0x13:SAM3卡座; + * 0x14:SAM4卡座 + * 0x3x:非接CPU卡 + * @return = 0 表示卡座有卡,其他见状态码 + */ + Long ICCReaderGetStatus(Long ReaderHandle, String ICCSlotNo); + + + /** + * 接触 CPU 卡执行APDU命令 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param ICCSlotNo ICC插槽号 0x01 :大卡座 ; + * 0x02 :副卡座 ; + * 0x11:SAM1卡座; + * 0x12:SAM2卡座; + * 0x13:SAM3卡座; + * 0x14:SAM4卡座 + * 0x3x:非接CPU卡 + * @param CommandAPDU APDU命令数据,以十六进制字符串形式输入 + * @return 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败 + */ + Long ICCReaderApplicationHEX(Long ReaderHandle, String ICCSlotNo, String CommandAPDU); + + + /** + * 4442卡片上电,数据以十六进制字符串输出 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return 返回卡片上电信息 = 0 表示成功,非0失败 + */ + Long ICCReader4442PowerOnHEX(Long ReaderHandle); + + + /** + * 4442卡片下电 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return = 0 表示成功,非0失败 + */ + Long ICCReader4442PowerOff(Long ReaderHandle); + + + /** + * 读取4442卡的指定字段内容,以十六进制字符串输出 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param offset 起始地址,需小于256 + * @param len 数据长度,offset+len需小于256 + * @return 返回卡片读取信息 = 0 表示成功,非0失败 + */ + Long ICCReader4442ReadHEX(Long ReaderHandle, int offset, int len); + + + /** + * 写 4442 卡的指定字段内容,以十六进制字符串输入参数 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param offset 起始地址,需小于256 + * @param len 数据长度,offset+len需小于256 + * @param data 待写入卡片数据 + * @return 返回卡片读取信息 = 0 表示成功,非0失败 + */ + Long ICCReader4442WriteHEX(Long ReaderHandle, int offset, int len, String data); + + + /** + * 4442卡认证密钥 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param keyHex 卡密钥 + * @return = 0 表示成功,非0失败 + */ + Long ICCReader4442Verify(Long ReaderHandle, String keyHex); + + /** ----- 非接触操作函数 -------------- */ + /** + * 查找天线磁场区域内有无卡,只有卡片上电后才能查找到 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return = 0 表示成功,非0失败 + */ + Long PICCReaderRequest(Long ReaderHandle); + + + /** + * 天线操作 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param flag 00-关场强 01-开场强 + * @return = 0 表示成功,非0失败 + */ + Long PICCReaderRFControl(Long ReaderHandle, String flag); + + + /** --------------- 非接 CPU 卡操作函数 ------------ */ + /** + * 非接TypeA CPU卡上电复位,输出十六进制字符串 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度,大于0 表示成功,其他失败 + */ + Long PICCReaderPowerOnTypeAHEX(Long ReaderHandle); + + + /** + * 非接TypeB CPU卡上电复位,输出十六进制字符串 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度,大于0 表示成功,其他失败 + */ + Long PICCReaderPowerOnTypeBHEX(Long ReaderHandle); + + /** + * 非接触 CPU 卡执行APDU命令,命令以十六进制字符串传输 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @param CommandAPDU APDU命令数据,以十六进制字符串形式输入 + * @return APDU命令执行后,响应的数据,返回数据为十六进制字符串 + * 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败 + */ + Long PICCReaderApplicationHEX(Long ReaderHandle, String CommandAPDU); + + + /** ---------------- 二代证/外国人居留证/港澳台居住证 --------------- */ + /** + * 读取身份证物理ID号 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return 返回身份证物理ID信息 = 0 表示成功,非0失败 + */ + Long PICCReaderReadCardID(Long ReaderHandle); + + + /** + * 读取身份证物理ID号 + * @param ReaderHandle ICCReaderOpen函数所返回的值 + * @return 返回错误信息 = 0 表示成功,非0失败 + */ + Long PICCReaderReadIDCard(Long ReaderHandle); + + /** 以下函数须在 “PICCReaderReadIDCard” 函数执行成功之后调用,否则获取不到有效信息 */ + /** + * 获取证件类型 + * @return + * 0:居民身份证 + * 1:外国人永久居留证 + * 2:港澳台居民居住证 + * 4:新外国人永久居留证 + */ + Integer GetCardType(); + + /** + * 姓名(类型为 1 时表示:外国人中文姓名) + */ + Integer GetName(); + + /** + * 性别 + */ + Integer GetSex(); + /** + * 民族 + */ + Integer GetNation(); + /** + * 出生日期 + */ + Integer GetBirth(); + /** + * 住址 + */ + Integer GetAddress(); + /** + * 公民身份证号码(类型为 1时表示:外国人居留证号码) + */ + Integer GetCertNo(); + /** + * 签发机关 + */ + Integer GetDepartemt(); + /** + * 有效起始日期 + */ + Integer GetEffectDate(); + /** + * 有效截止日期 + */ + Integer GetExpireDate(); + /** + * bmp 格式照片数据 + */ + Integer GetBmpFileData(); + /** + * 生成照片 + * TODO 入参参考文中3.4.1 + */ + Integer GetBmpFile(); + /** + * 是否含存在指纹信息:存在时返回 512 或者 1024 + * 不存在时返回 0 + */ + Integer IsFingerExist(); + /** + * 获取指纹数据:成功时返回获取到的字节长度 + */ + Integer GetFingerprint(); + /** + * 外国人英文姓名 + */ + Integer GetEnName(); + /** + * 外国人国籍代码,符合GB/T2659-2000规定 + */ + Integer GetNationalityCode(); + /** + * 港澳台通行证号码 + */ + Integer GetTXZHM(); + /** + * 港澳台通行证签发次数 + */ + Integer GetTXZQFCS(); + /** + * 外国人换证次数 + */ + Integer GetHZCS(); + + /** ------------ 社保卡 ---------*/ + /** + * 选择社保卡社会保障系统环境后,通过 PSAM 卡对社保卡进行内部认证,通过后将卡内的基本信息读出返回。 + * @param iType 操作卡的类型 + * 1-接触式操作卡; + * 2-非接触式操作卡; + * 3-自动寻卡,接触式操作卡优先; + * 4-自动寻卡,非接触式操作卡优先 + * @return + */ + Long iReadCardBas(Integer iType); + + /** + * 基于加密机的读基本信息(步骤一) + * 选择社会保障系统环境后,返回内部认证和外部认证所需信息。 + * @param iType 操作卡的类型 + * 1-接触式操作卡; + * 2-非接触式操作卡; + * 3-自动寻卡,接触式操作卡优先; + * 4-自动寻卡,非接触式操作卡优先 + * @return + */ + Long iReadCardBasHSMStep1(Integer iType); + + /** + * 基于加密机的读基本信息(步骤二) + * 根据加密机返回的内部认证和外部认证结果数据对社保卡进行内部认证和外部认证,通过后将卡内的基本信息读出返回。 + * @param pKey 加密机返回的内部认证和外部认证结果数据,依次为:内部认证结果数据 + * (即内部认证鉴别数据(16 位)和内部认证鉴别所需的原始信息(16 位)拼接组 + * 成)、外部认证结果数据(即外部认证鉴别数据(16 位)和外部认证鉴别所需的 + * 原始信息(16 位)拼接组成)。各数据项之间以“|”分割,且最后一个数据项以“|”结尾。 + * @return + */ + Long iReadCardBasHSMStep2(String pKey); + } + + /** + * 定义自定义异常类,用于表示注册控件时发生的错误 + */ + public static class CardReaderRegistrationException extends Exception { + public CardReaderRegistrationException(String message) { + super(message); + } + + public CardReaderRegistrationException(String message, Throwable cause) { + super(message, cause); + } + } +} diff --git a/src/main/resources/win32-x86-64/SSSE32.dll b/src/main/resources/win32-x86-64/SSSE32.dll new file mode 100644 index 0000000..70f4dfa Binary files /dev/null and b/src/main/resources/win32-x86-64/SSSE32.dll differ diff --git a/src/main/resources/win32-x86-64/UnPack.dll b/src/main/resources/win32-x86-64/UnPack.dll new file mode 100644 index 0000000..2dc0943 Binary files /dev/null and b/src/main/resources/win32-x86-64/UnPack.dll differ