1. 基于Redis实现的发号机

使用RedisTemplate操作Redis,基于Redis的integer类型,使用自增方法来获取对应的流水号。

1.1 Redis相关操作封装

1.1.1 操作接口

  1. public interface RedisDao {
  2. /**
  3. * 指定key是否存在
  4. *
  5. * @param key
  6. * @return
  7. */
  8. Boolean isExist(String key);
  9. /**
  10. * 自增,+1,返回增长后的值
  11. *
  12. * @param key
  13. * @return
  14. */
  15. long incr(String key);
  16. /**
  17. * 配置过期时间
  18. *
  19. * @param key
  20. */
  21. void expireKey(String key);
  22. }

1.1.2 操作接口实现

  1. @Service
  2. public class RedisDaoImpl implements RedisDao {
  3. @Autowired
  4. private RedisTemplate redisTemplate;
  5. @Override
  6. public Boolean isExist(String key) {
  7. return redisTemplate.hasKey(key);
  8. }
  9. /**
  10. * 自增,+1,返回增长后的值
  11. *
  12. * @param key
  13. * @return
  14. */
  15. @Override
  16. public long incr(String key) {
  17. return redisTemplate.opsForValue().increment(key);
  18. }
  19. /**
  20. * 设置过期时间
  21. *
  22. * @param key
  23. */
  24. @Override
  25. public void expireKey(String key) {
  26. redisTemplate.expire(key, 36, TimeUnit.HOURS);
  27. }
  28. }

1.2 相关工具

1.2.1 补位工具

通过此工具来根据业务需要,填充流水号位数,未占用的位进行补“0”操作。

  1. @Component
  2. public class ApplyCodeUtil {
  3. public ApplyCodeUtil() {
  4. }
  5. @Value("${applyCode.length}")
  6. int DEFAULT_LENGTH;
  7. /**
  8. * 获得 DEFAULT_LENGTH 位的序列号,长度不足 DEFAULT_LENGTH 位,前面补0
  9. *
  10. * @param seq
  11. * @return
  12. */
  13. public String getSequence(long seq) {
  14. String str = String.valueOf(seq);
  15. int len = str.length();
  16. if (len >= DEFAULT_LENGTH) {// 取决于业务规模,目前要求设置为3位流水号
  17. return str;
  18. }
  19. int rest = DEFAULT_LENGTH - len;
  20. StringBuilder sb = new StringBuilder();
  21. for (int i = 0; i < rest; i++) {
  22. sb.append('0');
  23. }
  24. sb.append(str);
  25. return sb.toString();
  26. }
  27. }

可以通过在配置文件中对applyCode.length进行配置,来决定流水号占位长度。

1.2.2 日期处理工具

  1. import cn.hutool.core.date.DateUtil;
  2. public class TimeUtil {
  3. /**
  4. * 获取今日日期
  5. *
  6. * @return
  7. */
  8. public static String getToday() {
  9. return DateUtil.format(DateUtil.date(), "yyyyMMdd");
  10. }
  11. }

1.3 流水号生成

1.3.1 生成接口

  1. public interface SerialNumberService {
  2. /**
  3. * redis中的业务前缀key
  4. */
  5. String SERIAL_NUMBER = "bussiness:applyCode:";
  6. /**
  7. * 根据两位业务码字符串,生成一个流水号,格式按照:<br/>
  8. * yyyyMMdd{自增序列号}
  9. * 两位,00-99
  10. * @return 序列号
  11. * @throws LJBaseException
  12. */
  13. String generate() throws LJBaseException;
  14. }

1.3.2 生成接口实现

  1. @Service
  2. public class SerialNumberServiceImpl implements SerialNumberService {
  3. @Autowired
  4. private RedisDao redisDao;
  5. @Autowired
  6. private ApplyCodeUtil applyCodeUtil;
  7. @Override
  8. public String generate() throws LJBaseException {
  9. /** 获取今天的日期:yyyyMMdd */
  10. String date = TimeUtil.getToday();
  11. /** 构造redis的key */
  12. String key = SERIAL_NUMBER + date;
  13. /** 自增 */
  14. Boolean exist = redisDao.isExist(key);
  15. long sequence = redisDao.incr(key);
  16. if (exist == null || !exist) {
  17. redisDao.expireKey(key);
  18. }
  19. String seq = applyCodeUtil.getSequence(sequence);
  20. StringBuilder sb = new StringBuilder();
  21. sb.append(date).append(seq);
  22. String serial = sb.toString();
  23. return serial;
  24. }
  25. }
  1. <br />至此,我们的简单流水号生成器就完成了,调用`SerialNumberService`中的`generate()`方法即可生成对应的流水号。