Bladeren bron

微信端身份码接口开发

baiyun 1 jaar geleden
bovenliggende
commit
2ad7c463c0

+ 6 - 0
ruoyi-common/ruoyi-common-core/pom.xml

@@ -132,6 +132,12 @@
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+            <version>3.21.0-GA</version>
+            <scope>compile</scope>
+        </dependency>
 
     </dependencies>
 

+ 355 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ByteArrayUtilByYC.java

@@ -0,0 +1,355 @@
+package org.dromara.common.core.utils;
+
+
+import javassist.bytecode.ByteArray;
+import org.apache.commons.lang3.ArrayUtils;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ *
+ * @author ZZK
+ *
+ */
+public class ByteArrayUtilByYC extends ByteArray {
+
+	/**
+	 * 转为16位无符号正数
+	 *
+	 * @param code:字节数组
+	 * @param index:从哪个位置开始
+	 * @param isLittleEndian:是否是高低位互换(true:若bytes是低位在前,那么转为整型时,要恢复为高位在前的方式)
+	 * @return
+	 */
+	public static int readU16bit(byte[] code, int index, boolean isLittleEndian) {
+
+		if (isLittleEndian == true)
+			return (code[index] & 0xff) | ((code[index + 1] & 0xff) << 8);
+
+		return ((code[index] & 0xff) << 8) | (code[index + 1] & 0xff);
+	}
+
+	/**
+	 * 转为32位无符号整数
+	 *
+	 * @param code:字节数组
+	 * @param index:从哪个位置开始
+	 * @param isLittleEndian:是否是高低位互换(true:若bytes是低位在前,那么转为整型时,要恢复为高位在前的方式)
+	 * @return
+	 */
+	public static long readU32bit(byte[] code, int index, boolean isLittleEndian) {
+
+		if (isLittleEndian == true)
+			return ((code[index] & 0xff) | ((code[index + 1] & 0xff) << 8) | ((code[index + 2] & 0xff) << 16)
+					| ((code[index + 3] & 0xff) << 24)) & 0x0FFFFFFFFL; // 转为无符号32位整型
+
+		return (code[index] << 24) | ((code[index + 1] & 0xff) << 16) | ((code[index + 2] & 0xff) << 8)
+				| (code[index + 3] & 0xff) & 0x0FFFFFFFFL; // 转为无符号32位整型
+
+	}
+
+	/**
+	 * 转为64位整数
+	 *
+	 * @param code:字节数组
+	 * @param index:从哪个位置开始
+	 * @param isLittleEndian:是否是高低位互换(true:若bytes是低位在前,那么转为整型时,要恢复为高位在前的方式)
+	 */
+	public static long read64bit(byte[] code, int index, boolean isLittleEndian) {
+
+		if (code.length != 8)
+			throw new IllegalArgumentException("传入数据的长度不等于8个字节。");
+
+		ByteBuffer buffer = ByteBuffer.allocate(8);
+
+		if (isLittleEndian == true) {
+			for (int i = code.length - 1; i >= 0; i--)
+				buffer.put(code[i]);
+			buffer.flip();
+		} else {
+			buffer.put(code, 0, code.length);
+			buffer.flip();
+
+		}
+		return buffer.getLong();
+
+	}
+
+	/**
+	 * 将整型数据写入为16进制数据
+	 *
+	 * @param value:数据
+	 * @param code:待写入的字节数组
+	 * @param index:起始偏移位
+	 * @param isLittleEndian:是否是高低位互换(true:低位在前)
+	 */
+	public static void write16bit(int value, byte[] code, int index, boolean isLittleEndian) {
+		if (isLittleEndian == true) {
+			code[index] = (byte) value;
+			code[index + 1] = (byte) (value >>> 8);
+		} else {
+			code[index] = (byte) (value >>> 8);
+			code[index + 1] = (byte) value;
+		}
+
+	}
+
+	/**
+	 * 将整型数据写入为32进制数据
+	 *
+	 * @param value:数据
+	 * @param code:待写入的字节数组
+	 * @param index:起始偏移位
+	 * @param isLittleEndian:是否是高低位互换(true:低位在前)
+	 */
+	public static void write32bit(int value, byte[] code, int index, boolean isLittleEndian) {
+		if (isLittleEndian == true) {
+			code[index] = (byte) value;
+			code[index + 1] = (byte) (value >>> 8);
+			code[index + 2] = (byte) (value >>> 16);
+			code[index + 3] = (byte) (value >>> 24);
+		} else {
+			code[index] = (byte) (value >>> 24);
+			code[index + 1] = (byte) (value >>> 16);
+			code[index + 2] = (byte) (value >>> 8);
+			code[index + 3] = (byte) value;
+		}
+	}
+
+	/**
+	 * 将整型数据写入为64进制数据
+	 *
+	 * @param value:数据
+	 * @param code:待写入的字节数组
+	 * @param index:起始偏移位
+	 * @param isLittleEndian:是否是高低位互换(true为低位在前,高位在后)
+	 */
+	public static void write64bit(long value, byte[] code, int index, boolean isLittleEndian) {
+		ByteBuffer buffer = ByteBuffer.allocate(8);
+		buffer.putLong(0, value);
+		byte[] b = buffer.array();
+		if (isLittleEndian == true) // 若为ture,则进行交互先后位置
+			ArrayUtils.reverse(b);
+		code[0] = b[0];
+		code[1] = b[1];
+		code[2] = b[2];
+		code[3] = b[3];
+		code[4] = b[4];
+		code[5] = b[5];
+		code[6] = b[6];
+		code[7] = b[7];
+	}
+
+	/**
+	 * 拷贝一个字节数组
+	 *
+	 * @param src:源数组
+	 * @param srcPos:源起点
+	 * @param dest:目标数组
+	 * @param destPos:目标起点
+	 * @param length:拷贝字节长度
+	 */
+	public static void copy(byte[] src, int srcPos, byte[] dest, int destPos, int length) {
+		System.arraycopy(src, srcPos, dest, destPos, length);
+	}
+
+	/**
+	 * 将二进制转换成16进制
+	 *
+	 * 字节码转换为16进制字符串
+	 *
+	 * @param bytes
+	 * @param       isPrefix:是否要加入前缀0x,当为false则不加
+	 * @return
+	 */
+	public static String parseByte2HexStr(byte bytes[], boolean isPrefix) {
+		StringBuffer sb = new StringBuffer();
+		if (isPrefix == true)
+			sb.append("0x");
+		for (int i = 0; i < bytes.length; i++) {
+			String hex = Integer.toHexString(bytes[i] & 0xFF);
+			if (hex.length() == 1) {
+				hex = '0' + hex;
+			}
+			sb.append(hex.toUpperCase());
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 将二进制转换成16进制(指定长度)
+	 *
+	 * @param index:起始下标
+	 * @param length:读取的字节长度
+	 * @param bytes:源字节数组
+	 * @return
+	 */
+	public static String parseByte2HexStr(byte[] bytes, int index, int length) {
+		StringBuffer sb = new StringBuffer();
+		for (int i = index; i < index + length; i++) {
+			String hex = Integer.toHexString(bytes[i] & 0xFF);
+			if (hex.length() == 1) {
+				hex = '0' + hex;
+			}
+			sb.append(hex.toUpperCase());
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 将字节数组倒叙转换为16进制字符串
+	 *
+	 * @param bytes
+	 * @return
+	 */
+	public static String parseByte2HexStrByDesc(byte bytes[]) {
+		StringBuffer sb = new StringBuffer();
+		for (int i = bytes.length; i > 0; i--) {
+			String hex = Integer.toHexString(bytes[i - 1] & 0xFF);
+			if (hex.length() == 1) {
+				hex = '0' + hex;
+			}
+			sb.append(hex.toUpperCase());
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 将16进制转换为二进制
+	 *
+	 * @param hexStr
+	 * @return
+	 */
+	public static byte[] parseHexStr2Byte(String hexStr) {
+
+		if (hexStr.length() < 1) {
+			return null;
+		}
+
+		byte[] result = new byte[hexStr.length() / 2];
+		for (int i = 0; i < hexStr.length() / 2; i++) {
+			int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
+			int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
+			result[i] = (byte) (high * 16 + low);
+		}
+		return result;
+	}
+
+	/**
+	 * 将16进制字符串倒叙的转换为二进制
+	 *
+	 * @param hexStr
+	 * @return
+	 */
+	public static byte[] parseHexStr2ByteByDesc(String hexStr) {
+		if (hexStr.length() < 1) {
+			return null;
+		}
+		byte[] result = new byte[hexStr.length() / 2];
+		for (int i = hexStr.length() / 2, j = 0; i > 0; i--, j++) {
+			int high = Integer.parseInt(hexStr.substring((i - 1) * 2, (i - 1) * 2 + 1), 16);
+			int low = Integer.parseInt(hexStr.substring((i - 1) * 2 + 1, (i - 1) * 2 + 2), 16);
+			result[j] = (byte) (high * 16 + low);
+		}
+		return result;
+	}
+
+	/**
+	 * 获取CRC校验码值(bytes中的最后一位CRC数据传00过来)
+	 *
+	 * @param bytes
+	 * @return
+	 */
+	public static int getCRC(byte[] bytes) {
+		int ucCRC = 0x00;
+
+		for (int i = 0; i < bytes.length - 1; i++) {
+			ucCRC ^= bytes[i] & 0x0FF; // 转为无符号的byte
+
+			for (int j = 0; j < 8; j++) {
+				if ((ucCRC & 0x01) != 0) {
+					ucCRC >>= 1;
+					ucCRC ^= 0x8c;
+				} else {
+					ucCRC >>= 1;
+				}
+			}
+		}
+		return ucCRC;
+	}
+
+	/**
+	 * 将bytes转为uuid
+	 *
+	 * @param bytes
+	 * @return
+	 */
+	public static String uuidFromByteArray(byte[] bytes) {
+		ByteBuffer bb = ByteBuffer.wrap(bytes);
+		long high = bb.getLong();
+		long low = bb.getLong();
+		UUID uuid = new UUID(high, low);
+		return uuid.toString();
+	}
+
+	/**
+	 * 将uuid转回bytes
+	 *
+	 * @param str
+	 * @return
+	 */
+	public static byte[] byteArrayFromUuid(String str) {
+		UUID uuid = UUID.fromString(str);
+		ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
+		bb.putLong(uuid.getMostSignificantBits());
+		bb.putLong(uuid.getLeastSignificantBits());
+
+		return bb.array();
+	}
+
+	/**
+	 * 将UUID转为bytes
+	 *
+	 * @param uuid
+	 * @return
+	 */
+	public static byte[] uuidToByte(UUID uuid) {
+		ByteArrayOutputStream ba = new ByteArrayOutputStream(16);
+		DataOutputStream da = new DataOutputStream(ba);
+		try {
+			da.writeLong(uuid.getMostSignificantBits());
+			da.writeLong(uuid.getLeastSignificantBits());
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return ba.toByteArray();
+	}
+
+	/**
+	 * 将byte转为二进制
+	 *
+	 * @param b
+	 * @return
+	 */
+	public static String byteToBit(byte b, boolean revers) {
+		String str = Integer.toBinaryString(b);
+		if (str.length() < 8) {
+			str = StringUtilsByYC.addString(String.valueOf(str), "0", 8, "L");
+		}
+		if (revers == true) {
+			StringBuffer sb = new StringBuffer();
+			for (int i = str.length() - 1; i >= 0; i--) {
+				sb.append(str.charAt(i));
+			}
+			str = sb.toString();
+		}
+
+		return str;
+	}
+
+
+}

+ 141 - 0
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtilsByYC.java

@@ -0,0 +1,141 @@
+package org.dromara.common.core.utils;
+
+/**
+ * @author Hz
+ * @date 2025/1/16
+ * @description TODO
+ */
+public class StringUtilsByYC {
+    public static final String EMPTY = "";
+
+    /**
+     * 判断字符串是否是整数
+     *
+     * @param number
+     * @return
+     */
+    public static boolean isInteger(String number) {
+        boolean isNumber = false;
+        if (StringUtils.isNotEmpty(number)) {
+            isNumber = number.matches("^([1-9]\\d*)|(0)$");
+        }
+        return isNumber;
+    }
+
+    /**
+     * 判断字符串不为空
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isNotEmpty(String str) {
+        boolean isNotEmpty = false;
+        if (str != null && !str.trim().equals("") && !str.trim().equalsIgnoreCase("NULL")) {
+            isNotEmpty = true;
+        }
+        return isNotEmpty;
+    }
+
+    /**
+     * 判断字符串为空
+     *
+     * @param str
+     * @return
+     */
+    public static boolean isEmpty(String str) {
+        return !isNotEmpty(str);
+    }
+
+    /**
+     * 将数组转成SQL认识的字符串 123,432,2312 id in('123','432','2312')
+     *
+     * @param ids
+     * @return
+     */
+    public static String fromArrayToStr(String[] ids) {
+        StringBuffer str = new StringBuffer();
+        for (int i = 0; i < ids.length; i++) {
+            str.append("'" + ids[i] + "',");
+        }
+        if (ids.length > 0) {
+            str.deleteCharAt(str.length() - 1);
+        }
+        return str.toString();
+    }
+
+    /**
+     * 去掉指定字符串的最后一位
+     *
+     * @param string 要处理的字符串
+     * @return 处理后的字符串
+     */
+    public static String trimLast(String string) {
+        return string.substring(0, string.length() - 1);
+    }
+
+    /**
+     * addString:将指定的基础字符串补充指定的字符,以达到指定的长度.
+     *
+     * @param base 要补充的基础字符串
+     * @param add  填充的字符
+     * @param len  填充后的总长度,如果填充后的总长度小于基础字符串的长度则不进行处理
+     * @param pos  填充的位置,L向左填充 R向右填充
+     * @return 填充后的字符串
+     * @throws @since JDK 1.8
+     * @author luoyibo
+     */
+    public static String addString(String base, String add, Integer len, String pos) {
+        StringBuffer sBuffer = new StringBuffer();
+        String reString = base;
+        Integer addLen = len - base.length();
+        if (addLen > 0) {
+            for (int i = 0; i < addLen; i++) {
+                sBuffer.append(add);
+            }
+            if (pos.toUpperCase().equals("L"))
+                reString = sBuffer.toString() + reString;
+            else
+                reString = reString + sBuffer.toString();
+        }
+        return reString;
+    }
+
+    /**
+     * 替换文本内容
+     * @param base
+     * @param add 替换的字符
+     * @param start 起始位置(从0开始,包含)
+     * @param end 结束位置(不包含)
+     * @return
+     */
+    public static String replaceString(String base, String add, Integer start, Integer end) {
+        StringBuffer sBuffer = new StringBuffer();
+        Integer addLen = base.length();
+        if (addLen > 0) {
+            for (int i = 0; i < addLen; i++) {
+                if (start <= i && end > i) {
+                    sBuffer.append(add);
+                } else {
+                    sBuffer.append(base.charAt(i));
+                }
+            }
+
+        }
+        return sBuffer.toString();
+    }
+
+    /**
+     * 检查指定的字符串列表是否不为空。
+     */
+    public static boolean areNotEmpty(String... values) {
+        boolean result = true;
+        if (values == null || values.length == 0) {
+            result = false;
+        } else {
+            for (String value : values) {
+                result &= !isEmpty(value);
+            }
+        }
+        return result;
+    }
+}

+ 10 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/wx/contorller/WxController.java

@@ -66,4 +66,14 @@ public class WxController extends BaseController {
         Long userId = LoginHelper.getUserId();
         return wxService.uploadUserPhoto(userId, imgData);
     }
+
+    /**
+     * 获取身份码
+     * @return
+     */
+    @GetMapping("/getIdCode")
+    public R<String> getIdCode() {
+        Long userId = LoginHelper.getUserId();
+        return wxService.getIdCode(userId);
+    }
 }

+ 2 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/wx/service/IWxService.java

@@ -22,4 +22,6 @@ public interface IWxService {
     boolean updateCardStatus(Long userId, String cardStatus);
 
     R<String> uploadUserPhoto(Long userId, String imgData);
+
+    R<String> getIdCode(Long userId);
 }

+ 68 - 0
ruoyi-modules/ruoyi-backstage/src/main/java/org/dromara/backstage/wx/service/impl/WxServiceImpl.java

@@ -11,9 +11,11 @@ import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import com.arcsoft.face.FaceInfo;
 import com.arcsoft.face.toolkit.ImageInfo;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.time.DateFormatUtils;
 import org.dromara.backstage.cardCenter.domain.PtCard;
 import org.dromara.backstage.cardCenter.mapper.PtCardMapper;
 import org.dromara.backstage.consumption.mapper.XfCreditAccountMapper;
@@ -26,7 +28,9 @@ import org.dromara.backstage.wx.service.FaceEngineService;
 import org.dromara.backstage.wx.service.IWxService;
 import org.dromara.common.core.domain.R;
 import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.ByteArrayUtilByYC;
 import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtilsByYC;
 import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.system.api.RemoteDictService;
@@ -38,6 +42,7 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -273,4 +278,67 @@ public class WxServiceImpl implements IWxService {
         return imageBytes;
     }
 
+    @Override
+    public R<String> getIdCode(Long userId) {
+        //根据userId 查询卡片信息
+        PtCard card = cardMapper.selectOne(new LambdaQueryWrapper<PtCard>().eq(PtCard::getUserId, userId));
+        if(ObjectUtil.isEmpty(card) || ObjectUtil.isEmpty(card.getFactoryId())){
+            return R.fail("该用户未领取卡片");
+        }else {
+            return  R.ok(getCode(card.getFactoryId()));
+        }
+    }
+
+    /**
+     *物理卡号转二维码数据
+     * @param fixId
+     * @return
+     */
+    private  static String getCode(Long fixId)
+    {
+        //Long fixId=123456789l;
+
+        String fixStr=Long.toHexString(fixId);
+        if(fixStr.length()<8)
+            fixStr= StringUtilsByYC.addString(fixStr, "0",8, "L");
+        byte[] fixBytes= ByteArrayUtilByYC.parseHexStr2Byte(fixStr);
+
+        //当前时间
+        String time= DateFormatUtils.format(new Date(), "yy-MM-dd-HH-mm-ss");
+        String[] timeStrs=time.split("-");
+
+        byte[] bytes=new byte[15];
+        bytes[0]=0;
+        ByteArrayUtilByYC.copy(fixBytes , 0, bytes, 1, 4);
+        bytes[5]=Byte.valueOf(timeStrs[5]);
+        bytes[6]=Byte.valueOf(timeStrs[0]);
+        bytes[7]=Byte.valueOf(timeStrs[1]);
+        bytes[8]=Byte.valueOf(timeStrs[2]);
+        bytes[9]=Byte.valueOf(timeStrs[3]);
+        bytes[10]=Byte.valueOf(timeStrs[4]);
+        bytes[11]=10;
+        bytes[12]=5;
+        bytes[13]=100;
+        bytes[14]=0;
+
+        //计算crc校验值
+        byte crcByte=0;
+        for(int i=0;i<bytes.length;i++) {
+            crcByte=(byte) ((crcByte^(bytes[i]))&0xFF);
+        }
+
+        //加密后9个字节
+        bytes[5]=(byte) ((bytes[0]^bytes[5])&0xFF);
+        bytes[6]=(byte) ((bytes[1]^bytes[6])&0xFF);
+        bytes[7]=(byte) ((bytes[2]^bytes[7])&0xFF);
+        bytes[8]=(byte) ((bytes[3]^bytes[8])&0xFF);
+        bytes[9]=(byte) ((bytes[4]^bytes[9])&0xFF);
+        bytes[10]=(byte) ((bytes[0]^bytes[10])&0xFF);
+        bytes[11]=(byte) ((bytes[1]^bytes[11])&0xFF);
+        bytes[12]=(byte) ((bytes[2]^bytes[12])&0xFF);
+        bytes[13]=(byte) ((bytes[3]^bytes[13])&0xFF);
+        bytes[14]=crcByte;
+
+        return ByteArrayUtilByYC.parseByte2HexStr(bytes, false);
+    }
 }