diff --git a/basic-util/src/main/java/ink/wgink/util/verification/share/ShareCodeUtil.java b/basic-util/src/main/java/ink/wgink/util/verification/share/ShareCodeUtil.java new file mode 100644 index 00000000..9979b4e4 --- /dev/null +++ b/basic-util/src/main/java/ink/wgink/util/verification/share/ShareCodeUtil.java @@ -0,0 +1,124 @@ +package ink.wgink.util.verification.share; + +import java.util.Arrays; + +/** + * When you feel like quitting. Think about why you started + * 当你想要放弃的时候,想想当初你为何开始 + * + * @ClassName: ShareCodeUtil + * @Description: 分享码,全局唯一,长度6位 + * @Author: wanggeng + * @Date: 2021/5/2 11:58 上午 + * @Version: 1.0 + */ +public class ShareCodeUtil { + + /** + * 随机字符串 + */ + private static final char[] CHARS = new char[]{'F', 'L', 'G', 'W', '5', 'X', 'C', '3', + '9', 'Z', 'M', '6', '7', 'Y', 'R', 'T', '2', 'H', 'S', '8', 'D', 'V', 'E', 'J', '4', 'K', + 'Q', 'P', 'U', 'A', 'N', 'B'}; + + private final static int CHARS_LENGTH = 32; + /** + * 邀请码长度 + */ + private final static int CODE_LENGTH = 6; + /** + * 随机数据 + */ + private final static long SLAT = 1234561L; + /** + * PRIME1 与 CHARS 的长度 L互质,可保证 ( id * PRIME1) % L 在 [0,L)上均匀分布 + */ + private final static int PRIME1 = 3; + + /** + * PRIME2 与 CODE_LENGTH 互质,可保证 ( index * PRIME2) % CODE_LENGTH 在 [0,CODE_LENGTH)上均匀分布 + */ + private final static int PRIME2 = 11; + + /** + * 生成邀请码 + * + * @param id 唯一的id主键 + * @return code + */ + public static String gen(Long id) { + //补位 + id = id * PRIME1 + SLAT; + //将 id 转换成32进制的值 + long[] b = new long[CODE_LENGTH]; + //32进制数 + b[0] = id; + for (int i = 0; i < CODE_LENGTH - 1; i++) { + b[i + 1] = b[i] / CHARS_LENGTH; + //按位扩散 + b[i] = (b[i] + i * b[0]) % CHARS_LENGTH; + } + b[5] = (b[0] + b[1] + b[2] + b[3] + b[4]) * PRIME1 % CHARS_LENGTH; + + //进行混淆 + long[] codeIndexArray = new long[CODE_LENGTH]; + for (int i = 0; i < CODE_LENGTH; i++) { + codeIndexArray[i] = b[i * PRIME2 % CODE_LENGTH]; + } + + StringBuilder buffer = new StringBuilder(); + Arrays.stream(codeIndexArray).boxed().map(Long::intValue).map(t -> CHARS[t]).forEach(buffer::append); + return buffer.toString(); + } + + /** + * 将邀请码解密成原来的id + * + * @param code 邀请码 + * @return id + */ + public static Long decode(String code) { + if (code.length() != CODE_LENGTH) { + return null; + } + //将字符还原成对应数字 + long[] a = new long[CODE_LENGTH]; + for (int i = 0; i < CODE_LENGTH; i++) { + char c = code.charAt(i); + int index = findIndex(c); + if (index == -1) { + //异常字符串 + return null; + } + a[i * PRIME2 % CODE_LENGTH] = index; + } + + long[] b = new long[CODE_LENGTH]; + for (int i = CODE_LENGTH - 2; i >= 0; i--) { + b[i] = (a[i] - a[0] * i + CHARS_LENGTH * i) % CHARS_LENGTH; + } + + long res = 0; + for (int i = CODE_LENGTH - 2; i >= 0; i--) { + res += b[i]; + res *= (i > 0 ? CHARS_LENGTH : 1); + } + return (res - SLAT) / PRIME1; + } + + /** + * 查找对应字符的index + * + * @param c 字符 + * @return index + */ + private static int findIndex(char c) { + for (int i = 0; i < CHARS_LENGTH; i++) { + if (CHARS[i] == c) { + return i; + } + } + return -1; + } + +}