1 import cn.hutool.core.util.RandomUtil;
2 import cn.hutool.core.util.StrUtil;
3 import lombok.extern.slf4j.Slf4j;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.data.redis.core.RedisTemplate;
6 import org.springframework.data.redis.core.script.DefaultRedisScript;
7 import org.springframework.lang.Nullable;
8 import org.springframework.stereotype.Component;
9
10 import java.time.LocalDateTime;
11 import java.time.format.DateTimeFormatter;
12 import java.util.Collections;
13 import java.util.concurrent.TimeUnit;
14
15 /**
16 * 生成订单流水号18 * 精确到秒级,后面加随机数(redis获取)
19 * <p>
20 * 变更记录:2023-12-13 14:10 gz.zhang 通过增加随机性,修正因宿主机时钟回拨导致生成重复值的bug
21 * 变更记录:2023-12-19 14:37 刘红洁/张国战 ①key改为按日期,最后的拼接用取模的方式防止数据越界,②解决concat带来的bug。
22 *
23 * @author wangzaizhou
24 */
25 @Component
26 @Slf4j
27 public class GenerateOrderIdUtil {
28 private static final String DEFAULT_KEY_PREFIX = "keyPrefix";
29 private static RedisTemplate<String, Object> stringObjectRedisTemplate;
30
31 @Autowired
32 public void setRedisUtil(RedisTemplate<String, Object> redisTemplate) {
33 stringObjectRedisTemplate = redisTemplate;
34 }
35
36 /**
37 * 订单流水号组成: 时间秒 + 5位数(redis计算后的)
38 *
39 * @param keyPrefix redis key的前缀标识,可以指定为 系统标识(如“Channel”),也可以指定为业务标识(如“Pay”),或者具体数据标识(如“PayPaymentFlow”),etc.,也可为空
40 * @return 2021030914590406391
41 */
42 public static long genOrderId(@Nullable String keyPrefix) {
43 if (StrUtil.isBlank(keyPrefix)) {
44 keyPrefix = DEFAULT_KEY_PREFIX;
45 }
46 LocalDateTime now = LocalDateTime.now();
47 String redisKey = keyPrefix + now.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
48 Long incrValue = null;
49 try {
50 incrValue = stringObjectRedisTemplate.execute(REDIS_SCRIPT, Collections.singletonList(redisKey), TimeUnit.HOURS.toSeconds(24));
51 } catch (Exception e) {
52 log.error("GenerateOrderIdUtil 生成订单流水号异常,keyPrefix={}", keyPrefix, e);
53 }
54 if (incrValue == null) incrValue = RandomUtil.randomLong(99999);
55 String orderIdPrefix = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
56 String orderId = String.format("%s%05d", orderIdPrefix, incrValue % 100000);
57 return Long.parseLong(orderId);
58 }
59
60 /**
61 * 订单流水号组成: 时间秒 + 5位数(redis计算后的)
62 *
63 * @return 2021030914590406391
64 */
65 public static long genOrderId() {
66 return genOrderId(DEFAULT_KEY_PREFIX);
67 }
68
69 private final static DefaultRedisScript<Long> REDIS_SCRIPT = new DefaultRedisScript<>(
70 "local key = KEYS[1]\n" +
71 "local expiration_time = (ARGV[1])\n" +
72
73 "local current_value = redis.call('INCRBY', key, 1)\n" +
74 "if current_value == 1 then\n" +
75 " redis.call('EXPIRE', key, expiration_time)\n" +
76 "end\n" +
77 "return current_value\n"
78 , Long.class);
79
80 }
标签:return,String,不谢,redis,流水号,keyPrefix,import From: https://blog.51cto.com/u_15708799/8985242