由于以前也做过很多兑换码的功能,但是也没有考虑过大量的兑换码的情况,所以这里尝试实现了一个生成与兑换的方案,分享出来。当然这不一定是最好的解决方案,这里仅供大家参考。有什么问题或可以优化的地方欢迎留言讨论。
*此方案可以根据输入的兑换码数量以及兑换码的字符长度来生成兑换码,每次生成兑换码的最大数量为int的最大值,一般为2147483647,即21亿个。
*此方案不需要数据库存储已生成的兑换码,直接使用验证算法即可验证兑换码是否有效。
*注意此算法的最短兑换码长度为12。这里可以根据需求对兑换码的结构进行调整来减少此长度。
首先说下思路
每一位兑换码有4部分构成:
[类型(1),id(4),随机码(n),校验码(1)]
类型为每次生成兑换码的组id,这里只用了1个byte来存储,可以根据需要增加。
id为每次生成的每个兑换码的唯一id。
随机码为每个兑换码的随机数。
校验码用来在验证兑换码时进行校验。
生成过程:
1.根据输入的兑换码总长度计算出随机码的位数,然后对每一位随机赋值。
2.把类型,id和随机码组成一个byte数组,计算总和,然后对byte.max进行取余运算,结果最为校验码。把校验码放在数组最末尾。
3.因为前面的时间和id有一定的规律性,我们使用随机码对时间和id进行异或操作,使兑换码看起来没有规律。
4.为了更加安全,我们使用一个密码对全部数据按顺序进行异或运算,这样即使知道了算法,在不知道密码的情况些也很难对数据进行破解。
5.我们使用32位的编码表来表示二进制数据,但是每个byte位长度为8,能表示127个数据,所以这里我们要对原数据进行拆分,32位编码表只需要5位就能表示,所以这里我们把原byte数组拆分为每5位为一个byte。如图:
红色部分直接补0,末尾不足的部分也补充为0.这样一位数据就可以正好对应编码表中的一个数据。
6.把我们重新整理好的byte数组按照编码表转换位字符串就是我们最终的兑换码。
验证的过程就是把生成的过程反过来执行一遍。
下面给出完整代码:
public class Redeem {
static String stringtable = "abcdefghijkmnpqrstuvwxyz23456789";
final static String password = "dak3le2";
//从byte转为字符表索引所需要的位数
final static int convertByteCount = 5;
public static void main( String[] args ) throws Exception
{
ShowTime();
System.out.println("=======&#