身份证读取(完成)、社保卡读取(待调试)

This commit is contained in:
王志成 2025-02-17 16:58:54 +08:00
parent 6ca1cdce4b
commit 47c9d8dc5a
30 changed files with 7692 additions and 1498 deletions

View File

@ -1,89 +0,0 @@
package com.dpkj.modules.autoReplyPrint.base;
import com.dpkj.common.exception.RRException;
import com.dpkj.modules.autoReplyPrint.utils.AutoReplyPrint;
import com.dpkj.modules.autoReplyPrint.utils.ImageUtils;
import com.sun.jna.Pointer;
import org.springframework.web.multipart.MultipartFile;
/**
* 图片打印基础实现
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 14:37:23
*/
public abstract class BaseImagePrint {
/**
* 必须要实现这个获取句柄
* @param devName 设备名称/串口名称
* @return 窗口句柄
*/
public abstract Pointer getHandle(String devName);
public void printFromPath(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
Pointer handle = getHandle(devName);
try {
// 开始打印图片
boolean printTag = AutoReplyPrint.INSTANCE.CP_Pos_PrintRasterImageFromFile(handle, dstw, dsth, pszFile, binaryzation_method, compression_method);
if( !printTag ){
throw new RRException("打印图片失败");
}
// 切纸
AutoReplyPrint.INSTANCE.CP_BlackMark_SetBlackMarkPaperCutPosition(handle, 0);
boolean cutPaper = AutoReplyPrint.INSTANCE.CP_Pos_FeedAndHalfCutPaper(handle);
if ( !cutPaper){
throw new RRException("图片裁剪失败,请自行裁剪");
}
}catch (Exception e){
e.printStackTrace();
throw new RRException(e);
}finally {
if ( handle != null) AutoReplyPrint.INSTANCE.CP_Port_Close(handle);
}
}
public void printFromPathData(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
// 获取图片
byte[] data = ImageUtils.imageToBytes(pszFile);
this.printFromData(devName, dstw, dsth, data, binaryzation_method, compression_method);
}
public void printFromData(String devName, int dstw, int dsth, byte[] data, int binaryzation_method, int compression_method) {
Pointer handle = getHandle(devName);
try {
// 开始打印图片
boolean printTag = AutoReplyPrint.INSTANCE.CP_Pos_PrintRasterImageFromData(handle, dstw, dsth, data, data.length, binaryzation_method, compression_method);
if( !printTag ){
throw new RRException("打印图片失败");
}
// 切纸
AutoReplyPrint.INSTANCE.CP_BlackMark_SetBlackMarkPaperCutPosition(handle, 0);
boolean cutPaper = AutoReplyPrint.INSTANCE.CP_Pos_FeedAndHalfCutPaper(handle);
if ( !cutPaper){
throw new RRException("图片裁剪失败,请自行裁剪");
}
}catch (Exception e){
e.printStackTrace();
throw new RRException(e);
}finally {
if ( handle != null) AutoReplyPrint.INSTANCE.CP_Port_Close(handle);
}
}
public void printFromMultipartFile(String devName, int dstw, int dsth, MultipartFile file, int binaryzation_method, int compression_method){
byte[] data = ImageUtils.getByteToMultipartFile(file);
this.printFromData(devName, dstw, dsth, data, binaryzation_method, compression_method);
}
}

View File

@ -1,78 +0,0 @@
package com.dpkj.modules.autoReplyPrint.controller;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.autoReplyPrint.service.ImagePrintService;
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.multipart.MultipartFile;
import javax.annotation.Resource;
/**
* 图片打印控制层
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 13:57:11
*/
@RequestMapping("/autoReplyPrint")
public class ImagePrintController {
@Resource(name = "USBImagePrint")
private ImagePrintService usbImagePrintService;
/**
* 图片打印通过路径
*/
@GetMapping("/usb/imagePrint/path")
Result<Void> usbImagePrintFromPath(@RequestParam(defaultValue = "VID:0x0FE6,PID:0x811E") String usbName,
@RequestParam(defaultValue = "500") Integer width,
@RequestParam(defaultValue = "500") Integer height,
@RequestParam String path, Integer binaryMethod, Integer compressionMethod){
this.usbImagePrintService.imagePrintFromPath(usbName, width, height, path, binaryMethod, compressionMethod);
return Result.ok("图片打印成功");
}
/**
* 图片打印通过byte[]
*/
@GetMapping("/usb/imagePrint/pathData")
Result<Void> usbImagePrintFromData(@RequestParam(defaultValue = "VID:0x0FE6,PID:0x811E") String usbName,
@RequestParam(defaultValue = "500") Integer width,
@RequestParam(defaultValue = "500") Integer height,
@RequestParam String path, Integer binaryMethod, Integer compressionMethod){
this.usbImagePrintService.imagePrintFromPathData(usbName, width, height, path, binaryMethod, compressionMethod);
return Result.ok("图片打印成功");
}
/**
* 图片打印通过multipartFile文件
*/
@GetMapping("/usb/imagePrint/multipartFile")
Result<Void> usbImagePrintFromData(@RequestParam(defaultValue = "VID:0x0FE6,PID:0x811E") String usbName,
@RequestParam(defaultValue = "500") Integer width,
@RequestParam(defaultValue = "500") Integer height,
@RequestParam MultipartFile file, Integer binaryMethod, Integer compressionMethod){
this.usbImagePrintService.imagePrintFromMultipartFile(usbName, width, height, file, binaryMethod, compressionMethod);
return Result.ok("图片打印成功");
}
/**
* 图片打印通过byte[]
*/
@GetMapping("/usb/imagePrint/data")
Result<Void> usbImagePrintFromData(@RequestParam(defaultValue = "VID:0x0FE6,PID:0x811E") String usbName,
@RequestParam(defaultValue = "500") Integer width,
@RequestParam(defaultValue = "500") Integer height,
@RequestParam byte[] data, Integer binaryMethod, Integer compressionMethod){
this.usbImagePrintService.imagePrintFromData(usbName, width, height, data, binaryMethod, compressionMethod);
return Result.ok("图片打印成功");
}
}

View File

@ -1,54 +0,0 @@
package com.dpkj.modules.autoReplyPrint.controller;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.vo.Result;
import com.dpkj.modules.autoReplyPrint.service.impl.TemplateService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 打印模板控制层
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 15:25:03
*/
@RestController
@RequestMapping("/autoReplyPrint")
public class TemplateController {
@Resource
private TemplateService templateService;
@GetMapping("/template/{templateName}")
public Result<String> testTemplate(@RequestParam String jsonData,
@RequestParam Integer width,
@RequestParam Integer height,
@PathVariable String templateName,
@RequestParam(defaultValue = "E:\\images") String saveDir) {
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), templateName, width, height, saveDir);
return Result.ok("模板生成成功");
}
@GetMapping("/template")
public Result<String> testTemplate(@RequestParam String jsonData,
@RequestParam Integer width,
@RequestParam Integer height, @RequestParam(defaultValue = "E:\\images") String saveDir) {
String html = "<!DOCTYPE html>\n" +
"<html>\n" +
"<head><title>Test</title></head>\n" +
"<body>\n" +
"<h1>你好,我是一个好的模板</h1>\n" +
"<h2><span th:text='${name}'> </span></h2>\n" +
"</body>\n" +
"</html>";
this.templateService.generateReceiptImage(JSONObject.parseObject(jsonData), html, width, height, saveDir);
return Result.ok("模板生成成功");
}
}

View File

