| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- package com.ylx.massage.utils;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Component;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.atomic.AtomicLong;
- @Component
- @Slf4j
- public class OrderNumberGenerator {
- // 订单单号前缀
- public static final String KEY_PREFIX_ORDER = "YORDER";
- public static final String KEY_PREFIX_RECHAR = "RECHAR";
- public static final String KEY_PREFIX_CASH = "CASH";
- public static final String KEY_PREFIX_REFUND = "REFUND";
- public static final String KEY_PREFIX_PRODUCTORDER = "PRODUCT";
- private static final DateTimeFormatter DATE_FORMATTER2 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
- private static final int SEQUENCE_MAX_VALUE = 99999;
- private static final int SEQUENCE_WARN_THRESHOLD = 90000;
- /**
- * 机器ID(用于多实例部署时区分不同节点)
- * 可通过配置中心或启动参数动态获取,这里使用固定值
- */
- private static final String MACHINE_ID = "01";
- /**
- * 每个前缀的序列号缓存(key 格式:prefix + yyyyMMddHHmmss)
- */
- private final ConcurrentHashMap<String, AtomicLong> sequenceCache = new ConcurrentHashMap<>();
- /**
- * 生成并返回当天的下一个自增单号。
- * 不依赖 Redis,使用本地原子序列生成器。
- *
- * @param prefix 订单号前缀
- * @return String 订单号(格式:prefix + yyyyMMddHHmmss + machineId + 5位序列号)
- */
- public String generateNextOrderNumber(String prefix) {
- LocalDateTime now = LocalDateTime.now();
- String timeStr = now.format(DATE_FORMATTER2);
- String cacheKey = prefix + timeStr;
- // 获取或创建当前秒的序列号
- AtomicLong sequence = sequenceCache.computeIfAbsent(cacheKey, k -> {
- log.debug("创建新的序列号缓存,key:{}", cacheKey);
- return new AtomicLong(0);
- });
- // 原子递增并获取序列号
- long newSequence = sequence.incrementAndGet();
- // 容量预警:序列号超过警戒阈值时记录警告日志
- if (newSequence > SEQUENCE_WARN_THRESHOLD) {
- log.warn("订单号序列号接近上限,当前值:{},前缀:{},时间:{}", newSequence, prefix, timeStr);
- }
- // 序列号溢出检查
- if (newSequence > SEQUENCE_MAX_VALUE) {
- log.error("订单号序列号超过上限,当前值:{},前缀:{},时间:{}", newSequence, prefix, timeStr);
- throw new IllegalStateException("当前秒内订单号序列号超出系统限制,请稍后重试");
- }
- // 格式:前缀 + 时间串 + 机器ID + 5位序列号
- return prefix + timeStr + MACHINE_ID + String.format("%05d", newSequence);
- }
- public static void main(String[] args) {
- OrderNumberGenerator generator = new OrderNumberGenerator();
- // 测试生成 10 个订单号
- for (int i = 0; i < 10; i++) {
- System.out.println(generator.generateNextOrderNumber(KEY_PREFIX_PRODUCTORDER));
- if (i < 9) {
- try {
- // 模拟不同时间的订单
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
|