QQ登录

只需要一步,快速开始

APP扫码登录

只需要一步,快速开始

手机号码,快捷登录

手机号码,快捷登录

查看: 3275|回复: 0

[JAVA/JSP] 教你如何用Java根据日期生成流水号

[复制链接]

等级头衔

积分成就    金币 : 2841
   泡泡 : 1516
   精华 : 6
   在线时间 : 1294 小时
   最后登录 : 2024-11-21

丰功伟绩

优秀达人突出贡献荣誉管理论坛元老

联系方式
发表于 2021-4-24 12:58:08 | 显示全部楼层 |阅读模式
一、前言- S% g1 L* {6 Q/ Q8 R
       生成流水号,在企业中可以说是比较常见的需求,尤其是订单类业务。一般来说,需要保证流水号的唯一性。
+ p# }& q- |3 S$ y* C) Q2 b  如果没有长度和字符的限制,那么直接使用UUID生成一个唯一字符串即可,也可以直接使用数据库表中的主键,主键就是唯一的。
* t8 y' C! X- U0 K3 v/ s       那么,如果限制了流水号必须多少位,这种怎么生成呢?可以采用"前缀+日期+数字"的方式(ps:此方式是需要用到缓存的)
% M2 y& _$ ?# k0 P" T; Q( P
  • 前缀:为了更好的标识这个流水号是属于哪种类型;
  • 日期:为了防止重复;
  • 数字:为了表示当前的流水所处序号。
  • 需求:生成一个17位数的唯一流水号,“LSH”+yyyyMMdd+6位数字5 k. {5 H8 w3 N% L* M; f: J
二、代码实现# B1 |% h: {2 v2 Z( K. ^4 {
  1. import java.text.SimpleDateFormat;
  2. import java.util.Calendar;
  3. import java.util.Date;
  4. import java.util.GregorianCalendar;
  5. import java.util.concurrent.atomic.AtomicInteger;
  6. public class SerialNoTest {
  7.     public static void main(String[] args) {
  8.         String serialNo = generateSerialNo();
  9.         System.out.println("生成的流水号:"+serialNo);
  10.     }
  11.     /**
  12.      * 生成17位唯一流水号,"LSH"+yyyyMMdd+6位数字
  13.      * 6位数字,如:000001
  14.      * @return
  15.      */
  16.     private static String generateSerialNo(){
  17.         //定义需要返回的流水号
  18.         String serialNo = null;
  19.         //先查询到今天的日期,格式:"yyyyMMdd"
  20.         String todayDate = new SimpleDateFormat("yyyyMMdd")
  21.                                 .format(new Date());
  22.         //固定字母前缀 拼接 今天日期,组成新的完整的前缀,也就是缓存的key
  23.         String cacheKey = "LSH"+todayDate;
  24.         //再通过key查询缓存有没有num数据,缓存操作根据自身项目封装工具类
  25.         Long codeNum = cacheService.getCache(cacheKey, Long.class);
  26.         //如果缓存查询有值,数值+1,再赋值给下一个流水号
  27.         if (null != codeNum) {
  28.             codeNum = codeNum + 1L;
  29.         } else {
  30.             //如果缓存查询没值,直接赋值为1
  31.             codeNum = 1L;
  32.         }
  33.         //流水号 = 缓存key + 拼接的数值 = 前缀 + 日期 + 拼接的数值
  34.         serialNo = getCodeOfSix(cacheKey, codeNum.intValue());
  35.         //设置缓存,调用此方法,会自动将key所对应的value+1,保存时长:今天剩余的时间
  36.         cacheService.incr(cacheKey, getSeconds());
  37.         return serialNo;
  38.     }
  39.     /**
  40.      * 将数值拼接成对应的位数
  41.      * @param prefix  前缀:"LSH"+yyyyMMdd
  42.      * @param nowNum  当前要生成的数字
  43.      * @return 拼接好的流水号
  44.      */
  45.     public static String getCodeOfSix(String prefix,int nowNum ) {
  46.         //需要返回的code
  47.         StringBuilder codeSb = new StringBuilder();
  48.         //需要拼接的数字
  49.         StringBuilder numSb = new StringBuilder();
  50.         //封装的数字对象,里面 value 加了 volatile关键字,保证了线程安全
  51.         AtomicInteger count = new AtomicInteger(nowNum);
  52.         //将数值补足为6位字符串
  53.         if (count.get() < 10) {
  54.             numSb.append("00000").append(count.get());
  55.         } else if(count.get() < 100){
  56.             numSb.append("0000").append(count.get());
  57.         }else if(count.get() < 1000){
  58.             numSb.append("000").append(count.get());
  59.         }else if(count.get() < 10000){
  60.             numSb.append("00").append(count.get());
  61.         }else if(count.get() < 100000){
  62.             numSb.append("0").append(count.get());
  63.         } else if (count.get() >= 100000) {
  64.             numSb.append(count.get());
  65.         }
  66.         //先拼接前缀
  67.         codeSb.append(prefix);
  68.         //再拼接数字
  69.         codeSb.append(numSb);
  70.         return codeSb.toString();
  71.     }
  72.     /**
  73.      * 获取当天结束还剩余多少秒
  74.      * @return
  75.      */
  76.     public static int getSeconds(){
  77.                 //获取今天当前时间
  78.         Calendar curDate = Calendar.getInstance();
  79.                 //获取明天凌晨0点的日期
  80.         Calendar tommorowDate = new GregorianCalendar(
  81.                 curDate.get(Calendar.YEAR),
  82.                 curDate.get(Calendar.MONTH),
  83.                 curDate.get(Calendar.DATE) + 1,
  84.                 0, 0, 0);
  85.                 //返回 明天凌晨0点 和 今天当前时间 的差值(秒数)
  86.         return (int)(tommorowDate.getTimeInMillis() - curDate .getTimeInMillis()) / 1000;
  87.     }
  88. }
      假如今天是2021年4月22日,运行项目,生成的第1个流水号则为:LSH20210422000001
, N! w4 J) ]/ @1 E       第2个流水号则为:LSH20210422000002,依次类推。
6 {, ]$ k% K) y( U需要注意的是:
5 c7 A  z* w- C& s" K& u
  • 如果限制了位数,6位数字每天最多能生成10w个流水号,所以,这个数字位数根据具体业务量进行调整。
  • 如果每天的生成数量量不到1w,那么使用4位数字即可。
    / F2 k2 w7 y  w( ]7 I
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|paopaomj.COM ( 渝ICP备18007172号|渝公网安备50010502503914号 )

GMT+8, 2024-11-22 03:31

Powered by paopaomj X3.5 © 2016-2025 sitemap

快速回复 返回顶部 返回列表