/**
* 生成码
*/
@Component
@Slf4j
public class GenerateCodeUtils {
/**
* 默认重试次数
*/
public static final int DEFAULT_RETRY_NUM = 10;
/**
* 默认重试时间间隔
*/
public static final int DEFAULT_SLEEP_TIME = 1;
/**
* 默认自增最大数
*/
public static final int DEFAULT_MAX_NUM = 999;
/**
* 默认随机数因子
*/
public static final int DEFAULT_RANDOM_FACTOR = 5;
/**
* 默认自增数
*/
public static final int DEFAULT_DELTA = 1;
/**
* 默认随机数
*/
public static final int DEFAULT_RANDOM_NUM = 100;
private static String monthDay;
//自增开始数
private static AtomicInteger startNum = new AtomicInteger(0);
//重试次数
final int retryNum;
//重试时间间隔
final int sleepTime;
//自增最大数
final int maxNum;
//随机数因子
final int randomFactor;
//随机数
final int randomNum;
//自增数
final int delta;
public GenerateCodeUtils() {
this.retryNum = DEFAULT_RETRY_NUM;
this.sleepTime = DEFAULT_SLEEP_TIME;
this.maxNum = DEFAULT_MAX_NUM;
this.randomFactor = DEFAULT_RANDOM_FACTOR;
this.randomNum = DEFAULT_RANDOM_NUM;
this.delta = DEFAULT_DELTA;
}
/**
* @param retryNum 重试次数
* @param sleepTime 重试时间间隔
* @param maxNum 自增最大数
* @param randomFactor 随机数因子
* @param randomNum 随机数
* @param delta 自增数
*/
public GenerateCodeUtils(int retryNum, int sleepTime, int maxNum, int randomFactor, int randomNum, int delta) {
if (retryNum < 0) {
throw new IllegalArgumentException("Illegal initial retryNum: " +
retryNum);
}
if (sleepTime < 0) {
throw new IllegalArgumentException("Illegal initial sleepTime: " +
sleepTime);
}
if (maxNum <= 0) {
throw new IllegalArgumentException("Illegal initial maxNum: " +
maxNum);
}
if (randomNum <= 0) {
throw new IllegalArgumentException("Illegal initial randomNum: " +
randomNum);
}
if (delta <= 0) {
throw new IllegalArgumentException("Illegal initial delta: " +
delta);
}
this.retryNum = retryNum;
this.sleepTime = sleepTime;
this.maxNum = maxNum;
this.randomFactor = randomFactor;
this.randomNum = randomNum;
this.delta = delta;
}
public String generateCode(Function<String, Integer> function) {
LogUtil.info(log, "生成码:{}", Thread.currentThread().getName());
monthDay = getMonthDay();
// 设置返回值条件
String code = getCode(function);
if (StringUtils.isEmpty(code)) {
Predicate<String> predicate = Predicates.equalTo(null);
code = RetryUtils.guavaRetryExecute(retryNum, sleepTime, TimeUnit.SECONDS, Exception.class, () -> {
LogUtil.info(log, "开始执行可重试方法");
String resCode = getCode(function);
if (!StringUtils.isEmpty(resCode)) {
LogUtil.info(log, "重试成功");
return resCode;
}
LogUtil.info(log, "重试失败");
// 执行需重试业务逻辑
return null; // 返回值与"null"不相等,不进行重试
}, predicate, log);
}
if (StringUtils.isEmpty(code)) {
throw new BizException(CodeMsg.CODE_GENERATE_FAIL);
}
return code;
}
public String getCode(Function<String, Integer> function) {
//随机字符集
String randomStr = RandomStringUtils.getRandom(randomFactor);
//自增数,进程内(sychronize锁)分钟级自增0-999,初始数使用 100以内随机。时间超过1分钟的重新初始化。
synchronized (this) {
String newMonthDay = getMonthDay();
if (startNum.get() >= maxNum) {
startNum.set(ThreadLocalRandom.current().nextInt(randomNum));
}
if (!monthDay.equals(newMonthDay)) {
monthDay = newMonthDay;
}
String startNumStr = String.format("%03d", startNum.addAndGet(delta));
StringJoiner stringJoiner = new StringJoiner("");
String code = stringJoiner.add(monthDay).add(randomStr).add(startNumStr).toString();
Integer count = function.apply(code);
if (count > 0) {
return null;
}
return code;
}
}
public String getMonthDay() {
LocalDate date = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMdd");
return date.format(formatter);
}
}
import java.util.concurrent.ThreadLocalRandom;
/**
* 随机字符集: 小写字母 a-z(去除i/l等易与数字混淆)、0-9
*/
public class RandomStringUtils {
private static final char[] CHARS = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
/**
* 获取随机字符串
*
* @param size 长度
* @return String 随机字符串
*/
public static String getRandom(int size) {
StringBuilder s = new StringBuilder();
for (int i = 0; i < size; i++) {
s.append(CHARS[ThreadLocalRandom.current().nextInt(CHARS.length)]);
}
return s.toString();
}
}