原理:利用日期表达式生成时间字符串,利用redis的 increment 生成自增数字,保证code唯一。
具体格式如下:
如:CODE[D:yyyyMMdd][N:4] 生成结果:CODE202105200001
[]包裹的字符串是规则,在[]外的是固定字符串
[D:日期规则] :表示日期规则,获取日期。如:[D:yyyyMMdd] -> 20210520
[DL:日期规则] :表示日期规则,获取日期并转成字母。如:[DL:MMdd] -> 0520 -> 0EB0
[N:数值长度] :表示数值长度,获取N位数字。如:[N:4] -> 0001
[NL:数值长度] :表示数值长度,获取N位数字并转成字母。如:[N:4] -> 0001 -> 000A
代码如下:
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 利用Redis的递增生成code
*
* @author zenan.qi
* @date 2021-5-20
*/
@Component
public class CodeGenerator {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* @param rule code的生成规则 :如 CODE[D:yyyyMMdd][N:4]
* [D:日期规则] :表示日期规则,获取日期。如:[D:yyyyMMdd] -> 20210520
* [DL:日期规则] :表示日期规则,获取日期并转成字母。如:[DL:MMdd] -> 0520 -> 0EB0
* [N:数值长度] :表示数值长度,获取N位数字。如:[N:4] -> 0001
* [NL:数值长度] :表示数值长度,获取N位数字并转成字母。如:[N:4] -> 0001 -> 000A
* 其余的为固定字符
* @return code 如:CODE202105200001
*/
public synchronized String nextCode(String rule) {
String code = rule;
Pattern pattern = Pattern.compile("\\[([A-Z]+):([^\\]]+)\\]");
Matcher matcher = pattern.matcher(rule);
while (matcher.find()) {
String fullRule = matcher.group(0);
String oneRule = matcher.group(1);
String twoRule = matcher.group(2);
String fullValue = "";
//日期
if (oneRule.startsWith("D")) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(twoRule);
fullValue = dateTimeFormatter.format(LocalDateTime.now());
}
//数值
if (oneRule.startsWith("N")) {
System.out.println(code);
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
ops.increment(code, 1L);
Integer value = Integer.parseInt(ops.get(code).toString());
fullValue = String.format("%0" + twoRule + "d", value);
}
if (StringUtils.contains(oneRule, "L")) {
fullValue = numberTurnLetter(fullValue);
}
code = code.replace(fullRule, fullValue);
}
return code;
}
/**
* 数字转字母,1-9 对应 A-I,0 对应 0
*
* @param s 数字字符串
* @return 字母字符串
*/
private String numberTurnLetter(String s) {
String reString = "";
for (int x = 0; x < s.length(); x++) {
// 转换的单个字母
String single = "";
if (s.charAt(x) == '0') {
single = "0";
} else {
char s1 = (char) (((s.charAt(x) - '0') - 1) + (int) 'a');
String s2 = "" + s1;
single = s2.toUpperCase();
}
reString = reString + single;
}
return reString;
}
}
测试:
//YD固定字符串,4位年,2位月,2位日,4位自增长
System.out.println(codeGenerator.nextCode("YD[D:yyyyMMdd][N:4]"));
System.out.println(codeGenerator.nextCode("YD[D:yyyyMMdd][N:4]"));
//YD固定字符串,4位年,2位月字(字母显示),2位日(字母显示),4位自增长
System.out.println(codeGenerator.nextCode("YD[D:yyyy][DL:MMdd][N:4]"));
System.out.println(codeGenerator.nextCode("YD[D:yyyy][DL:MMdd][N:4]"));
//YD固定字符串,4位年,2位月字(字母显示),2位日(字母显示),4位自增长(字母显示)
System.out.println(codeGenerator.nextCode("YD[D:yyyy][DL:MMdd][NL:4]"));
System.out.println(codeGenerator.nextCode("YD[D:yyyy][DL:MMdd][NL:4]"));
结果
//YD固定字符串,4位年,2位月,2位日,4位自增长
YD202105210001
YD202105210002
//YD固定字符串,4位年,2位月字(字母显示),2位日(字母显示),4位自增长
YD20210EBA0001
YD20210EBA0002
//YD固定字符串,4位年,2位月字(字母显示),2位日(字母显示),4位自增长(字母显示)
YD20210EBA000A
YD20210EBA000B