8、9位用户ID生成加密ID、解密算法
我们可能需要对某些用户的真实数字ID进行加密,让加密后的ID长度还是那么多,又要可恢复,可一眼认出是个加密ID,因此我设计了一种加解密方法,可对8、9位数字ID做加密,加密后的ID长度9位,包含一个字母,其余均是数字,且无法发现加密前后两ID的规律,加密工具如下。
System.out.println(UserIdEncodeUtil.encodeID(52113075L));
System.out.println(UserIdEncodeUtil.encodeID(92113075L));
System.out.println(UserIdEncodeUtil.encodeID(521130751L));
System.out.println(UserIdEncodeUtil.encodeID(921130751L));
u80768999
N59508377
1u8076899
1N5950837
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 8、9位数字ID加密、解密工具
*
* @author humorchen
* @date 2022/3/16 13:48
*/
public class UserIdEncodeUtil {
/**
* 最小ID(8位)
*/
private static int MIN_ID = 10000000;
/**
* 最大ID(9亿9)
*/
private static int MAX_ID = 999999999;
/**
* 最多26*2=52个字母
*/
private static char[] CHARS = new char[52];
/**
* 不使用的字母集合
*/
private static List<Character> BAN_CHARS = Arrays.asList('O', 'o', 'l');
/**
* 字母和字母数组下标的映射
*/
private static Map<Character, Integer> CHAR_INDEX_MAP = new HashMap<>(52);
/**
* 初始化字符数组和映射map
*/
static {
fillAlphabet('a', 'z');
fillAlphabet('A', 'Z');
}
/**
* 从form到to的字符填充到数组和映射map里去
*
* @param from
* @param to
*/
private static void fillAlphabet(char from, char to) {
for (int i = from; i <= to; i++) {
char c = (char) i;
if (BAN_CHARS.contains(c)) {
continue;
}
int index = CHAR_INDEX_MAP.size();
CHARS[index] = c;
CHAR_INDEX_MAP.put(c, index);
}
}
/**
* 编码ID数字
*
* @param n
* @return
*/
private static int encode(int n) {
int ret = 0;
if (n < 16777217) {
n = (n << 2) | 3;
} else {
n = n << 2 | 1;
}
while (n > 0) {
ret = (ret << 1) | (n & 1);
n = n >> 1;
}
return ret;
}
/**
* 解码ID的数字
*
* @param n
* @return
*/
private static int decode(int n) {
int ret = 0;
while (n > 0) {
ret = (ret << 1) | (n & 1);
n = n >> 1;
}
ret = ret >> 2;
return ret;
}
/**
* 编码后的数字转换为字符串显示
*
* @param n
* @return
*/
private static String nToString(int n) {
StringBuilder sb = new StringBuilder();
sb.append(n);
if (sb.length() == 9) {
//有9位,则前面两位数字做字符值小写、大写52个位置
sb.delete(0, 2);
int i = n / 10000000;
sb.insert(0, CHARS[i]);
} else {
//8位数,最后一位变d+最前面第一个数字,第一位就变字母了,还原的时候字符值-d即可(d是100)
int i = n % 10;
sb.setCharAt(7, (char) ('d' + i));
}
return sb.toString();
}
/**
* 编码后的ID转换回被加密的数字
*
* @param id
* @return
*/
private static int stringToN(String id) {
char fist = id.charAt(0);
char last = id.charAt(id.length() - 1);
int n = -1;
if (fist >= 'A') {
//是第一个为字母
n = CHAR_INDEX_MAP.get(fist) * 10000000 + Integer.parseInt(id.substring(1));
} else if (last >= 'a') {
//最后一个位字母(去掉最后一位变数字乘以10+最后一位的数字)
n = Integer.parseInt(id.substring(0, id.length() - 1)) * 10 + last - 'd';
}
return n;
}
/**
* 编码8位数字ID
*
* @param n
* @return
*/
private static String encode8ID(int n) {
return nToString(encode(n));
}
/**
* 解码8位ID
*
* @param n
* @return
*/
private static int decode8ID(String n) {
return decode(stringToN(n));
}
/**
* 加密8、9位数字ID
*
* @param id
* @return
*/
public static String encodeID(Long id) {
//参数校验
if (id == null || id < MIN_ID || id > MAX_ID) {
return "";
}
int n = id.intValue();
int nine = 100000000;
//9位ID
StringBuilder sb = new StringBuilder(9);
//九位ID
if (n >= nine) {
//取前8位
int eight = n / 10;
//最后一位数
int last = n % 10;
//加密前8位
String eightID = encode8ID(eight);
sb.append(eightID);
if (eightID.charAt(0) >= 'A') {
//第一位是字母
sb.insert(0, last);
} else {
//最后一位是字母
sb.append(last);
}
} else {
//八位ID
String eightID = encode8ID(n);
sb.append(eightID);
if (eightID.charAt(0) >= 'A') {
//第一位是字母则补最后一位
sb.append(eightID.charAt(eightID.length() - 1));
} else {
//最后一位是字母就补第一位
sb.insert(0, eightID.charAt(0));
}
}
return sb.toString();
}
/**
* 解码8、9位ID
*
* @param id
* @return
*/
public static Long decodeID(String id) {
//提前拦截非法ID字符串
if (id == null || id.length() != 9) {
return -1L;
}
boolean first = id.charAt(0) >= 'A', last = id.charAt(8) >= 'A';
int ret = -1;
try {
if (first || last) {
//第一位或者最后一位是字母则证明原始ID是8位的
if (first) {
//拿前面的8位去解开就是原始ID
ret = decode8ID(id.substring(0, 8));
} else if (last) {
//拿后8位去解开是原始ID
ret = decode8ID(id.substring(1));
}
} else {
//否则是9位的原始ID
if (id.charAt(1) >= 'A') {
//如果第二位是字母,解开最后8位并加上第一位
ret = decode8ID(id.substring(1)) * 10 + id.charAt(0) - '0';
} else if (id.charAt(7) >= 'A') {
//倒数第二位是字母,解开前8位并加上最后一位
ret = decode8ID(id.substring(0, 8)) * 10 + id.charAt(8) - '0';
}
}
} catch (Exception e) {
}
//拦截(还原后的ID超出范围的为-1返回,正确的ID会正确解码成功)
if (ret != -1 && (ret < MIN_ID || ret > MAX_ID)) {
}
return new Long(ret);
}
}
本文来自博客园,作者:HumorChen99,转载请注明原文链接:https://www.cnblogs.com/HumorChen/p/18039474