@ -1,59 +0,0 @@
package com.dpkj.modules.autoReplyPrint.service;
import org.springframework.web.multipart.MultipartFile;
/**
* 图片打印服务接口
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 11:38:36
*/
public interface ImagePrintService {
/**
* 图片打印
* @param devName 设备名称/usb/tcp/com
* @param dstw 要打印的宽度
* @param dsth 要打印的高度
* @param pszFile 图片的路径
* @param binaryzation_method 图片二值化算法0 表示抖动算法1 表示阀值算法2 表示误差扩散法具体效果请测试查看
* @param compression_method 最终打印数据的压缩方式各值定义如下0 不压缩1 一级压缩2 二级压缩
*/
void imagePrintFromPath(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method);
/**
* 图片打印内部直接读取转换为byte进行打印
* @param devName 设备名称/usb/tcp/com
* @param dstw 要打印的宽度
* @param dsth 要打印的高度
* @param pszFile 图片的路径
* @param binaryzation_method 图片二值化算法0 表示抖动算法1 表示阀值算法2 表示误差扩散法具体效果请测试查看
* @param compression_method 最终打印数据的压缩方式各值定义如下0 不压缩1 一级压缩2 二级压缩
*/
void imagePrintFromPathData(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method);
/**
* 直接传输数据进行打印
* @param devName 设备名称/usb/tcp/com
* @param dstw 要打印的宽度
* @param dsth 要打印的高度
* @param data 图片数据
* @param binaryzation_method 图片二值化算法0 表示抖动算法1 表示阀值算法2 表示误差扩散法具体效果请测试查看
* @param compression_method 最终打印数据的压缩方式各值定义如下0 不压缩1 一级压缩2 二级压缩
*/
void imagePrintFromData(String devName, int dstw, int dsth, byte[] data, int binaryzation_method, int compression_method);
/**
* 直接传的MultipartFile文件过来
* @param devName 设备名称/usb/tcp/com
* @param dstw 要打印的宽度
* @param dsth 要打印的高度
* @param file 图片数据
* @param binaryzation_method 图片二值化算法0 表示抖动算法1 表示阀值算法2 表示误差扩散法具体效果请测试查看
* @param compression_method 最终打印数据的压缩方式各值定义如下0 不压缩1 一级压缩2 二级压缩
*/
void imagePrintFromMultipartFile(String devName, int dstw, int dsth, MultipartFile file, int binaryzation_method, int compression_method);
}

View File

