产品需求要生成有序的订单 key+ 年月日时分秒 +6位序号 由00001-99999组成 且每天都是从00001开始
公司系统有部署多台服务,这需要一个有序的序列不能重复而且得保证获取时的原子性这里 我们考虑使用了redis Incr 这个命令
Redis Incr 命令能将 key 中储存的数字值增一,这样就不会取到重复的编号。
需要提前引入Redis
使用
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
public class DateUtils {
public static final long ONE_DAY_MILLS = 3600000 * 24;
private DateUtils() {
}
/**
* 日期格式 enum(枚举类型):一组类似的值包含到一种类型当中。而这种枚举类型的名称则会被定义成独一无二的类型描述符 -->为申明的变量提供更大的取值范围
*/
public enum DateFormat {
/**
* 格式:"yyyyMMddHHmmss"
*/
ALLTIME {
@Override
public String getValue() {
return "yyyyMMddHHmmss";
}
},
/**
* 格式:"yyyy-MM-dd HH:mm:ss"
*/
ALL_TIME {
public String getValue() {
return "yyyy-MM-dd HH:mm:ss";
}
},
/**
* 格式:"yyyy-MM-dd HH:mm"
*/
ONLY_MINUTE {
public String getValue() {
return "yyyy-MM-dd HH:mm";
}
},
/**
* 格式:"yyyy-MM-dd HH"
*/
ONLY_HOUR {
public String getValue() {
return "yyyy-MM-dd HH";
}
},
/**
* 格式:"yyyy-MM-dd"
*/
ONLY_DAY {
public String getValue() {
return "yyyy-MM-dd";
}
},
/**
* 格式:"yyyy-MM"
*/
ONLY_MONTH {
public String getValue() {
return "yyyy-MM";
}
},
/**
* 格式:"MM-dd"
*/
ONLY_MONTH_DAY {
public String getValue() {
return "MM-dd";
}
},
/**
* 格式:"MM-dd HH:mm"
*/
ONLY_MONTH_SEC {
public String getValue() {
return "MM-dd HH:mm";
}
},
/**
* 格式:"HH:mm:ss"
*/
ONLY_TIME {
public String getValue() {
return "HH:mm:ss";
}
},
/**
* 格式:"HH:mm"
*/
ONLY_HOUR_MINUTE {
public String getValue() {
return "HH:mm";
}
};
public abstract String getValue();
}
/**
* 获取当前时间 格式---->2019-08-04 13:30:29
*/
public static String getNowTime(DateFormat format) {
String nowtime = null;
Calendar calendar = Calendar.getInstance();
Date dateNow = calendar.getTime();
SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);
nowtime = sdf.format(dateNow);
return nowtime;
}
/**
* 将一个日期字符串转换成Data对象 string-->date
*
* @param dateString 日期字符串
* @param format 转换格式
* @return
*/
public static Date stringToDate(String dateString, DateFormat format) {
Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);
try {
date = sdf.parse(dateString);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
/**
* 将date转换成字符串 date--->string
*
* @param date 日期
* @param format 日期目标格式
* @return
*/
public static String dateToString(Date date, DateFormat format) {
String string = "";
SimpleDateFormat sdf = new SimpleDateFormat(format.getValue(), Locale.CHINA);
string = sdf.format(date);
return string;
}
/**
* 获取指定日期
*
* @param date 指定日期
* @return 返回值为: "周日", "周一", "周二", "周三", "周四", "周五", "周六"
*/
public static String getWeekOfDate(Date date) {
String[] weekDays = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;
if (week < 0)
week = 0;
return weekDays[week];
}
/**
* 获取指定日期对应周几的序列
*
* @param date 指定日期
* @return 周一:1 周二:2 周三:3 周四:4 周五:5 周六:6 周日:7
*/
public static int getIndexWeekOfDate(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int index = calendar.get(Calendar.DAY_OF_WEEK);
if (index == 1) {
return 7;
} else {
return --index;
}
}
/**
* 获取当前月份
*/
public static int getNowMonth() {
Calendar calendar = Calendar.getInstance();
return calendar.get(Calendar.MONTH) + 1;
}
/**
* 获取当前月号
*/
public static int getNowDay() {
Calendar calendar = Calendar.getInstance();
return calendar.get(Calendar.DATE);
}
/**
* 获取当前年份
*/
public static int getNowYear() {
Calendar calendar = Calendar.getInstance();
return calendar.get(Calendar.YEAR);
}
/**
* 获取本月份的天数
*/
public static int getNowDaysOfMonth() {
Calendar calendar = Calendar.getInstance();
return daysOfMonth(calendar.get(Calendar.YEAR), calendar.get(Calendar.DATE) + 1);
}
/**
* 计算两个日期之间的年份差距
*
* @param firstDate
* @param secondDate
* @return
*/
public static int getYearGapOfDates(Date firstDate, Date secondDate) {
if (firstDate == null || secondDate == null) {
return 0;
}
Calendar helpCalendar = Calendar.getInstance();
helpCalendar.setTime(firstDate);
int firstYear = helpCalendar.get(Calendar.YEAR);
helpCalendar.setTime(secondDate);
int secondYear = helpCalendar.get(Calendar.YEAR);
return secondYear - firstYear;
}
/**
* 计算两个日期之间的天数差
*
* @param startDate
* @param endDate
* @return
*/
public static int getDaysGapOfDates(Date startDate, Date endDate) {
int date = 0;
if (startDate != null && endDate != null) {
date = getDaysBetween(startDate, endDate);
}
return date;
}
/**
* 计算两个日期之间的月份差距
*
* @param firstDate
* @param secondDate
* @return
*/
public static int getMonthGapOfDates(Date firstDate, Date secondDate) {
if (firstDate == null || secondDate == null) {
return 0;
}
return (int) ((secondDate.getTime() - firstDate.getTime())
/ ONE_DAY_MILLS / 30);
}
/**
* 获取指定月份的天数
*
* @param year 年份
* @param month 月份
* @return 对应天数
*/
public static int daysOfMonth(int year, int month) {
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return 31;
case 4:
case 6:
case 9:
case 11:
return 30;
case 2:
if ((year % 4 == 0 && year % 100 == 0) || year % 400 != 0) {
return 29;
} else {
return 28;
}
default:
return -1;
}
}
private static int getDaysBetween(Date startDate, Date endDate) {
return (int) ((endDate.getTime() - startDate.getTime()) / ONE_DAY_MILLS);
}
}
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
@SuppressWarnings(value = {"rawtypes"})
@Slf4j
public class OrderNumberUtils {
@Autowired
@Qualifier("redisTemplate")
private RedisTemplate redisTemplate;
/**
* 对取值补 0
*
* @param keyName
* @param lenght 补足多少位
* @return
*/
public String generateOrderNum(String keyName, int lenght) {
Integer serialNumber = getSerialNumber(keyName);
return String.format("%0" + lenght + "d", serialNumber);
}
/**
* 数量自增 已设置过期时间
*
* @param keyName
* @return
*/
public Integer getSerialNumber(String keyName) {
keyName = "SerialNumber:" + keyName;
try {
RedisAtomicLong entityIdCounter = new RedisAtomicLong(keyName, redisTemplate.getConnectionFactory());
Long incr = entityIdCounter.getAndIncrement();
if (null == incr || incr.longValue() == 0) {// 初始设置过期时间
// 设置过期时间 24小时
entityIdCounter.expire(24, TimeUnit.HOURS);
// 这里取第二次 incr 就是从1开始了,默认从0开始
incr = entityIdCounter.getAndIncrement();
}
log.debug(keyName + "==========" + incr);
return incr.intValue();
} catch (Exception e) {
log.error("======redisIncr======", e);
}
return null;
}
}
// 生成number指定长度 0000001、
int leng = 6;
String 年月日 = DateUtils.dateToString(new Date(), DateUtils.DateFormat.ALLTIME);
String number = orderNumber.generateOrderNum(年月日, leng );
System.out.println(年月日.concat( number));
订单结果
20230722114301000001
20230722114301000002
20230722114301000003
20230722114301000004
20230722114301000005
20230722114302000001
20230722114302000002
20230722114302000004