java-中基于redis 自增生成每天的单号,key 隔天自动失效


package com.property.common.utils;

import com.property.common.constant.OrderConstants;
import com.property.common.enums.OrderNoTypeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Calendar;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
* @className: OrderNoSerialUtil
* @program: work
* @description: 单号生成工具类
* @author: wangliangzhi
* @create: 2021-12-21 11:16
*/
@Component
public class OrderNoSerialUtil {

@Autowired
private RedisUtil redisUtil;

/**
* 生成单号前缀
*/
private static String getFormNoPrefix(OrderNoTypeEnum orderNoTypeEnum) {
//格式化时间
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(orderNoTypeEnum.getDatePattern());
StringBuffer sb = new StringBuffer();
sb.append(orderNoTypeEnum.getPrefix());
sb.append(formatter.format(LocalDateTime.now()));
return sb.toString();
}

/**
* 构建流水号缓存Key
*
* @param serialPrefix 流水号前缀
* @return 流水号缓存Key
*/
private static String getCacheKey(String serialPrefix) {
return OrderConstants.SERIAL_CACHE_PREFIX.concat(serialPrefix);
}

/**
* 补全流水号
*
* @param serialPrefix 单号前缀
* @param incrementalSerial 当天自增流水号
* @author mengqiang
* @date 2019/1/1
*/
private static String completionSerial(String serialPrefix, Long incrementalSerial,
OrderNoTypeEnum orderNoTypeEnum) {
StringBuffer sb = new StringBuffer(serialPrefix);

//需要补0的长度=流水号长度 -当日自增计数长度
int length = orderNoTypeEnum.getSerialLength() - String.valueOf(incrementalSerial).length();
//补零
for (int i = 0; i < length; i++) {
sb.append("0");
}
//redis当日自增数
sb.append(incrementalSerial);
return sb.toString();
}


/**
* 补全随机数
*
* @param serialWithPrefix 当前单号
* @param orderNoTypeEnum 单号生成枚举
* @author mengqiang
* @date 2019/1/1
*/
private static String completionRandom(String serialWithPrefix, OrderNoTypeEnum orderNoTypeEnum) {
StringBuilder sb = new StringBuilder(serialWithPrefix);
//随机数长度
int length = orderNoTypeEnum.getRandomLength();
if (length > 0) {
Random random = new Random();
for (int i = 0; i < length; i++) {
//十以内随机数补全
sb.append(random.nextInt(10));
}
}
return sb.toString();
}

/**
* @param orderNoTypeEnum:
* @Description 基于redis生成单号(时间格式 + 自增数)
* @author wangliangzhi
* @Date: 2021/12/21
* @time: 14:15
* @return: java.lang.String
**/
public String createOrderNo(OrderNoTypeEnum orderNoTypeEnum) {
//获得单号前缀
//格式 固定前缀 +时间前缀 示例
String formNoPrefix = getFormNoPrefix(orderNoTypeEnum);
//获得缓存key
String cacheKey = getCacheKey(formNoPrefix);
//获得当日自增数
Long incrementalSerial = redisUtil.incr(cacheKey, 1);
// 设置key过期时间, 保证每天的流水号从1开始
if (incrementalSerial == 1) {
//设置失效时间 凌晨过期
redisUtil.expire(cacheKey, getSecondsNextEarlyMorning(), TimeUnit.SECONDS);
}
//组合单号并补全流水号
String serialWithPrefix = completionSerial(formNoPrefix, incrementalSerial, orderNoTypeEnum);
//补全随机数
return completionRandom(serialWithPrefix, orderNoTypeEnum);
}


private Long getSecondsNextEarlyMorning() {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_YEAR, 1);
// 改成这样就好了
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.MILLISECOND, 0);
return (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
}

}







package com.property.common.enums;

import com.property.common.constant.OrderConstants;
import lombok.Getter;

/**
* @className: OrderNoTypeEnum
* @program: work
* @description: 单号生成类型枚举
* @author: wangliangzhi
* @create: 2021-12-21 11:04
*/
@Getter
public enum OrderNoTypeEnum {
/**
* 巡更计划单号:
* 固定前缀:XGJH
* 时间格式:yyyyMMdd
* 流水号长度:6(当单日单据较多时可根据业务适当增加流水号长度)
* 随机数长度:0
* 总长度:0
*/
XGJH_ORDER("XGJH", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),


/**
* 巡更单单号:
* 固定前缀:XGJH
* 时间格式:yyyyMMdd
* 流水号长度:6(当单日单据较多时可根据业务适当增加流水号长度)
* 随机数长度:0
* 总长度:0
*/
XG_ORDER("XG", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),


/**
* 巡更单单号:app使用区分
* 固定前缀:XGJH
* 时间格式:yyyyMMdd
* 流水号长度:6(当单日单据较多时可根据业务适当增加流水号长度)
* 随机数长度:0
* 总长度:0
*/
XG_APP_ORDER("XG-A", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),

/**
* 巡检计划单号:
* 固定前缀:XJJH
* 时间格式:yyyyMMdd
* 流水号长度:6
* 随机数长度:0
* 总长度:0
*/
XJJH_ORDER("XJJH", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),


/**
* 巡检单单号:
* 固定前缀:XJ
* 时间格式:yyyyMMdd
* 流水号长度:6(当单日单据较多时可根据业务适当增加流水号长度)
* 随机数长度:0
* 总长度:0
*/
XJ_ORDER("XJ", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),

/**
* 巡检单单号:app使用区分
* 固定前缀:XJ-A
* 时间格式:yyyyMMdd
* 流水号长度:6(当单日单据较多时可根据业务适当增加流水号长度)
* 随机数长度:0
* 总长度:0
*/
XJ_APP_ORDER("XJ-A", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),

/**
* 设备编号:
* 固定前缀:"EQ"
* 时间格式:yyyyMMdd
* 流水号长度:6
* 随机数长度:0
* 总长度:0
*/
EQ_ORDER("EQ", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0),

/**
* 巡检项目编号:
* 固定前缀:"XJXM"
* 时间格式:yyyyMMdd
* 流水号长度:6
* 随机数长度:0
* 总长度:0
*/
XJXM_ORDER("XJXM", OrderConstants.SERIAL_YYYYMMDD_PREFIX, 6, 0, 0);

/**
* 单号前缀l
* 为空时填""
*/
private final String prefix;

/**
* 时间格式表达式
* 例如:yyyyMMdd
*/
private final String datePattern;

/**
* 流水号长度 --指的是自增的顺序
*/
private final Integer serialLength;
/**
* 随机数长度 --指的是使用随机生成的数字
*/
private final Integer randomLength;

/**
* 总长度
*/
private final Integer totalLength;


OrderNoTypeEnum(String prefix, String datePattern, Integer serialLength, Integer randomLength, Integer totalLength) {
this.prefix = prefix;
this.datePattern = datePattern;
this.serialLength = serialLength;
this.randomLength = randomLength;
this.totalLength = totalLength;
}
}



posted on   Wang_12138  阅读(1528)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示