最近在做一个电商的项目,其中的一个业务是生成积分券,相信大家都知道,积分券是又一系列的不同的字母和数字组成。这个看起来也不是很难,生成不重复的随机数啦。细想一下视乎还少了一些逻辑,既不能与生成中的重复,也不能和数据库中已有的重复。好了,不啰嗦了,下面咱们看具体实现。
理清逻辑
- 将已有的进行查找
- 生成之前和现有的对比
- 进行保存
当然了生成随机数有多种方式,这里我就使用一种简单的HashSet方法。
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 单例工具类,用于生成积分券(由数字和字母组成)
* @author hanyankun
*
*
*/
public class GenerateRandomNumber {
private GenerateRandomNumber() {
}
private volatile static GenerateRandomNumber instanceGenerateRandomNumber = null;
private static Lock lock = new ReentrantLock();
/**
* 单例模式 ,doubleCheck
*
* @return GenerateRandomNumber
*/
public static GenerateRandomNumber getInstance() {
if (null == instanceGenerateRandomNumber) {
lock.lock();
if (null == instanceGenerateRandomNumber) {
instanceGenerateRandomNumber = new GenerateRandomNumber();
}
lock.unlock();
}
return instanceGenerateRandomNumber;
}
/**
* 生成随机数字和字母组合
*
* @param length
* 字符的长度
* @param numSize
* 总的个数
* @param merchantIntegre 用于存储积分券集合
*/
public void getCharAndNumr(int length, int numSize,
HashSet<String> merchantIntegre) {
//第一层循环用于生成积分券个数,第二层用于组合积分码
for (int j = 0; j < numSize; j++) {
String val = new String("");
Random random = new Random();
//积分码生成
for (int i = 0; i < length; i++) {
// 输出字母还是数字
String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
// 字符串
if ("char".equalsIgnoreCase(charOrNum)) {
// 取得大写字母还是小写字母
int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char) (choice + random.nextInt(26));
} else if ("num".equalsIgnoreCase(charOrNum)) { // 数字
val += String.valueOf(random.nextInt(10));
}
}
merchantIntegre.add(val);
}
// 首次循环完成,可能有重复值,生成的字符串总数小于原有,递归循环再次生成。
while (merchantIntegre.size() < numSize) {
numSize = numSize - merchantIntegre.size();
// 继续循环生成
getCharAndNumr(length, numSize, merchantIntegre);
}
}
}
以上为创建的单例工具类,使用双重Lock锁方法防止多实例。getCharAndNumr方法为积分券生成方法。
单元测试
我们模拟一种数据库已经有部分数据,再次生成一部分数据
public class GenerateRandomNumberTest {
HashSet<String> merchantSet = new HashSet<String>(); // 仿真数据库数据
int length = 10; //生成的积分券长度
int numSize = 1024; //数据库中已有1024条数据
@Before
public void setUp() throws Exception {
GenerateRandomNumber.getInstance().getCharAndNumr(length, numSize,
merchantSet);
System.out.println("数据库原有积分券个数是:"+merchantSet.size() +" ");
}
@Test
public void testGetCharAndNumrIntIntHashSetOfString() {
HashSet<String> merchantSet2 = new HashSet<String>(); // 仿真数据库数据
merchantSet2.addAll(merchantSet) ; //临时存储数据库查询到的数据(浅拷贝)
//再次生成1万个积分券,但是总个数却是11024个
GenerateRandomNumber.getInstance().getCharAndNumr(10, 10000,
merchantSet);
System.out.println("生成的积分券总个数是: "+merchantSet.size());
//因为传入时已经带有部分数据, 需要删除原有数据
merchantSet.removeAll(merchantSet2); //删除数据库中原有数据, 保留新增数据
System.out.println("新增积分券个数是: "+merchantSet.size());
}
}
打印数据为:
总结:
总体来说,用于的还是最基本的java基础,随机数,单例模式以及集合的操作,包括深拷贝与浅拷贝。基本功还是的要牢固呀。