| package com.dy.common.util; | 
|   | 
| import lombok.extern.slf4j.Slf4j; | 
| import org.springframework.stereotype.Component; | 
|   | 
| import java.util.Calendar; | 
|   | 
| @Slf4j | 
| @Component | 
| public class IDLongGenerator { | 
|   | 
|     private static final Object synObj = new Object() ; | 
|   | 
|     private static final int yearLength = 4 ;//4:年度取四位, 3:年度取三位, 2:年度取两位, 1:年度取一位, 0:年度取0位 | 
|   | 
|     private static int add = 0 ; | 
|     private static final int chengShu = 1000 ;//1000:三位自增量,即一秒钟可产生10000个ID | 
|     private static final int maxAdd = 999 ; | 
|     private static long last; | 
|     //后缀 | 
|     //在分布式系统中,例如多个数据中间件dataMw,多个系统都会向数据库中插入数据,用的都是此ID生成器, | 
|     //此ID生成器在各个子系统中难免为同一类数据生成相同的ID,造成数据库插入因主键相同而报错, | 
|     //所以设计此后缀,每个子系统后缀不同 | 
|     private static int suffix = 0 ; | 
|   | 
|     static { | 
|         last = current() ; | 
|     } | 
|   | 
|     /** | 
|      *  2023 10 28 09 14 40 00000 | 
|      * 长度19的ID,年度取两位,长度18的ID,年度取四位,17位数字超出了javascript的表数范围,javascript会表数不正确 | 
|      */ | 
|     public Long generate(){ | 
|         synchronized (synObj){ | 
|             //Long id = doGenerate() ; | 
|             //log.info("产生ID = " + id); | 
|             //return id ; | 
|             return doGenerate() ; | 
|         } | 
|     } | 
|     /** | 
|      * 设置后缀,不同子系统设置不同的后缀 | 
|      * @param suffix ID后缀,0到99 | 
|      */ | 
|     public static void setSuffix(int suffix) throws Exception{ | 
|         if(suffix < 0 || suffix > 99){ | 
|             throw new Exception("后缀只能是0到99的数字") ; | 
|         } | 
|         IDLongGenerator.suffix = suffix ; | 
|     } | 
|   | 
|   | 
|     /** | 
|      * 得到今日开始的id(如: 230630 00000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateTodayStartId(){ | 
|         return (currentTodayStart() * chengShu) * 100 + suffix; | 
|     } | 
|      | 
|     /** | 
|      * 得到今日截止的id(如: 230630 24000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateTodayEndId(){ | 
|         return (currentTodayEnd() * chengShu) * 100 + suffix; | 
|     } | 
|      | 
|      | 
|     /** | 
|      * 得到某日开始的id(如: 230630 00000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateBeforeXDayStartId(int xday){ | 
|         return (beforeXDayStart(xday) * chengShu) * 100 + suffix; | 
|     } | 
|      | 
|     /** | 
|      * 得到某日截止的id(如: 230630 24000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateBeforeXDayEndId(int xday){ | 
|         return (beforeXDayEnd(xday) * chengShu) * 100 + suffix; | 
|     } | 
|    | 
|      | 
|     /** | 
|      * 得到某日开始的id(如: 230630 00000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateOneDayStartId(int year, int month, int day){ | 
|         return (currentOneDayStart(year, month, day) * chengShu) * 100 + suffix; | 
|     } | 
|      | 
|     /** | 
|      * 得到某日截止的id(如: 230630 24000000000) | 
|      * @return ID | 
|      */ | 
|     public static Long generateOneDayEndId(int year, int month, int day){ | 
|         return (currentOneDayEnd(year, month, day) * chengShu) * 100 + suffix; | 
|     } | 
|   | 
|      | 
|   | 
|     /** | 
|      * 执行生成 | 
|      * @return ID 20231218 104504 06900 | 
|      */ | 
|     private Long doGenerate(){ | 
|         long id ; | 
|         long now = current() ; | 
|         if(now != last){ | 
|             //上次生成ID 与本次生成ID 不在同一秒内 | 
|             last = now ; | 
|             add = 0 ; | 
|             id = last * chengShu + add++; | 
|         }else{ | 
|             //上次生成ID 与本次生成ID 在同一秒内 | 
|             if(add >= maxAdd){ | 
|                 //附加量已经用尽 | 
|                 waitNextSecond(last) ;//等到下一秒 | 
|                 id = last * chengShu + add++ ;//返回上一秒生成的ID | 
|                 add = 0 ;//附加量归零,为下一秒准备 | 
|             }else{ | 
|                 //附加量未用尽 | 
|                 id = last * chengShu + add++ ; | 
|             } | 
|         } | 
|         return (id * 100) + suffix ; | 
|     } | 
|     /** | 
|      * 等待下一秒到来 | 
|      * @param last 上次时间(精确到秒) | 
|      */ | 
|     private void waitNextSecond(Long last){ | 
|         try { | 
|             Thread.sleep(10); | 
|         } catch (InterruptedException ignored) { | 
|         }finally{ | 
|             long now = current() ; | 
|             if(now == last){ | 
|                 waitNextSecond(last) ; | 
|             } | 
|         } | 
|     } | 
|   | 
|     | 
|      | 
|     /** | 
|      * 格式为 y*yMMddHHmmss | 
|      * @return ID | 
|      */ | 
|     private static long current(){ | 
|         Calendar cal = Calendar.getInstance(); | 
|         return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L | 
|         + (cal.get(Calendar.MONTH) + 1) * 100000000L | 
|         + cal.get(Calendar.DAY_OF_MONTH) * 1000000L | 
|         + cal.get(Calendar.HOUR_OF_DAY) * 10000L | 
|         + cal.get(Calendar.MINUTE) * 100L | 
|         + cal.get(Calendar.SECOND)  ; | 
|     } | 
|     | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long currentTodayStart(){ | 
|         Calendar cal = Calendar.getInstance(); | 
|         return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L | 
|         + (cal.get(Calendar.MONTH) + 1) * 100000000L  | 
|         + cal.get(Calendar.DAY_OF_MONTH) * 1000000L ; | 
|     } | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long currentTodayEnd(){ | 
|         Calendar cal = Calendar.getInstance(); | 
|         return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L | 
|         + (cal.get(Calendar.MONTH) + 1) * 100000000L  | 
|         + cal.get(Calendar.DAY_OF_MONTH) * 1000000L  | 
|         + 24 * 10000L ; | 
|     } | 
|      | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long currentOneDayStart(int year, int month, int day){ | 
|         return (dealYear(year)) * 10000000000L | 
|         + month * 100000000L  | 
|         + day * 1000000L ; | 
|     } | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long currentOneDayEnd(int year, int month, int day){ | 
|         return (dealYear(year)) * 10000000000L | 
|         + month * 100000000L  | 
|         + day * 1000000L  | 
|         + 24 * 10000L ; | 
|     } | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long beforeXDayStart(int xday){ | 
|         Calendar cal = Calendar.getInstance(); | 
|         cal.add(Calendar.DATE, xday<=0?xday:-xday); | 
|         return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L | 
|         + (cal.get(Calendar.MONTH) + 1) * 100000000L  | 
|         + cal.get(Calendar.DAY_OF_MONTH) * 1000000L ; | 
|     } | 
|      | 
|     /** | 
|      * 格式为  | 
|      * @return ID | 
|      */ | 
|     private static long beforeXDayEnd(int xday){ | 
|         Calendar cal = Calendar.getInstance(); | 
|         cal.add(Calendar.DATE, xday<=0?xday:-xday); | 
|         return (dealYear(cal.get(Calendar.YEAR))) * 10000000000L | 
|         + (cal.get(Calendar.MONTH) + 1) * 100000000L  | 
|         + cal.get(Calendar.DAY_OF_MONTH) * 1000000L  | 
|         + 24 * 10000L ; | 
|     } | 
|   | 
|     /** | 
|      * 处理年度 | 
|      * @param year 年度 | 
|      * @return 处理后的年度 | 
|      */ | 
|     private static int dealYear(int year){ | 
|         if(yearLength == 0){ | 
|             return 0 ; | 
|         }else if(yearLength == 1){ | 
|             return year % 10 ; | 
|         }else if(yearLength == 2){ | 
|             return year % 100 ; | 
|         }else if(yearLength == 3){ | 
|             return year % 1000 ; | 
|         }else if(yearLength == 4){ | 
|             return year ; | 
|         }else{ | 
|             return year ; | 
|         } | 
|     } | 
|   | 
| //    public static void main(String[] args){ | 
| //        Calendar cal = Calendar.getInstance(); | 
| //        System.out.println(cal.get(Calendar.MONTH) + 1) ; | 
| // | 
| //        IDLongGenerator o = new IDLongGenerator() ; | 
| //        int total = 1 ; | 
| //        for(int i = 0 ; i < total ; i++){ | 
| //            System.out.println(o.generate()) ; | 
| //        } | 
| //        long start = System.currentTimeMillis() ; | 
| //        long end = System.currentTimeMillis() ; | 
| //        System.out.println("产生" + total + "ID用时" + (end - start) + "毫秒"); | 
| // | 
| //        Long todayStartId = IDLongGenerator.generateTodayStartId() ; | 
| //        System.out.println("today start id:\n" + todayStartId); | 
| //        Long todayEndId = IDLongGenerator.generateTodayEndId() ; | 
| //        System.out.println("today end id:\n" + todayEndId); | 
| // | 
| // | 
| //        Long beforeXDayStartId = IDLongGenerator.generateBeforeXDayStartId(3) ; | 
| //        System.out.println("before3Day start id:\n" + beforeXDayStartId); | 
| //        Long beforeXDayEndId = IDLongGenerator.generateBeforeXDayEndId(3) ; | 
| //        System.out.println("before3Day end id:\n" + beforeXDayEndId); | 
| // | 
| // | 
| //        Long oneDayStartId = IDLongGenerator.generateOneDayStartId(2023, 7, 9) ; | 
| //        System.out.println("OneDay(2023-07-09) start id:\n" + oneDayStartId); | 
| //        Long oneDayEndId = IDLongGenerator.generateOneDayEndId(2023, 7, 11) ; | 
| //        System.out.println("OneDay(2023-07-11) end id:\n" + oneDayEndId); | 
| //    } | 
|      | 
| } |