java生成兑换码礼包码

原创 2018年04月17日 17:44:52
import java.util.HashSet;
import java.util.Random;
import java.util.Set;


public class GenSerial {
	private static final String Base32Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
	
	/**
	 * 生成新的序列号	<br>
	 * <p>生成规则:45位的数 (二进制)<br>
	 * 		 标识位  + 数据位 + 校验位 <br>
	 * 然后将55位的数映射到用 ABCDEFGHJKLMNPQRSTUVWXYZ23456789 表示的序列号,要映射到32个字符中就是每5位代表一个字符(2^5=32),
	 * 所有生成的序列号是 45/5=9位。
	 *  
	 * @param codeLen	code长度
	 * @param flag	标识
	 * @param flagBitLen 标识长度
	 * @param checkBitLen 校验位长度
	 * @return
	 */
	public static String generateNewCode(int codeLen, int flag, int flagBitLen, int checkBitLen) {
		Long ret = 0L; // 长整形ID
		Random random = new Random();
		int checkModData = 1<<checkBitLen;
		int totalBitLen = codeLen*5;
		int dataBitLen = totalBitLen - checkBitLen - flagBitLen;
		long randData = (long)(1 + (1L<<dataBitLen - 1) * random.nextDouble());
		
		if(flagBitLen > 0){
			flag = flag & ((1<<flagBitLen) - 1);					//防止越位,若16位标识则是 0xffff
			ret += (long)flag << (totalBitLen - flagBitLen);		//高位标志位
		}
		
		ret += randData << checkBitLen; 						// 中位数据位
		long checkNum = (ret >> checkBitLen) % checkModData;	//低位校验位
		ret += checkNum; // 1 - 7位 校验位
		return convertToBase32SerialCode(ret, codeLen);
	}
	
	public static String generateNewCode(int flag, int flagBitLen) {
		return generateNewCode(9, flag, flagBitLen, 7);		//生成码9位,活动id 16位
	}
	
	public static String generateNewCode(int flag) {
		int flagBitLen = 0;
		if(flag == 0){
			flagBitLen = 0;
		}else{
			flagBitLen = Integer.toBinaryString(flag).length();
		}
		return generateNewCode(9, flag, flagBitLen, 7);		//生成码9位
	}
	
	public static String generateNewCode() {
		return generateNewCode(9, 0, 0, 7);					//生成码9位
	}
	
	/**
	 * 
	 * @param historyCodeSet	历史生成的序列号 集合
	 * @param number
	 * @param codeLen
	 * @param flag
	 * @param flagBitLen
	 * @param checkBitLen
	 * @return
	 */
	public static Set<String> generateCodes(Set<String> historyCodeSet, int number, int codeLen, int flag, int flagBitLen, int checkBitLen){
		Set<String> generatedCodes = new HashSet<String>(number*4/3+1);
		if(historyCodeSet == null){
			historyCodeSet = new HashSet<String>(0);
		}
		while(generatedCodes.size()<number){
			String code = generateNewCode(codeLen, flag, flagBitLen, checkBitLen);
			if(!historyCodeSet.contains(code)){
				generatedCodes.add(code);
			}
		}
		return generatedCodes;
	}
	
	
	/**
	 * 
	 * @param historyCodeSet
	 * @param number
	 * @return
	 */
	public static Set<String> generateCodes(Set<String> historyCodeSet, int number, int codeLen){
		return generateCodes(historyCodeSet, number, codeLen, 0, 0, 7);
	}
	
	/**
	 * 
	 * @param historyCodeSet
	 * @param number
	 * @return
	 */
	public static Set<String> generateCodes(Set<String> historyCodeSet, int number){
		return generateCodes(historyCodeSet, number, 9, 0, 0, 7);
	}
	

	/**
	 * 将随机数转换成BASE32编码 序列码
	 * 
	 * @return
	 */
	private static String convertToBase32SerialCode(long longRandValue, int codeLen) {
		StringBuffer codeSerial = new StringBuffer(16);
		long tmpRandValue = longRandValue;
		for (int i = 0; i < codeLen; i++) {
			int code = (int) (tmpRandValue & 0x1F);
			char convertCode = Base32Alphabet.charAt(code);
			codeSerial.append(convertCode);
			tmpRandValue = tmpRandValue >> 5;
		}
		return codeSerial.reverse().toString();
	}
	
	
	/**
	 * 将兑换码序列字符转化成数字。
	 * 
	 * @return
	 */
	private static int convertBase32CharToNum(char ch) {
		int index = Base32Alphabet.indexOf(ch);
		return index;
	}
	
	/**
	 * 将序列号转成长整数
	 * 
	 * @return
	 */
	public static long convertBase32CharToNum(String serialCode) {
		long id = 0;

		for (int i = 0; i < serialCode.length(); i++) {
			int originNum = convertBase32CharToNum(serialCode.charAt(i));
			if(originNum == -1){
				return 0;
			}
			id = id << 5;
			id += originNum;
		}
		return id;
	}

