需求:
-
大写字母+数字,排除 O I (大写 o i )
-
预计长度 20 个字符,例如 AAAAA-BBBBB-CCCCC-DDDDD
-
码中需要具有校验算法
-
代码实现 一共 4组数据,每组根据前4位生成第五位数据。
生成规则: 大写字母+数字,排除 O I (大写 o i ) 还剩下34位字符 将每个字符和 0-33 数字关联(map实现) 然后将每4位数字按照进制算法然后取模34(我这里又加了常量系数)得到第5位数字,通过数字拿到应字符。 通过初始化将数据库码查到内存中,生成的时候如若冲突,重新生成即可。 校验规则: 按照生成规则,每4位生成一次与输入码进行比较
/**
* @autor
* 兑换码生成工具
*/
@Slf4j
public class GenerateRedemption {
//保存码和对应数字信息
private static final Map<Integer, String> CHARARTER_MAP = new HashMap<>();
//验证是否与数据库已存在的兑换码重复
public static Set<String> redeemCodeSet = new HashSet<>();
private static final int COUNT_1 = 11;
private static final int COUNT_2 = 22;
private static final int COUNT_3 = 33;
private static final int COUNT_4 = 44;
private static final int COUNT_5 = 55;
private static final int COUNT_6 = 66;
private static final int COUNT_7 = 77;
private static final int COUNT_8 = 88;
private static final int COUNT_9 = 99;
private static final int COUNT_10 = 1010;
private static final int COUNT_11 = 1111;
private static final int COUNT_12 = 1212;
private static final int COUNT_13 = 1313;
private static final int COUNT_14 = 1414;
private static final int COUNT_15 = 1515;
private static final int COUNT_16 = 1616;
static {
//将数字和大写字母()按照顺序放在map中
CHARARTER_MAP.put(0, "0");
CHARARTER_MAP.put(1, "1");
CHARARTER_MAP.put(2, "2");
CHARARTER_MAP.put(3, "3");
CHARARTER_MAP.put(4, "4");
CHARARTER_MAP.put(5, "5");
CHARARTER_MAP.put(6, "6");
CHARARTER_MAP.put(7, "7");
CHARARTER_MAP.put(8, "8");
CHARARTER_MAP.put(9, "9");
CHARARTER_MAP.put(10, "A");
CHARARTER_MAP.put(11, "B");
CHARARTER_MAP.put(12, "C");
CHARARTER_MAP.put(13, "D");
CHARARTER_MAP.put(14, "E");
CHARARTER_MAP.put(15, "F");
CHARARTER_MAP.put(16, "G");
CHARARTER_MAP.put(17, "H");
CHARARTER_MAP.put(18, "J");
CHARARTER_MAP.put(19, "K");
CHARARTER_MAP.put(20, "L");
CHARARTER_MAP.put(21, "M");
CHARARTER_MAP.put(22, "N");
CHARARTER_MAP.put(23, "P");
CHARARTER_MAP.put(24, "Q");
CHARARTER_MAP.put(25, "R");
CHARARTER_MAP.put(26, "S");
CHARARTER_MAP.put(27, "T");
CHARARTER_MAP.put(28, "U");
CHARARTER_MAP.put(29, "V");
CHARARTER_MAP.put(30, "W");
CHARARTER_MAP.put(31, "X");
CHARARTER_MAP.put(32, "Y");
CHARARTER_MAP.put(33, "Z");
}
private GenerateRedemption(IRedeemCodeService redeemCodeService) {
//初始化数据库兑换码数据(就是将数据库中已存在的数据查出来)
redeemCodeSet = redeemCodeService.redeemCodeSet();
}
//单例
private static GenerateRedemption g = null;
public static synchronized GenerateRedemption getInstance(IRedeemCodeService redeemCodeService) {
if (g == null) {
g = new GenerateRedemption(redeemCodeService);
}
return g;
}
/**
*
* @param count //码生成数量
* @return
*/
public List<String> getCode(int count) {
StringBuilder stringBuilder = new StringBuilder();
List<String> redeemCodeList = new ArrayList<>();
List<Integer> integers = new ArrayList<>();
while (count > 0) {
for (int i = 0; i < 20; i++) {
Random random = new Random();
int index = random.nextInt(34);
if ((i + 1) % 5 == 0) {
stringBuilder.append(getCheckCode(integers, i));
integers.clear();
} else {
integers.add(i);
stringBuilder.append(CHARARTER_MAP.get(index));
}
}
String currentRedeemCode = stringBuilder.toString().trim();
if (redeemCodeSet.add(currentRedeemCode)) {
redeemCodeList.add(currentRedeemCode);
count--;
}
stringBuilder.setLength(0);
}
return redeemCodeList;
}
//一共 4组数据,每组根据前4位生成第五位数据
private static String getCheckCode(List<Integer> integers, Integer index) {
Integer checkCode = 0;
switch (index) {
case 4:
checkCode = (integers.get(0) * (34 ^ 3) * COUNT_1 + integers.get(1) * (34 ^ 2) * COUNT_2 + integers.get(2) * (34 ^ 1) * COUNT_3 + integers.get(3) * (34 ^ 0) * COUNT_4) % 34;
break;
case 9:
checkCode = (integers.get(0) * (34 ^ 3) * COUNT_5 + integers.get(1) * (34 ^ 2) * COUNT_6 + integers.get(2) * (34 ^ 1) * COUNT_7 + integers.get(3) * (34 ^ 0) * COUNT_8) % 34;
break;
case 14:
checkCode = (integers.get(0) * (34 ^ 3) * COUNT_9 + integers.get(1) * (34 ^ 2) * COUNT_10 + integers.get(2) * (34 ^ 1) * COUNT_11 + integers.get(3) * (34 ^ 0) * COUNT_12) % 34;
break;
case 19:
checkCode = (integers.get(0) * (34 ^ 3) * COUNT_13 + integers.get(1) * (34 ^ 2) * COUNT_14 + integers.get(2) * (34 ^ 1) * COUNT_15 + integers.get(3) * (34 ^ 0) * COUNT_16) % 34;
break;
default:
break;
}
log.info("checkCode 是", checkCode);
return CHARARTER_MAP.get(checkCode);
}
public boolean checkCode(String redeemCode) {
if (redeemCode.length() != 20) {
return false;
}
char[] redeemCodeChar = redeemCode.toCharArray();
List<Integer> integers = new ArrayList<>();
for (char c : redeemCodeChar) {
if (!CHARARTER_MAP.containsValue(String.valueOf(c))) {
return false;
}
int i = 0;
for (Map.Entry<Integer, String> e : CHARARTER_MAP.entrySet()) {
if (e.getValue().equals(c)) {
integers.add(e.getKey());
i++;
if ((i + 1) % 5 == 0) {
if (!getCheckCode(integers, i).equals(String.valueOf(c))) {
return false;
}
integers.clear();
}
}
}
}
return true;
}
}