兑换码,激活码算法包括码生成,码校验算法,(java 20位,可修改)

4,203 阅读1分钟

需求:

  • 大写字母+数字,排除 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;
    }


}