基本思路

1、利用Redis中RedisAtomicLong类和其方法incrementAndGet()实现自增操作。

2、获取当天剩余的时间转化为秒,设置redis对应key值的失效时间

3、按照编号规则组装数据

遇到的坑

1、编号会存在重复操作,解决方案

 (1)在创建RedisAtomicLong类时使用Redisson分布式锁,详见下列代码

 (2)、使用下面代码替代RedisAtomicLong操作

Long increment = redisTemplate.opsForValue().increment(key, 1);
redisTemplate.expire(key,liveTime, TimeUnit.SECONDS);

2、Redisson分布式锁创建失败,为null,解决方案需要对redisTemplate进行序列化配置

  /**
     * redis key的层级不能超过3层()
     * 根据前缀+日期+每天的自增编号例如(WF2021041411200001)
     *
     * @param prefix
     * @param key
     * @param length
     * @return
     */
    public String getDayIncrCode(String prefix, String key, int length) {
        String code = "";
        String formatDay = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        Long dayEndTime = getAppointDateTimeMills();
        //当天失效
        long liveTime = (dayEndTime - System.currentTimeMillis()) / 1000;
        Long incre = getIncre(key, liveTime);
        String sequence = getSequence(incre, length);
        if (StrUtil.isNotBlank(prefix)) {
            code = code + prefix;
        }
        code = code + formatDay + sequence;

        return code;
    }

 获取当天结束的时间戳

 /**
     * 获取指定时间毫秒值
     *
     * @return
     */
    public static Long getAppointDateTimeMills() {
        Calendar ca = Calendar.getInstance();
        //失效的时间
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        long curtime = ca.getTimeInMillis();
        return curtime;
    }

利用Redis中RedisAtomicLong生成自增(核心使用了 redis中的increment方法)

//RedisAtomicLong源码
public long incrementAndGet() {
        return this.operations.increment(this.key, 1L);
    }
  /**
     * 获取redis原子自增数据
     *
     * @param key
     * @param liveTime
     * @return
     */
    public Long getIncre(String key, long liveTime) {
        RedisAtomicLong counter = null;
        RLock lock = null;
        if (!redisTemplate.hasKey(key)) {
            try {
                lock = redissonLock.lock(key, 1);
                counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
            } finally {
                redissonLock.unlock(lock);
            }
        } else {
            counter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
        }
        Long increment = counter.incrementAndGet();
        //初始设置过期时间
        boolean result = (null == increment || increment.longValue() == 0) && liveTime > 0;
        if (result) {
            counter.set(1);
            counter.expire(liveTime, TimeUnit.SECONDS);
            increment = 1L;
        }
        return increment;
    }

格式化数据 

   /**
     * 补全自增的数据
     *
     * @param seq
     * @param length
     * @return
     */
    public static String getSequence(long seq, int length) {
        String str = String.valueOf(seq);
        int len = str.length();
        // 取决于业务规模,应该不会到达4
        if (len >= length) {
            return str;
        }
        int rest = length - len;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < rest; i++) {
            sb.append('0');
        }
        sb.append(str);
        return sb.toString();
    }

测试

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class IdUtilsTest {

    @Autowired
    private IdUtils idUtils;

    @Test
    public void testSequenceCode() {
        String key="test:er6666:6666:934";
        String formatDay = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        key=key+formatDay;
        for (int i = 0; i < 20; i++) {
            String st = idUtils.getDayIncrCode("ST", key, 4);
            System.out.println(st);
        }
    }
}

输出结果

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