编号,订单号生成

import com.alibaba.druid.util.StringUtils;
import com.google.common.base.Preconditions;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

/**
 * 生成编号组件类
 *
 * @author huangkl
 * @version v1.0
 * @date 2020/9/27/027 9:31
 */
@Component
@AllArgsConstructor
@Slf4j
public class ProductionSerialNOComponent {
  private final RedisTemplate redisTemplate;
  private final String REDIS_CACHE_KEY = "com:keyu:codes_of_unused:";
  /**
   * 生成编号: 基于redis实现, 第一次获取编号先往redis中预存不重复的code, 再取出用作生成流水号以保证不重复, code数量不足时位数自动增加一位, 每天凌晨0点清理预存
   *
   * @param digits 位数
   * @param prefix 前缀
   * @return Boolean
   * @author huangkl
   */
  public String getNO(Integer digits, String prefix) {
    Preconditions.checkNotNull(digits, "位数不能为空");
    Preconditions.checkArgument(digits < 7, "位数不能超过六位");
    Preconditions.checkArgument(!StringUtils.isEmpty(prefix), "前缀不能为空");
    String code = getCode(digits);
    String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    return prefix + date + code;
  }

  private String getCode(Integer digits) {
    String key = REDIS_CACHE_KEY + digits;
    Integer code = (Integer) redisTemplate.opsForSet().pop(key);
    if (code == null) {
      Integer[] nos = generateCodes(digits);
      redisTemplate.opsForSet().add(key, nos);
      redisTemplate.expire(key, getNowToNextDaySeconds(), TimeUnit.SECONDS);
      code = (Integer) redisTemplate.opsForSet().pop(key);
    } else {
      if (redisTemplate.opsForSet().size(key) == 0) {
        // code用完了,向下一位进
        int length = code.toString().length() + 1;
        Integer[] list = generateCodes(length);
        redisTemplate.opsForSet().add(key, list);
        redisTemplate.expire(key, getNowToNextDaySeconds(), TimeUnit.SECONDS);
      }
    }
    return code.toString();
  }

  private Integer[] generateCodes(Integer digits) {
    StringBuffer minString = new StringBuffer("1");
    StringBuffer maxString = new StringBuffer("9");
    List<Integer> list = new ArrayList<>();
    for (int i = 1; i < digits; i++) {
      minString.append("0");
      maxString.append("9");
    }
    int min = Integer.parseInt(minString.toString());
    int max = Integer.parseInt(maxString.toString());
    for (int k = min; k <= max; k++) {
      list.add(k);
    }
    Integer[] array = list.toArray(new Integer[list.size()]);
    return array;
  }
  /**
   * 计算第二天凌晨与当前时间的时间差秒数
   *
   * @param
   * @return java.lang.Long
   * @author huangkl
   */
  private Long getNowToNextDaySeconds() {
    Calendar cal = Calendar.getInstance();
    cal.add(Calendar.DAY_OF_YEAR, 1);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return (cal.getTimeInMillis() - System.currentTimeMillis()) / 1000;
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值