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;
}
}