@ -1,59 +0,0 @@
package com.dpkj.modules.autoReplyPrint.service.impl;
import com.dpkj.common.exception.RRException;
import com.dpkj.modules.autoReplyPrint.base.BaseImagePrint;
import com.dpkj.modules.autoReplyPrint.service.ImagePrintService;
import com.dpkj.modules.autoReplyPrint.utils.AutoReplyPrint;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/**
* 串口图片打印
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-20 14:55:37
*/
@Service("COMImagePrint")
@Slf4j
public class COMImagePrintServiceImpl extends BaseImagePrint implements ImagePrintService {
@Override
public Pointer getHandle(String devName) {
try {
Pointer pointer = AutoReplyPrint.INSTANCE.CP_Port_OpenLpt(devName);
if ( pointer == null ){
throw new RRException();
}
return pointer;
}catch (Exception e){
e.printStackTrace();
throw new RRException("获取COM串口句柄失败");
}
}
@Override
public void imagePrintFromPath(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPath(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromPathData(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPathData(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromData(String devName, int dstw, int dsth, byte[] data, int binaryzation_method, int compression_method) {
super.printFromData(devName, dstw, dsth, data, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromMultipartFile(String devName, int dstw, int dsth, MultipartFile file, int binaryzation_method, int compression_method) {
super.printFromMultipartFile(devName, dstw, dsth, file, binaryzation_method, compression_method);
}
}

View File

@ -1,63 +0,0 @@
package com.dpkj.modules.autoReplyPrint.service.impl;
import com.dpkj.common.exception.RRException;
import com.dpkj.modules.autoReplyPrint.base.BaseImagePrint;
import com.dpkj.modules.autoReplyPrint.service.ImagePrintService;
import com.dpkj.modules.autoReplyPrint.utils.AutoReplyPrint;
import com.sun.jna.Pointer;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/**
* tcp类型句柄的图片打印
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-20 14:46:06
*/
@Data
@Service("TCPImagePrint")
@Slf4j
public class TCPImagePrintServiceImpl extends BaseImagePrint implements ImagePrintService {
private String destIP; // 目标ip
private Short destPort; // 目标端口
@Override
public Pointer getHandle(String devName) {
try {
Pointer pointer = AutoReplyPrint.INSTANCE.CP_Port_OpenTcp("0", destIP, destPort, 300000, 1);
if ( pointer == null ){
throw new RRException();
}
return pointer;
}catch (Exception e){
e.printStackTrace();
throw new RRException("获取TCP句柄失败");
}
}
@Override
public void imagePrintFromPath(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPath(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromPathData(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPathData(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromData(String devName, int dstw, int dsth, byte[] data, int binaryzation_method, int compression_method) {
super.printFromData(devName, dstw, dsth, data, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromMultipartFile(String devName, int dstw, int dsth, MultipartFile file, int binaryzation_method, int compression_method) {
super.printFromMultipartFile(devName, dstw, dsth, file, binaryzation_method, compression_method);
}
}

View File

@ -1,334 +0,0 @@
package com.dpkj.modules.autoReplyPrint.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.dpkj.common.exception.RRException;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.templatemode.TemplateMode;
import org.thymeleaf.templateresolver.StringTemplateResolver;
import org.w3c.dom.Document;
import org.xhtmlrenderer.layout.SharedContext;
import org.xhtmlrenderer.simple.Graphics2DRenderer;
import javax.imageio.ImageIO;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.thymeleaf.context.Context;
/**
* 模板服务类
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-18 15:33:51
*/
@Service
@Slf4j
public class TemplateService {
/**
* 生成小票图片
*
* @param data json数据用来填充模板
* @param template 模板html字符串或者模板名称
* @param width 图片宽度
* @param height 图片高度
* @param saveDir 图片的保存路径如果为空那么不进行图片的保存
* @return 图片字节数组
*/
public byte[] generateReceiptImage(JSONObject data, String template, int width, int height, String saveDir) {
try {
// 获取模板上下文
Context context = this.getContext(data);
TemplateEngine templateEngine = new TemplateEngine();
if (checkIsHtml(template)) {
StringTemplateResolver resolver = new StringTemplateResolver();
resolver.setTemplateMode("HTML");
// 设置模板引擎使用这个自定义的模板解析器
templateEngine.setTemplateResolver(resolver);
}else {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(true);
resolver.setApplicationContext(new AnnotationConfigReactiveWebApplicationContext());
templateEngine.setTemplateResolver(resolver);
}
// 渲染模板
String html = templateEngine.process(template, context);
BufferedImage image = this.generate(html, width, height);
// 保存图片
if (saveDir != null && !"".equals(saveDir)) {
String outputPath = saveDir + "\\genera_image_" + System.currentTimeMillis() + ".png";
ImageIO.write(image, "PNG", new File(outputPath));
}
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "PNG", byteOutputStream);
return byteOutputStream.toByteArray();
} catch (Exception e) {
e.printStackTrace();
throw new RRException("图片打印失败");
}
}
/**
* 生成图片
* @param html html内容
*/
private BufferedImage generate(String html, int width, int height){
try {
// 转换为xhtml
String xhtml = this.htmlToXhtml(html);
// 转换为document
Document document = this.xhtmlToDocument(xhtml);
// 生成图片
return createImageToDocument(document, width, height);
} catch (Exception e) {
e.printStackTrace();
throw new RRException("图片打印失败");
}
}
/**
* 通过JsonObject进行context内容填充
* @param data jsonObject
* @return context
*/
private Context getContext(JSONObject data) {
// 创建Thymeleaf上下文
Context context = new Context();
Set<String> keys = data.keySet();
for (String key : keys) {
// 判单是否有图片生成统一后面采用的是_2base64Type
String[] split = key.split("_");
if (split.length > 1 && split[1].equals("2base64Type")) {
int width = split.length > 2 ? Integer.parseInt(split[2]) : 100;
int height = split.length > 3 ? Integer.parseInt(split[3]) : 100;
// 如果是图片类型,需要进行base64转换
String base64 = this.generateQRCode(String.valueOf(data.get(key)), width, height);
context.setVariable(split[0], "data:image/jpeg;base64," + base64);
} else {
// 普通字段直接设置
context.setVariable(key, data.get(key));
}
}
return context;
}
/**
* 根据内容生成二维码
* @param content 转换内容
*/
private String generateQRCode(String content, int width, int height) {
try {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置字符编码为 UTF-8
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); // 设置纠错级别
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage qrImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
qrImage.createGraphics();
Graphics2D graphics = (Graphics2D) qrImage.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
graphics.setColor(Color.BLACK);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (bitMatrix.get(i, j)) {
graphics.fillRect(i, j, 1, 1);
}
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(qrImage, "png", baos);
return Base64.getEncoder().encodeToString(baos.toByteArray());
}catch (Exception e){
log.error("二维码生成失败");
throw new RRException("二维码生成失败");
}
}
/**
* xhtml 转换为 Document
* @param xhtml xhtml
* @return document
* @throws Exception e
*/
private Document xhtmlToDocument(String xhtml) throws Exception {
// 创建DocumentBuilder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder builder = factory.newDocumentBuilder();
// 解析XHTML字符串为Document
return builder.parse(new ByteArrayInputStream(xhtml.getBytes(StandardCharsets.UTF_8)));
}
/**
* 转换将html转换为xhtml
* @param html html内容
* @return xhtml
*/
private String htmlToXhtml(String html) {
org.jsoup.nodes.Document doc = Jsoup.parse(html);
doc.outputSettings()
.syntax(org.jsoup.nodes.Document.OutputSettings.Syntax.xml)
.charset(StandardCharsets.UTF_8);
// 不使用外部DTD
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
"<head>\n" +
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n" +
"<style type=\"text/css\">\n" +
"body { font-family: SimSun, serif; }\n" +
"</style>\n" +
"</head>\n" +
"<body>\n" +
doc.body().html() +
"\n</body>\n" +
"</html>";
}
/**
* 通过document转换为图片
* @param document doc
* @param width 图片的宽度
* @param height 图片的高度
* @return bufferedImage
*/
private BufferedImage createImageToDocument(Document document, int width, int height) {
try {
// 创建Dimension对象
Dimension dimension = new Dimension(width, height);
// 创建图片
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D graphics = (Graphics2D) image.getGraphics();
// 设置白色背景
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, width, height);
// 设置渲染提示
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
// 创建渲染器
Graphics2DRenderer renderer = new Graphics2DRenderer();
renderer.setDocument(document, null);
// 设置渲染参数
SharedContext sharedContext = renderer.getSharedContext();
sharedContext.setInteractive(false);
sharedContext.setDPI(256f);
// 使用系统默认字体假设系统默认字体支持UTF - 8
Font font = new Font(Font.DIALOG, Font.PLAIN, 20);
graphics.setFont(font);
// 使用Dimension对象进行布局
renderer.layout(graphics, dimension);
renderer.render(graphics);
graphics.dispose();
return image;
} catch (Exception e) {
throw new RRException("渲染图片失败", e);
}
}
/**
* 校验这个模板内容是不是html字符串而非模板名称
* @param template template
* @return 是否是html字符串
*/
private boolean checkIsHtml(String template){
try {
String pattern = "<(\"[^\"]*\"|'[^']*'|[^'\">])*>";
Pattern r = Pattern.compile(pattern);
return r.matcher(template).find();
}catch (Exception e) {
return false;
}
}
/**
* 将document对象转换为字符串
* @param doc document
* @return document转换为的字符串
*/
private String documentToString(Document doc) {
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
return writer.getBuffer().toString();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -1,60 +0,0 @@
package com.dpkj.modules.autoReplyPrint.service.impl;
import com.dpkj.common.exception.RRException;
import com.dpkj.modules.autoReplyPrint.base.BaseImagePrint;
import com.dpkj.modules.autoReplyPrint.service.ImagePrintService;
import com.dpkj.modules.autoReplyPrint.utils.AutoReplyPrint;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/**
* 图片打印服务
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 11:38:36
*/
@Slf4j
@Service("USBImagePrint")
public class USBImagePrintServiceImpl extends BaseImagePrint implements ImagePrintService {
@Override
public Pointer getHandle(String devName) {
try {
Pointer pointer = AutoReplyPrint.INSTANCE.CP_Port_OpenUsb(devName, 1);
if ( pointer == null ){
throw new RRException();
}
return pointer;
}catch (Exception e){
e.printStackTrace();
throw new RRException("获取USB句柄失败");
}
}
@Override
public void imagePrintFromPath(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPath(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromPathData(String devName, int dstw, int dsth, String pszFile, int binaryzation_method, int compression_method) {
super.printFromPathData(devName, dstw, dsth, pszFile, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromData(String devName, int dstw, int dsth, byte[] data, int binaryzation_method, int compression_method) {
super.printFromData(devName, dstw, dsth, data, binaryzation_method, compression_method);
}
@Override
public void imagePrintFromMultipartFile(String devName, int dstw, int dsth, MultipartFile file, int binaryzation_method, int compression_method) {
super.printFromMultipartFile(devName, dstw, dsth, file, binaryzation_method, compression_method);
}
}

View File

@ -1,85 +0,0 @@
package com.dpkj.modules.autoReplyPrint.utils;
import com.dpkj.common.exception.RRException;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
/**
* 图片转换工具
*
* @author <a href="https://gitee.com/shi-chongli">石头人</a>
* @version 1.0
* @since 2025-01-17 14:06:09
*/
public class ImageUtils {
/**
* 读取图片并转换为byte数组
* @param imagePath 图片路径
* @return byte数组
*/
public static byte[] imageToBytes(String imagePath) {
try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(Paths.get(imagePath)));
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
throw new RRException("读取图片信息失败");
}
}
/**
* 获取文件byte[],通过 MultipartFile
* @param file 文件信息
* @return byte数组
*/
public static byte[] getByteToMultipartFile(MultipartFile file){
// 验证文件是否为空
if (file.isEmpty()) {
throw new RRException("文件内容为空");
}
// 验证文件类型
String contentType = file.getContentType();
if (contentType == null || !contentType.startsWith("image/")) {
throw new RRException("只支持图片文件");
}
// 获取文件扩展名
String fileName = file.getOriginalFilename();
String fileExtension = fileName != null ?
fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase() : "";
// 验证扩展名
List<String> allowedExtensions = Arrays.asList("jpg", "jpeg", "png", "gif");
if (!allowedExtensions.contains(fileExtension)) {
throw new RRException("不支持的文件格式");
}
try {
// 转换为字节数组
return file.getBytes();
}catch (Exception e){
e.printStackTrace();
throw new RRException("获取文件字节失败");
}
}
}

View File

@ -1,69 +1,139 @@
package com.dpkj.modules.cardReader.constant;
public interface StatusConstant {
// 执行成功
String IFD_OK = "0";
/**
* StatusConstant 枚举类用于表示读卡器的各种状态
* 该枚举包含了不同的状态码及其对应的状态描述提供了根据状态码获取状态描述的方法
*/
public enum StatusConstant {
/**
* 执行成功
*/
IFD_OK("0", "执行成功"),
/**
* 卡片类型不对
*/
IFD_ICC_TypeError("-1", "卡片类型不对"),
/**
* 无卡
*/
IFD_ICC_NoExist("-2", "无卡"),
/**
* 有卡未上电
*/
IFD_ICC_NoPower("-3", "有卡未上电"),
/**
* 卡片无应答
*/
IFD_ICC_NoResponse("-4", "卡片无应答"),
/**
* 卡片状态异常
*/
IFD_ICC_StatusErr("-5", "卡片状态异常"),
/**
* 读写器执行指令失败
*/
IFD_ICC_ExecuteErr("-6", "读写器执行指令失败"),
/**
* 读卡器连接错
*/
IFD_ConnectError("-11", "读卡器连接错"),
/**
* 未建立连接(没有执行打开设备函数)
*/
IFD_UnConnected("-12", "未建立连接(没有执行打开设备函数)"),
/**
* (动态库)不支持该命令
*/
IFD_BadCommand("-13", "(动态库)不支持该命令"),
/**
* (发给动态库的)命令参数出错
*/
IFD_ParameterError("-14", "(发给动态库的)命令参数出错"),
/**
* 信息校验和出错
*/
IFD_CheckSumError("-15", "信息校验和出错"),
/**
* 超时
*/
IFD_TimeOut("-16", "超时"),
/**
* 读取固件信息错误
*/
IFD_ReadErr("-17", "读取固件信息错误"),
/**
* 底层返回数据长度错误
*/
IFD_DeviceDataLen("-18", "底层返回数据长度错误"),
/**
* 卡片数据异常错误
*/
IFD_CardDataErr("-19", "卡片数据异常错误"),
/**
* 标志位不支持
*/
IFD_TAGNoExist("-20", "标志位不支持"),
/**
* 读取文件异常
*/
IFD_FileDataErr("-21", "读取文件异常"),
/**
* 设备返回数据异常
*/
IFD_DeviceDataErr("-22", "设备返回数据异常"),
/**
* 加载动态库失败
*/
IFD_LoadDllError("-23", "加载动态库失败"),
/**
* 用户取消操作
*/
IFD_UserCancel("-24", "用户取消操作"),
/**
* 密码长度错误
*/
IFD_KeyLengthErr("-25", "密码长度错误");
// 卡片类型不对
String IFD_ICC_TypeError = "-1";
private final String code;
private final String message;
// 无卡
String IFD_ICC_NoExist = "-2";
/**
* 构造函数用于初始化枚举的状态码和状态信息
* @param code 状态码
* @param message 状态信息
*/
StatusConstant(String code, String message) {
this.code = code;
this.message = message;
}
// 有卡未上电
String IFD_ICC_NoPower = "-3";
/**
* 获取状态码
* @return 状态码
*/
public String getCode() {
return code;
}
// 卡片无应答
String IFD_ICC_NoResponse = "-4";
/**
* 获取状态信息
* @return 状态信息
*/
public String getMessage() {
return message;
}
// 卡片状态异常
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";
}
/**
* 根据状态码获取相应的枚举实例
* @param code 状态码
* @return 对应的枚举实例如果不存在则返回 null
*/
public static String fromCode(String code) {
for (StatusConstant status : values()) {
if (status.code.equals(code)) {
return status.getMessage();
}
}
return null;
}
}

View File

@ -14,20 +14,19 @@ import org.springframework.web.bind.annotation.RestController;
*/
@Slf4j
@RestController
@RequestMapping("cardReader")
@RequestMapping("readCard")
public class CardReaderController {
@Autowired
private CardReaderService cardReaderService;
/**
* 连接设备并读取身份证信息
*
* @return
*/
@GetMapping("connectedDevice")
public Result<?> connectedDevice(@RequestParam(name = "devName") String devName) {
@GetMapping("IDCardReader")
public Result IDCardReader() {
try {
return cardReaderService.connectedDevice(devName);
return cardReaderService.IDCardReader();
} catch (Exception e) {
e.printStackTrace();
log.info("设备连接失败 {}", e.getMessage());
@ -38,13 +37,12 @@ public class CardReaderController {
/**
* 连接设备并读取社保卡信息
*
* @return
*/
@GetMapping("readSocialSecurityCard")
public Result<?> readSocialSecurityCard(@RequestParam(name = "devName") String devName) {
@GetMapping("SocialSecurityCardReader")
public Result<?> SocialSecurityCardReader() {
try {
return cardReaderService.readSocialSecurityCard(devName);
return cardReaderService.SocialSecurityCardReader();
} catch (Exception e) {
e.printStackTrace();
log.info("连接设备并读取社保卡信息失败 {}", e.getMessage());

View File

@ -5,7 +5,7 @@ import com.dpkj.common.vo.Result;
public interface CardReaderService {
Result<?> connectedDevice(String devName);
Result IDCardReader();
Result<?> readSocialSecurityCard(String devName);
Result SocialSecurityCardReader();
}

View File

@ -4,139 +4,95 @@ import com.dpkj.common.vo.Result;
import com.dpkj.modules.cardReader.service.CardReaderService;
import com.dpkj.modules.cardReader.utils.CardReaderSdk;
import com.dpkj.modules.cardReader.utils.CardReaderUtil;
import com.dpkj.modules.cardReader.utils.SocialSecurityCardInfoVO;
import com.dpkj.modules.cardReader.utils.UserInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class CardReaderServiceImpl implements CardReaderService {
private CardReaderUtil.CardReaderSdk cardReaderSdk = CardReaderUtil.getCardReaderSDK();
public CardReaderServiceImpl() throws CardReaderUtil.CardReaderRegistrationException {
}
private CardReaderSdk cardReaderSdk = CardReaderUtil.getCardReaderSDK();
@Value("${IDCardReader.waitingTime}")
private Long waitingTime;
@Override
public Result<?> connectedDevice(String devName) {
Long aLong = null;
public Result IDCardReader() {
Long handle = null;
UserInfoVO userInfo = null;
try {
// 连接指定设备与电脑端口即打开端口
// aLong = cardReaderSdk.ICC_Reader_Open(devName);
aLong = CardReaderSdk.INSTANCE.ICC_Reader_Open(devName);
log.info("连接指定设备与电脑端口,即打开端口:{}", aLong);
// 读取身份证物理ID号
// Long cardId = cardReaderSdk.PICC_Reader_Read_CardID(aLong);
Long cardId = CardReaderSdk.INSTANCE.PICC_Reader_Read_CardID(aLong);
log.info("读取身份证物理ID号:{}", cardId);
// 读取身份证物理ID号
// Long idCard = cardReaderSdk.PICC_Reader_ReadIDCard(aLong);
Long idCard = CardReaderSdk.INSTANCE.PICC_Reader_ReadIDCard(aLong);
log.info("读取身份证物理ID号:{}", idCard);
if (cardId != null) {
// 获取证件类型
// Integer cardType = cardReaderSdk.GetCardType(idCard.toString());
Integer cardType = CardReaderSdk.INSTANCE.GetCardType();
log.info("获取证件类型:{}", cardType);
// 姓名(类型为 1 时表示外国人中文姓名)
// Integer name = cardReaderSdk.GetName(idCard.toString());
Integer name = CardReaderSdk.INSTANCE.GetName(idCard.toString());
log.info("姓名:{}", name);
// 性别
// Integer sex = cardReaderSdk.GetSex(idCard.toString());
Integer sex = CardReaderSdk.INSTANCE.GetSex(idCard.toString());
log.info("性别:{}", sex);
// 民族
// Integer nation = cardReaderSdk.GetNation(idCard.toString());
Integer nation = CardReaderSdk.INSTANCE.GetNation(idCard.toString());
log.info("民族:{}", nation);
// 出生日期
// Integer birth = cardReaderSdk.GetBirth(idCard.toString());
Integer birth = CardReaderSdk.INSTANCE.GetBirth(idCard.toString());
log.info("出生日期:{}", birth);
// 住址
// Integer address = cardReaderSdk.GetAddress(idCard.toString());
Integer address = CardReaderSdk.INSTANCE.GetAddress(idCard.toString());
log.info("住址:{}", address);
// 公民身份证号码(类型为 1时表示外国人居留证号码)
// Integer certNo = cardReaderSdk.GetCertNo(idCard.toString());
Integer certNo = CardReaderSdk.INSTANCE.GetCertNo(idCard.toString());
log.info("公民身份证号码:{}", certNo);
// 签发机关
// Integer departemt = cardReaderSdk.GetDepartemt(idCard.toString());
Integer departemt = CardReaderSdk.INSTANCE.GetDepartemt(idCard.toString());
log.info("签发机关:{}", departemt);
// 有效起始日期
// Integer effectDate = cardReaderSdk.GetEffectDate(idCard.toString());
Integer effectDate = CardReaderSdk.INSTANCE.GetEffectDate(idCard.toString());
log.info("有效起始日期:{}", effectDate);
// 有效截止日期
// Integer expireDate = cardReaderSdk.GetExpireDate(idCard.toString());
Integer expireDate = CardReaderSdk.INSTANCE.GetExpireDate(idCard.toString());
log.info("有效截止日期:{}", expireDate);
// bmp 格式照片数据
String bmpFileData = cardReaderSdk.GetBmpFileData(cardId.toString());
log.info("bmp 格式照片数据:{}", bmpFileData);
// 生成照片
Integer bmpFile = cardReaderSdk.GetBmpFile(bmpFileData);
log.info("生成照片:{}", bmpFile);
// 是否含存在指纹信息存在时返回 512 或者 1024 不存在时返回 0
Integer isFingerExist = cardReaderSdk.IsFingerExist();
log.info("是否含存在指纹信息:{}", isFingerExist);
if (isFingerExist != 0) {
// 获取指纹数据成功时返回获取到的字节长度
Integer fingerprint = cardReaderSdk.GetFingerprint(isFingerExist.toString());
log.info("获取指纹数据:{}", fingerprint);
handle = cardReaderSdk.ICC_Reader_Open("USB1");
log.info("连接指定设备与电脑端口,即打开端口:{}", handle);
long startTime = System.currentTimeMillis();
while (true) {
try {
Long idCard = cardReaderSdk.PICC_Reader_ReadIDCard(handle);
userInfo = new UserInfoVO(cardReaderSdk);
if (!"".equals(userInfo.getName()) && userInfo.getName() != null) {
break;
}
} catch (Exception e) {
// 处理创建 UserInfoVO 时可能出现的异常
log.info("创建 UserInfoVO 对象时发生异常", e);
}
if (cardType == 1) {
// 外国人英文姓名
Integer enName = cardReaderSdk.GetEnName(cardId.toString());
log.info("外国人英文姓名:{}", enName);
// 外国人国籍代码符合GB/T2659-2000规定
Integer nationalityCode = cardReaderSdk.GetNationalityCode(cardId.toString());
log.info("外国人国籍代码:{}", nationalityCode);
// 外国人换证次数
Integer hzcs = cardReaderSdk.GetHZCS(cardId.toString());
log.info("外国人换证次数:{}", hzcs);
} else if (cardType == 2) {
// 港澳台通行证号码
Integer txzhm = cardReaderSdk.GetTXZHM(cardId.toString());
log.info("港澳台通行证号码:{}", txzhm);
// 港澳台通行证签发次数
Integer txzqfcs = cardReaderSdk.GetTXZQFCS(cardId.toString());
log.info("港澳台通行证签发次数:{}", txzqfcs);
long elapsedTime = System.currentTimeMillis() - startTime;
if (elapsedTime >= waitingTime) {
log.info("读取 ID 卡信息超时,等待了 {} 秒。", waitingTime);
return Result.error("读取 ID 卡信息超时,请重试。");
}
try {
// 短暂休眠避免 CPU 空转
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} catch (Error e) {
log.error("Error occurred during card reader operation: ", e);
if (aLong != null) {
// 关闭端口
cardReaderSdk.ICC_Reader_Close(aLong);
return Result.ok(userInfo);
} finally {
if (handle != null) {
// 不管什么情况最终都要关闭端口
cardReaderSdk.ICC_Reader_Close(handle);
}
return Result.error("操作失败:" + e.getMessage());
}
return Result.ok(aLong);
}
@Override
public Result<?> readSocialSecurityCard(String devName) {
Long aLong = null;
public Result SocialSecurityCardReader() {
Long handle = null;
try {
// 连接指定设备与电脑端口即打开端口
aLong = cardReaderSdk.ICC_Reader_Open(devName);
log.info("连接指定设备与电脑端口,即打开端口:{}", aLong);
handle = cardReaderSdk.ICC_Reader_Open("USB1");
log.info("连接指定设备与电脑端口,即打开端口:{}", handle);
// 读基本信息
String bas = cardReaderSdk.iReadCardBas(1);
String bas = cardReaderSdk.iReadCardBas(3);
log.info("读基本信息:{}", bas);
String[] split = bas.split("\\|");
SocialSecurityCardInfoVO socialSecurityCardInfoVO = new SocialSecurityCardInfoVO();
// 区号代码截取
socialSecurityCardInfoVO.setAreaCode(split[0].substring(split[0].length() - 6));
socialSecurityCardInfoVO.setSocialSecurityNo(split[1]);
socialSecurityCardInfoVO.setCardNumber(split[2]);
socialSecurityCardInfoVO.setIdentificationCode(split[3]);
socialSecurityCardInfoVO.setName(split[4]);
socialSecurityCardInfoVO.setCardResetInformation(split[5]);
socialSecurityCardInfoVO.setSpecificationVersion(split[6]);
socialSecurityCardInfoVO.setIssuanceDate(split[7]);
socialSecurityCardInfoVO.setExpireDate(split[8]);
socialSecurityCardInfoVO.setTerminalNumber(split[9]);
socialSecurityCardInfoVO.setTerminalDeviceNumber(split[10]);
return Result.ok(socialSecurityCardInfoVO);
} catch (Exception e) {
log.error("Error occurred during card reader operation: ", e);
if (aLong != null) {
if (handle != null) {
// 关闭端口
cardReaderSdk.ICC_Reader_Close(aLong);
cardReaderSdk.ICC_Reader_Close(handle);
}
return Result.error("操作失败:" + e.getMessage());
}
return null;
}
}

View File

@ -0,0 +1,418 @@
package com.dpkj.modules.cardReader.utils;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface CardReaderSdk extends Library {
CardReaderSdk INSTANCE = (CardReaderSdk) Native.loadLibrary("SSSE32", CardReaderSdk.class);
/**
* 连接指定设备与电脑端口即打开端口
*
* @param devName 接口名称USB1
* @return >0成功<=0失败
*/
Long ICC_Reader_Open(String devName);
/**
* 关闭已打开的电脑接口
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return =0成功非0失败
*/
Long ICC_Reader_Close(Long ReaderHandle);
/**
* 读写器产生蜂鸣
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param time 蜂鸣时间以毫秒为单位
* @return =0成功非0失败
*/
Long ICC_PosBeep(Long ReaderHandle, Long time);
/**
* 获取动态库及设备版本信息
*
* @return 设备及动态库版本信息 =0成功非0失败
*/
Long ICC_Reader_Libinfo();
/**
* 从EEPROM读取数据
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 偏移地址(起始地址)
* @param length 要读取的数据的长度
* @return 读取的数据 =0成功非0失败
*/
Long ICC_Reader_ReadEEPROM(Long ReaderHandle, int offset, int length);
/**
* 往EEPROM写入数据
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 偏移地址(起始地址)
* @param length 要写入的数据的长度
* @param buffer 待写入的数据
* @return =0成功非0失败
*/
Long ICC_Reader_WriteEEPROM(Long ReaderHandle, int offset, int length, String buffer);
/**
* 播放语音SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param voiceType 语音类型
* 1请插卡
* 2请刷卡
* 3读卡错误
* 4请输入密码
* 5密码错误
* 6操作成功
* 7操作超时
* 8操作失败
* 9请取回卡
* 10请重新输入密码
* 11请再次输入密码
* 12请输入新密码
* 13请输入旧密码
* 14请确认新密码
* @return =0成功非0失败
*/
@Deprecated
Long ICC_Reader_DispSound(Long ReaderHandle, String voiceType);
/**
* 接触 CPU 卡上电复位返回值数据格式为十六进制字符串
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return 上电返回ATR值数据格式为十六进制字符串
*/
Long ICC_Reader_PowerOnHEX(Long ReaderHandle, String ICCSlotNo);
/**
* CPU 卡下电
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return =0成功非0失败
*/
Long ICC_Reader_PowerOff(Long ReaderHandle, String ICCSlotNo);
/**
* 获取卡座状态
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return = 0 表示卡座有卡,其他见状态码
*/
Long ICC_Reader_GetStatus(Long ReaderHandle, String ICCSlotNo);
/**
* 接触 CPU 卡执行APDU命令
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @param CommandAPDU APDU命令数据以十六进制字符串形式输入
* @return 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败
*/
Long ICC_Reader_ApplicationHEX(Long ReaderHandle, String ICCSlotNo, String CommandAPDU);
/**
* 4442卡片上电数据以十六进制字符串输出
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回卡片上电信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_PowerOnHEX(Long ReaderHandle);
/**
* 4442卡片下电
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return = 0 表示成功,非0失败
*/
Long ICC_Reader_4442_PowerOff(Long ReaderHandle);
/**
* 读取4442卡的指定字段内容,以十六进制字符串输出
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 起始地址需小于256
* @param len 数据长度offset+len需小于256
* @return 返回卡片读取信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_ReadHEX(Long ReaderHandle, int offset, int len);
/**
* 4442 卡的指定字段内容以十六进制字符串输入参数
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 起始地址需小于256
* @param len 数据长度offset+len需小于256
* @param data 待写入卡片数据
* @return 返回卡片读取信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_WriteHEX(Long ReaderHandle, int offset, int len, String data);
/**
* 4442卡认证密钥
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param keyHex 卡密钥
* @return = 0 表示成功,非0失败
*/
Long ICC_Reader_4442_Verify(Long ReaderHandle, String keyHex);
/** ----- 非接触操作函数 -------------- */
/**
* 查找天线磁场区域内有无卡只有卡片上电后才能查找到
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return = 0 表示成功,非0失败
*/
Long PICC_Reader_Request(Long ReaderHandle);
/**
* 天线操作
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param flag 00-关场强 01-开场强
* @return = 0 表示成功,非0失败
*/
Long PICC_Reader_RFControl(Long ReaderHandle, String flag);
/** --------------- 非接 CPU 卡操作函数 ------------ */
/**
* 非接TypeA CPU卡上电复位输出十六进制字符串SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度大于0 表示成功,其他失败
*/
@Deprecated
Long PICC_Reader_PowerOnTypeAHEX(Long ReaderHandle);
/**
* 非接TypeB CPU卡上电复位输出十六进制字符串SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度大于0 表示成功,其他失败
*/
@Deprecated
Long PICC_Reader_PowerOnTypeBHEX(Long ReaderHandle);
/**
* 非接触 CPU 卡执行APDU命令命令以十六进制字符串传输SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param CommandAPDU APDU命令数据以十六进制字符串形式输入
* @return APDU命令执行后, 响应的数据, 返回数据为十六进制字符串
* 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败
*/
@Deprecated
Long PICC_Reader_ApplicationHEX(Long ReaderHandle, String CommandAPDU);
/** ---------------- 二代证/外国人居留证/港澳台居住证 --------------- */
/**
* 读取身份证物理ID号
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回身份证物理ID信息 = 0 表示成功,非0失败
*/
Long PICC_Reader_Read_CardID(Long ReaderHandle, byte[] response);
/**
* 读取身份证物理ID号
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回错误信息 = 0 表示成功,非0失败
*/
Long PICC_Reader_ReadIDCard(Long ReaderHandle);
/** 以下函数须在 “PICC_Reader_ReadIDCard” 函数执行成功之后调用,否则获取不到有效信息 */
/**
* 获取证件类型
*
* @return 0居民身份证
* 1外国人永久居留证
* 2港澳台居民居住证
* 4新外国人永久居留证
*/
Integer GetCardType();
/**
* 姓名(类型为 1 时表示外国人中文姓名)
*/
Integer GetName(byte[] outParam);
/**
* 性别
*/
Integer GetSex(byte[] outParam);
/**
* 民族
*/
Integer GetNation(byte[] outParam);
/**
* 出生日期
*/
Integer GetBirth(byte[] outParam);
/**
* 住址
*/
Integer GetAddress(byte[] outParam);
/**
* 公民身份证号码(类型为 1时表示外国人居留证号码)
*/
Integer GetCertNo(byte[] outParam);
/**
* 签发机关
*/
Integer GetDepartemt(byte[] outParam);
/**
* 有效起始日期
*/
Integer GetEffectDate(byte[] outParam);
/**
* 有效截止日期
*/
Integer GetExpireDate(byte[] outParam);
/**
* bmp 格式照片数据
*/
String GetBmpFileData(byte[] outParam);
/**
* 生成照片
* TODO 入参参考文中3.4.1
*/
Integer GetBmpFile(byte[] outParam);
/**
* 是否含存在指纹信息存在时返回 512 或者 1024
* 不存在时返回 0
*/
Integer IsFingerExist();
/**
* 获取指纹数据成功时返回获取到的字节长度
*/
Integer GetFingerprint(byte[] outParam);
/**
* 外国人英文姓名
*/
Integer GetEnName(byte[] outParam);
/**
* 外国人国籍代码符合GB/T2659-2000规定
*/
Integer GetNationalityCode(byte[] outParam);
/**
* 港澳台通行证号码
*/
Integer GetTXZHM(byte[] outParam);
/**
* 港澳台通行证签发次数
*/
Integer GetTXZQFCS(byte[] outParam);
/**
* 外国人换证次数
*/
Integer GetHZCS(byte[] outParam);
/** ------------ 社保卡 ---------*/
/**
* 选择社保卡社会保障系统环境后通过 PSAM 卡对社保卡进行内部认证通过后将卡内的基本信息读出返回
*
* @param iType 操作卡的类型
* 1-接触式操作卡
* 2-非接触式操作卡
* 3-自动寻卡接触式操作卡优先
* 4-自动寻卡非接触式操作卡优先
* @return
*/
String iReadCardBas(Integer iType);
/**
* 基于加密机的读基本信息步骤一
* 选择社会保障系统环境后返回内部认证和外部认证所需信息
*
* @param iType 操作卡的类型
* 1-接触式操作卡
* 2-非接触式操作卡
* 3-自动寻卡接触式操作卡优先
* 4-自动寻卡非接触式操作卡优先
* @return
*/
Long iReadCardBas_HSM_Step1(Integer iType);
/**
* 基于加密机的读基本信息步骤二
* 根据加密机返回的内部认证和外部认证结果数据对社保卡进行内部认证和外部认证通过后将卡内的基本信息读出返回
*
* @param pKey 加密机返回的内部认证和外部认证结果数据依次为内部认证结果数据
* 即内部认证鉴别数据16 和内部认证鉴别所需的原始信息16 拼接组
* 外部认证结果数据即外部认证鉴别数据16 和外部认证鉴别所需的
* 原始信息16 拼接组成各数据项之间以|分割且最后一个数据项以|结尾
* @return
*/
Long iReadCardBas_HSM_Step2(String pKey, byte[] outParam);
}

View File

@ -1,8 +1,7 @@
package com.dpkj.modules.cardReader.utils;
import com.sun.jna.Library;
import com.dpkj.common.exception.RRException;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@ -12,448 +11,15 @@ public class CardReaderUtil {
* 获取 多合一读卡器 实例同时注册 CardReaderSdk 控件
*
* @return CardReaderSdk 实例
* @throws CardReaderRegistrationException 如果注册控件失败抛出此异常
* @throws RRException 如果注册控件失败抛出此异常
*/
public static CardReaderSdk getCardReaderSDK() throws CardReaderRegistrationException {
public static CardReaderSdk getCardReaderSDK() throws RRException {
try {
// return Native.load("UnPack", CardReaderSdk.class);
return Native.load("SSSE32", CardReaderSdk.class);
return Native.loadLibrary("SSSE32", CardReaderSdk.class);
} catch (UnsatisfiedLinkError e) {
log.info("[CardReader][AutoReplyPrint2.getCardReaderSDK] SDK注册失败 {}", e.getMessage());
throw new CardReaderRegistrationException("Failed to load CardReaderSdk library: ", e);
throw new RRException("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 ICC_Reader_Open(String devName);
/**
* 关闭已打开的电脑接口
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return =0成功非0失败
*/
Long ICC_Reader_Close(Long ReaderHandle);
/**
* 读写器产生蜂鸣
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param time 蜂鸣时间以毫秒为单位
* @return =0成功非0失败
*/
Long ICC_PosBeep(Long ReaderHandle, Long time);
/**
* 获取动态库及设备版本信息
*
* @return 设备及动态库版本信息 =0成功非0失败
*/
Long ICC_Reader_Libinfo();
/**
* 从EEPROM读取数据
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 偏移地址(起始地址)
* @param length 要读取的数据的长度
* @return 读取的数据 =0成功非0失败
*/
Long ICC_Reader_ReadEEPROM(Long ReaderHandle, int offset, int length);
/**
* 往EEPROM写入数据
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 偏移地址(起始地址)
* @param length 要写入的数据的长度
* @param buffer 待写入的数据
* @return =0成功非0失败
*/
Long ICC_Reader_WriteEEPROM(Long ReaderHandle, int offset, int length, String buffer);
/**
* 播放语音SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param voiceType 语音类型
* 1请插卡
* 2请刷卡
* 3读卡错误
* 4请输入密码
* 5密码错误
* 6操作成功
* 7操作超时
* 8操作失败
* 9请取回卡
* 10请重新输入密码
* 11请再次输入密码
* 12请输入新密码
* 13请输入旧密码
* 14请确认新密码
* @return =0成功非0失败
*/
@Deprecated
Long ICC_Reader_DispSound(Long ReaderHandle, String voiceType);
/**
* 接触 CPU 卡上电复位返回值数据格式为十六进制字符串
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return 上电返回ATR值数据格式为十六进制字符串
*/
Long ICC_Reader_PowerOnHEX(Long ReaderHandle, String ICCSlotNo);
/**
* CPU 卡下电
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return =0成功非0失败
*/
Long ICC_Reader_PowerOff(Long ReaderHandle, String ICCSlotNo);
/**
* 获取卡座状态
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @return = 0 表示卡座有卡,其他见状态码
*/
Long ICC_Reader_GetStatus(Long ReaderHandle, String ICCSlotNo);
/**
* 接触 CPU 卡执行APDU命令
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param ICCSlotNo ICC插槽号 0x01 大卡座
* 0x02 副卡座
* 0x11SAM1卡座
* 0x12SAM2卡座
* 0x13SAM3卡座
* 0x14SAM4卡座
* 0x3x非接CPU卡
* @param CommandAPDU APDU命令数据以十六进制字符串形式输入
* @return 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败
*/
Long ICC_Reader_ApplicationHEX(Long ReaderHandle, String ICCSlotNo, String CommandAPDU);
/**
* 4442卡片上电数据以十六进制字符串输出
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回卡片上电信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_PowerOnHEX(Long ReaderHandle);
/**
* 4442卡片下电
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return = 0 表示成功,非0失败
*/
Long ICC_Reader_4442_PowerOff(Long ReaderHandle);
/**
* 读取4442卡的指定字段内容,以十六进制字符串输出
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 起始地址需小于256
* @param len 数据长度offset+len需小于256
* @return 返回卡片读取信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_ReadHEX(Long ReaderHandle, int offset, int len);
/**
* 4442 卡的指定字段内容以十六进制字符串输入参数
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param offset 起始地址需小于256
* @param len 数据长度offset+len需小于256
* @param data 待写入卡片数据
* @return 返回卡片读取信息 = 0 表示成功,非0失败
*/
Long ICC_Reader_4428_WriteHEX(Long ReaderHandle, int offset, int len, String data);
/**
* 4442卡认证密钥
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param keyHex 卡密钥
* @return = 0 表示成功,非0失败
*/
Long ICC_Reader_4442_Verify(Long ReaderHandle, String keyHex);
/** ----- 非接触操作函数 -------------- */
/**
* 查找天线磁场区域内有无卡只有卡片上电后才能查找到
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return = 0 表示成功,非0失败
*/
Long PICC_Reader_Request(Long ReaderHandle);
/**
* 天线操作
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param flag 00-关场强 01-开场强
* @return = 0 表示成功,非0失败
*/
Long PICC_Reader_RFControl(Long ReaderHandle, String flag);
/** --------------- 非接 CPU 卡操作函数 ------------ */
/**
* 非接TypeA CPU卡上电复位输出十六进制字符串SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度大于0 表示成功,其他失败
*/
@Deprecated
Long PICC_Reader_PowerOnTypeAHEX(Long ReaderHandle);
/**
* 非接TypeB CPU卡上电复位输出十六进制字符串SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 输出上电成功返回的卡片复位信息(ATS) 返回ATS长度大于0 表示成功,其他失败
*/
@Deprecated
Long PICC_Reader_PowerOnTypeBHEX(Long ReaderHandle);
/**
* 非接触 CPU 卡执行APDU命令命令以十六进制字符串传输SSSE32.dll暴露函数中未发现该函数但是文档中有
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @param CommandAPDU APDU命令数据以十六进制字符串形式输入
* @return APDU命令执行后, 响应的数据, 返回数据为十六进制字符串
* 大于 0 表示执行成功,其值为 Response_APDU 的数据长度.否则表示执行失败
*/
@Deprecated
Long PICC_Reader_ApplicationHEX(Long ReaderHandle, String CommandAPDU);
/** ---------------- 二代证/外国人居留证/港澳台居住证 --------------- */
/**
* 读取身份证物理ID号
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回身份证物理ID信息 = 0 表示成功,非0失败
*/
Long PICC_Reader_Read_CardID(Long ReaderHandle);
/**
* 读取身份证物理ID号
*
* @param ReaderHandle ICCReaderOpen函数所返回的值
* @return 返回错误信息 = 0 表示成功,非0失败
*/
Long PICC_Reader_ReadIDCard(Long ReaderHandle);
/** 以下函数须在 “PICC_Reader_ReadIDCard” 函数执行成功之后调用,否则获取不到有效信息 */
/**
* 获取证件类型
*
* @return 0居民身份证
* 1外国人永久居留证
* 2港澳台居民居住证
* 4新外国人永久居留证
*/
Integer GetCardType(Pointer pointer);
/**
* 姓名(类型为 1 时表示外国人中文姓名)
*/
Integer GetName(Pointer pointer);
/**
* 性别
*/
Integer GetSex(Pointer pointer);
/**
* 民族
*/
Integer GetNation(Pointer pointer);
/**
* 出生日期
*/
Integer GetBirth(Pointer pointer);
/**
* 住址
*/
Integer GetAddress(Pointer pointer);
/**
* 公民身份证号码(类型为 1时表示外国人居留证号码)
*/
Integer GetCertNo(Pointer pointer);
/**
* 签发机关
*/
Integer GetDepartemt(Pointer pointer);
/**
* 有效起始日期
*/
Integer GetEffectDate(Pointer pointer);
/**
* 有效截止日期
*/
Integer GetExpireDate(Pointer pointer);
/**
* bmp 格式照片数据
*/
String GetBmpFileData(String IDCard);
/**
* 生成照片
* TODO 入参参考文中3.4.1
*/
Integer GetBmpFile(String pBmpfilepath);
/**
* 是否含存在指纹信息存在时返回 512 或者 1024
* 不存在时返回 0
*/
Integer IsFingerExist();
/**
* 获取指纹数据成功时返回获取到的字节长度
*/
Integer GetFingerprint(String fpInfo);
/**
* 外国人英文姓名
*/
Integer GetEnName(String IDCard);
/**
* 外国人国籍代码符合GB/T2659-2000规定
*/
Integer GetNationalityCode(String IDCard);
/**
* 港澳台通行证号码
*/
Integer GetTXZHM(String IDCard);
/**
* 港澳台通行证签发次数
*/
Integer GetTXZQFCS(String IDCard);
/**
* 外国人换证次数
*/
Integer GetHZCS(String IDCard);
/** ------------ 社保卡 ---------*/
/**
* 选择社保卡社会保障系统环境后通过 PSAM 卡对社保卡进行内部认证通过后将卡内的基本信息读出返回
*
* @param iType 操作卡的类型
* 1-接触式操作卡
* 2-非接触式操作卡
* 3-自动寻卡接触式操作卡优先
* 4-自动寻卡非接触式操作卡优先
* @return
*/
String iReadCardBas(Integer iType);
/**
* 基于加密机的读基本信息步骤一
* 选择社会保障系统环境后返回内部认证和外部认证所需信息
*
* @param iType 操作卡的类型
* 1-接触式操作卡
* 2-非接触式操作卡
* 3-自动寻卡接触式操作卡优先
* 4-自动寻卡非接触式操作卡优先
* @return
*/
Long iReadCardBas_HSM_Step1(Integer iType);
/**
* 基于加密机的读基本信息步骤二
* 根据加密机返回的内部认证和外部认证结果数据对社保卡进行内部认证和外部认证通过后将卡内的基本信息读出返回
*
* @param pKey 加密机返回的内部认证和外部认证结果数据依次为内部认证结果数据
* 即内部认证鉴别数据16 和内部认证鉴别所需的原始信息16 拼接组
* 外部认证结果数据即外部认证鉴别数据16 和外部认证鉴别所需的
* 原始信息16 拼接组成各数据项之间以|分割且最后一个数据项以|结尾
* @return
*/
Long iReadCardBas_HSM_Step2(String pKey);
}
/**
* 定义自定义异常类用于表示注册控件时发生的错误
*/
public static class CardReaderRegistrationException extends Exception {
public CardReaderRegistrationException(String message) {
super(message);
}
public CardReaderRegistrationException(String message, Throwable cause) {
super(message, cause);
}
}
}

View File

@ -0,0 +1,29 @@
package com.dpkj.modules.cardReader.utils;
import lombok.Data;
@Data
public class SocialSecurityCardInfoVO {
// 发卡地区行政区划代码
private String areaCode;
// 社会保障号码
private String socialSecurityNo;
// 卡号
private String cardNumber;
// 卡识别码
private String identificationCode;
// 姓名
private String name;
// 卡复位信息
private String cardResetInformation;
// 规范版本
private String specificationVersion;
// 发卡日期
private String issuanceDate;
// 卡有效期
private String expireDate;
// 终端机编号
private String terminalNumber;
// 终端设备号
private String terminalDeviceNumber;
}

View File

@ -0,0 +1,147 @@
package com.dpkj.modules.cardReader.utils;
import com.dpkj.common.exception.RRException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Consumer;
/**
* 用户基本信息
*/
@Data
public class UserInfo {
/**
* 名字
*/
private String name;
/**
* 性别
*/
private String sex;
/**
* 民族
*/
private String nation;
/**
* 出生日期
*/
private String brith;
/**
* 住址
*/
private String address;
/**
* 身份证号码
*/
private String certNo;
/**
* 签发机关
*/
private String department;
/**
* 有效日期
*/
private String effectDate;
/**
* 截至日期
*/
private String expireDate;
/**
* 外国人姓名
*/
private String enName;
/**
* 外国人国籍
*/
private String nationalityCode;
/**
* 注册过的sdk实例
*/
@JsonIgnore
private CardReaderSdk cardReaderSdk;
/**
* 是否有指纹
*/
private Boolean fingerExist;
/**
* 指纹数据
*/
private byte[] fingerData;
/**
* 港澳台通行证号码
*/
private String TXZHM;
/**
* 港澳台通行证签发次数
*/
private Integer TXZQFCS;
/**
* 外国人换证次数
*/
private Integer HZCS;
public UserInfo(CardReaderSdk cardReaderSdk){
if ( cardReaderSdk == null ){
throw new RRException("sdk初始化失败");
}
this.cardReaderSdk = cardReaderSdk;
this.name = this.convert2Str(this.cardReaderSdk::GetName, "姓名转换失败");
this.sex = this.convert2Str(this.cardReaderSdk::GetSex, "性别转换失败");
this.nation = this.convert2Str(this.cardReaderSdk::GetNation, "民族转换失败");
this.brith = this.convert2Str(this.cardReaderSdk::GetBirth, "出生日期转换失败");
this.address = this.convert2Str(this.cardReaderSdk::GetAddress, "住址转换失败");
this.certNo = this.convert2Str(this.cardReaderSdk::GetCertNo, "身份证转换失败");
this.department = this.convert2Str(this.cardReaderSdk::GetDepartemt, "签发机关转换失败");
this.effectDate = this.convert2Str(this.cardReaderSdk::GetEffectDate, "过期时间转换失败");
this.expireDate = this.convert2Str(this.cardReaderSdk::GetExpireDate, "截至日期转换失败");
this.enName = this.convert2Str(this.cardReaderSdk::GetEnName, "外国人姓名转换失败");
this.nationalityCode = this.convert2Str(this.cardReaderSdk::GetNationalityCode, "外国人国籍转换失败");
}
private String convert2Str(Consumer<byte[]> function, String tip) {
byte[] param = new byte[256];
function.accept(param);
try {
return new String(param, "GBK").trim();
}catch (Exception e){
throw new RRException(tip == null ? "参数转换失败" : tip);
}
}
private LocalDateTime str2LocalDateTime(String str){
// 定义日期格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// 将字符串解析为 LocalDate
LocalDate localDate = LocalDate.parse(str, formatter);
// LocalDate 转换为 LocalDateTime设置时间为 00:00:00
return localDate.atStartOfDay();
}
}

View File

@ -0,0 +1,73 @@
package com.dpkj.modules.cardReader.utils;
import com.dpkj.common.exception.RRException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.function.Consumer;
@Data
public class UserInfoVO {
// 姓名
private String name;
// 性别
private String sex;
// 民族
private String nation;
// 出生年月
private String born;
// 地址
private String address;
// 身份证号
private String IDCardNo;
// 签发机关
private String grantDept;
// 有效期开始日期
private String userLifeBegin;
// 有效期过期时间
private String userLifeEnd;
@JsonIgnore
private CardReaderSdk cardReaderSdk;
public UserInfoVO(CardReaderSdk cardReaderSdk) {
if (cardReaderSdk == null) {
throw new RRException("sdk初始化失败");
}
this.cardReaderSdk = cardReaderSdk;
this.name = this.convert2Str(this.cardReaderSdk::GetName, "姓名转换失败");
this.sex = this.convert2Str(this.cardReaderSdk::GetSex, "性别转换失败");
this.nation = this.convert2Str(this.cardReaderSdk::GetNation, "民族转换失败");
this.born = this.convert2Str(this.cardReaderSdk::GetBirth, "出生日期转换失败");
this.address = this.convert2Str(this.cardReaderSdk::GetAddress, "住址转换失败");
this.IDCardNo = this.convert2Str(this.cardReaderSdk::GetCertNo, "身份证转换失败");
this.grantDept = this.convert2Str(this.cardReaderSdk::GetDepartemt, "签发机关转换失败");
this.userLifeBegin = this.convert2Str(this.cardReaderSdk::GetEffectDate, "有效期开始日期转换失败");
this.userLifeEnd = this.convert2Str(this.cardReaderSdk::GetExpireDate, "有效期截至日期转换失败");
}
private String convert2Str(Consumer<byte[]> function, String tip) {
byte[] param = new byte[256];
function.accept(param);
try {
return new String(param, "GBK").trim();
} catch (Exception e) {
throw new RRException(tip == null ? "参数转换失败" : tip);
}
}
private LocalDateTime str2LocalDateTime(String str) {
// 定义日期格式化器
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
// 将字符串解析为 LocalDate
LocalDate localDate = LocalDate.parse(str, formatter);
// LocalDate 转换为 LocalDateTime设置时间为 00:00:00
return localDate.atStartOfDay();
}
}

View File

@ -11,3 +11,7 @@ dpkj:
# 波特率 串口连接下使用
baud-rate:
# 身份证读取等待时间
IDCardReader:
waitingTime: 30000

View File

@ -11,3 +11,7 @@ dpkj:
# 波特率 串口连接下使用
baud-rate:
# 身份证读取等待时间
IDCardReader:
waitingTime: 30000

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.