image-20221223115554598

import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * @Projectname: hm-dianping
 * @Filename: RedisIdWork
 * @Author: SpringForest
 * @Data:2022/12/23 11:09
 * @Description: 
 * 1. 生成的ID总长度为32(如需修改长度请修改COUNT_BITS)
 * 2. 最高位为符号位永远为0
 * 3. 第1-32位为时间戳,最长使用时间为基准时间(可变)后69年
 * 4. 第33-63位为序列号位,使用Redis生成,每秒最大可用ID为2^32个
 */

public class RedisIdWork {
    /*
     * 开始时间戳
     * */
    private static final long BEGIN_TIMESTAMP = 1640995200L;
    /*
     * 序列号的位数
     * */
    private static final int COUNT_BITS = 32;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    public long nextId(String keyPrefix) {
        // 1. 生成时间戳
        LocalDateTime now = LocalDateTime.now();
        long nowSecond = now.toEpochSecond(ZoneOffset.UTC);
        long timestamp = nowSecond - BEGIN_TIMESTAMP;

        // 2. 生成序列号
        // 2.1 获取精确到天作为前缀的一部分,防止某一天到达上线
        now.format(DateTimeFormatter.ofPattern("yy yyMMdd"));
        // 2.2 自增长
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":");

        // 3. 拼接并返回
        // 3.1 使用位运算,将时间戳左移32位
        // 3.2 使用或运算填充低位
        return timestamp << COUNT_BITS | count;
    }


    /*
     * 设置基准时间戳
     * */

    public static void main(String[] args) {
        LocalDateTime time = LocalDateTime.of(2022, 1, 1, 0, 0, 0);

        long second = time.toEpochSecond(ZoneOffset.UTC);

        System.out.println("s=" + second);
    }

}