	/**
	 * 校验序列号是否合法
	 * 
	 * @param code
	 * @return
	 */
	public static boolean checkCodeValid(String code, int checkBitLen) {
		long id = 0;
		int checkModData = 1<<checkBitLen;
		for (int i = 0; i < code.length(); ++i) {
			long originNum = convertBase32CharToNum(code.charAt(i));
			if (originNum >= 32)
				return false; // 字符非法
			id = id<<5;
			id += originNum;
		}

		long data = id >> checkBitLen;
		long checkNum = id & (checkModData-1); // 最后7位是校验码

		if (data % checkModData == checkNum)
			return true;

		return false;
	}
	
	public static boolean checkCodeValid(String code) {
		if(code == null || code.length() == 0){
			return false;
		}
		return checkCodeValid(code, 7);
	}
	
	/**
	 * 从序列号提取标识
	 * 
	 * @param code	序列号
	 * @param flagBitLen	标识位长度
	 * @return
	 */
	public static Long getFlagFromCode(String code, int flagBitLen){
		long id = convertBase32CharToNum(code);
		return id >> (code.length()*5-flagBitLen);	
	}
	
	public static void main(String[] args) {
		System.out.println(checkCodeValid("ARXX2BWTE"));
		long sTime = System.currentTimeMillis();
		long eTime = 0L; 
		
		Set<String> codes = generateCodes(null, 7000000, 9, 0, 0, 7);
		eTime = System.currentTimeMillis();
		System.out.println("耗时 " + (eTime-sTime)/1000 + "秒");
		sTime = eTime;
		
		Set<String> codes2 = generateCodes(codes, 2000000, 9, 0, 0, 7);
		codes2.size();
		eTime = System.currentTimeMillis();
		System.out.println("耗时 " + (eTime-sTime)/1000 + "秒");
		
		String code = generateNewCode(1,10);
		System.out.println("序列号: "+code);
		boolean checkRs = checkCodeValid(code);
		System.out.println("序列号" + code + "是否合法:" + checkRs);
		long acId = getFlagFromCode(code,10);
		System.out.println("标识: " + acId);
		long numCode = convertBase32CharToNum(code);
		System.out.println("数字序列号 " + numCode);
		
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/z100871519/article/details/79978165

js<em>生成</em>条形码(真实可用)

js <em>生成</em>一维码(条形码) jquery使用barcode<em>生成</em>条形码 JsBarcode.all.js 立即下载...购买C币<em>兑换</em>积分 C币抽奖 资源所需积分/C币 当前拥有积分 当前拥有C币 5 4...
  • 2018年04月17日 00:00

怎样让Ant编译<em>生成</em>的字节码带<em>实际</em>参数信息,不是arg0之类

怎样让Ant编译<em>生成</em>的字节码带<em>实际</em>参数信息,不是arg0之类 会员到期时间: 剩余...购买C币<em>兑换</em>积分 C币抽奖 资源所需积分/C币 当前拥有积分 当前拥有C币 5 4...
  • 2018年04月17日 00:00

游戏礼包激活码案例分析

最近我们游戏有一个礼激活码的
  • RexGene
  • RexGene
  • 2014-11-11 14:30:29
  • 1379

对于卡券类兑换的,随机生成兑换码

package com.test; import java.util.Random; public class RedeemCodeUtils { public static void main...
  • wanghang88
  • wanghang88
  • 2017-08-24 01:33:17
  • 874

Kinglot代码<em>生成</em>器及<em>实际</em>项目应用(ASP.NET)

点击完成任务获取下载码 输入下载码 为了良好体验,...购买C币<em>兑换</em>积分 C币抽奖 资源所需积分/C币 当前...Kinglot代码<em>生成</em>器及<em>实际</em>项目应用(ASP.NET) 3积分 ...
  • 2018年04月15日 00:00

再谈非重复随机序列号生成算法

这段时间项目中又要开发兑换码功能,此前的项目已经开发过,但是为了保证这个功能在将来的可重复利用,我决定重构一下相关模块。原来的模块不是我开发的,但也已经可以完成这个要求。但其中存在两个问题,这也是基本...
  • duotemplar
  • duotemplar
  • 2017-08-16 11:51:23
  • 232

Java生成随机码(兑换码),带大小、小写字母、数字。

import java.util.Random; public class RandomString { /*** * 产生随机数的方法 * * @param len...
  • u012233421
  • u012233421
  • 2016-11-07 20:55:37
  • 1860

php批量生成200条8位兑换码

应公司需求,需要一次性生成200条兑换码,这个算是固定公式了,所以在此记录一下,以后有需要的话,我自己也能直接拿来用。一、兑换码生成的方式: /* * * 生成随机的兑换码 * */...
  • LJFPHP
  • LJFPHP
  • 2017-10-17 22:42:11
  • 502

GitHub上创建工程及代码提交、更新等相关操作

GitHub上创建工程及clone和push相关操作
  • skylin19840101
  • skylin19840101
  • 2017-03-15 12:01:27
  • 1034

[Python]Anaconda连接mysql数据库,生成的200个激活码保存在数据库

Anaconda连接Mysql数据库,主要分为两步:1.安装mysql,这里注意mysql的版本不要超过5.5,可直接在百度栏搜索出现的mysql版本是最新的,要加上版本进行搜索,我给出我下载的链接,...
  • danation
  • danation
  • 2017-07-29 16:05:30
  • 1236
收藏助手
不良信息举报
您举报文章:java生成兑换码礼包码
举报原因:
原因补充:

(最多只允许输入30个字)