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 ; 
 | 
    private static final int noSuffix = 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 + noSuffix; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 得到今日截止的id(如: 230630 24000000000) 
 | 
     * @return ID 
 | 
     */ 
 | 
    public static Long generateTodayEndId(){ 
 | 
        return (currentTodayEnd() * chengShu) * 100 + noSuffix; 
 | 
    } 
 | 
     
 | 
     
 | 
    /** 
 | 
     * 得到某日开始的id(如: 230630 00000000000) 
 | 
     * @return ID 
 | 
     */ 
 | 
    public static Long generateBeforeXDayStartId(int xday){ 
 | 
        return (beforeXDayStart(xday) * chengShu) * 100 + noSuffix; 
 | 
    } 
 | 
     
 | 
    /** 
 | 
     * 得到某日截止的id(如: 230630 24000000000) 
 | 
     * @return ID 
 | 
     */ 
 | 
    public static Long generateBeforeXDayEndId(int xday){ 
 | 
        return (beforeXDayEnd(xday) * chengShu) * 100 + noSuffix; 
 | 
    } 
 | 
   
 | 
     
 | 
    /** 
 | 
     * 得到某日开始的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); 
 | 
//    } 
 | 
     
 | 
} 
 |