欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

springboot+redis实现定制化的单据号或流水号

程序员文章站 2022-07-15 13:26:13
...

一、业务场景

公司各种业务都用到一个批次号、版本号、流水号等,这些号码都需要由一定的规律去生成,并且要实现自增的或者带特殊编号的功能。实现的方式有很多种,可以通过数据库表的自增来实现,也可以通过Redis的string类型的自增方法。现在就两种方式来对比一下。

二、springboot+Redis实现自增

1、导入Redis依赖

 <dependencies>             

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
    </dependencies>

2、编写service公共接口

/**
 * 生成编号
 * @author 
 */
public interface NumberGenService {

    /**
     * 根据code生成编号
     * 例:01
     * @param code 前缀
     * @return 编号
     */
    String generateNumber(String code);

    /**
     * 根据code及年月生成编号
     * 例子:20190501
     * @param code 前缀
     * @return 编号
     */
    String generateNumberByMonth(String code);


    /**
     * 根据code及年月日生成编号
     * 例子:2019050801
     * @param code 前缀
     * @return 编号
     */
    String generateNumberByDay(String code);

    /**
     * 根据code及年月日生成编号
     * 例子:2019050801
     * @param code 前缀
     * @param length 编号长度
     * @return 编号
     */
    String generateNumberByDay(String code, int length);
}

3、serviceImpl

import com.ehe.core.thread.LocalVariable;
import com.ehe.elder.service.NumberGenService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * 生成编号
 * @author Sue
 */
@Service
public class NumberGenServiceImpl implements NumberGenService {

    /** redis操作String */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final int LENGTH = 2;

    private static final DateTimeFormatter MONTH_FORMAT = DateTimeFormatter.ofPattern("yyyyMM");

    private static final DateTimeFormatter DAY_FORMAT = DateTimeFormatter.ofPattern("yyyyMMdd");

    @Override
    public String generateNumber (String code) {
        return getNumber(code, "", LENGTH);
    }

    @Override
    public String generateNumberByMonth (String code) {
        return getNumber(code, MONTH_FORMAT.format(LocalDate.now()), LENGTH);
    }

    @Override
    public String generateNumberByDay (String code) {
        return getNumber(code, DAY_FORMAT.format(LocalDate.now()), LENGTH);
    }

    @Override
    public String generateNumberByDay(String code, int length) {
        return getNumber(code, DAY_FORMAT.format(LocalDate.now()), length);
    }

    private String getNumber(String code, String month, int length) {
        // LocalVariable.getTenantCode() 租户编号,可以自己定义一个
        String key = LocalVariable.getTenantCode() + ":" + code + ":" + month;
        Long number = stringRedisTemplate.opsForValue().increment(key);
        return month + StringUtils.leftPad(number != null ? number.toString() : "1", length, '0');
    }
}

三、通过数据库自增实现

1、pojo

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
/**
 * @author 陳燃
 */
@Data
public class CreditAutoCode implements Serializable {

    private Long id;

    private Long year;

    private String createBy;

    private Date createTime;

    private String updateBy;

    private Date updateTime;

    private Byte delFlag;

    private String remark;

    private Long autoId;

}

2、工具

   /**
     * 获取编号:202012345
     * @return
     */
    private synchronized Long findCode(CurrentUser user) {
        Long code = null;
        //获取最大编号
        CreditAutoCode autoCode = creditAutoCodeMapper.selectCode();
        Long nowYear = Long.valueOf(
                DateUtils.format(new Date(),DateUtils.DATE_PATTERN).substring(0,4).replaceAll("-",""));
        CreditAutoCode creditAutoCode = new CreditAutoCode();
        //最大年份为null,重新计算年份自增
        if (autoCode == null || autoCode.getAutoId() == null){
            code = Long.valueOf(getNewEquipmentNo(nowYear.toString(),null));

            creditAutoCode.setYear(nowYear);
            creditAutoCode.setCreateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
            creditAutoCode.setCreateTime(new Date());
            creditAutoCode.setUpdateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
            creditAutoCode.setUpdateTime(new Date());
            creditAutoCode.setAutoId(1L);
            creditAutoCodeMapper.insert(creditAutoCode);
            return code;
        }
        //年份不匹配,重新计算自增
        if (!nowYear.equals(autoCode.getYear())){
            code = Long.valueOf(getNewEquipmentNo(nowYear.toString(),null));

            creditAutoCode.setYear(nowYear);
            creditAutoCode.setCreateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
            creditAutoCode.setCreateTime(new Date());
            creditAutoCode.setUpdateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
            creditAutoCode.setUpdateTime(new Date());
            creditAutoCode.setAutoId(1L);
            creditAutoCodeMapper.insert(creditAutoCode);
            return code;
        }
        String newCode = getNewEquipmentNo(nowYear.toString(),autoCode.getAutoId().toString());
        code = Long.valueOf(newCode);

        creditAutoCode.setYear(nowYear);
        creditAutoCode.setCreateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
        creditAutoCode.setCreateTime(new Date());
        creditAutoCode.setUpdateBy(user == null ? CommonConstant.SYSTEM : user.getShowName());
        creditAutoCode.setUpdateTime(new Date());
        creditAutoCode.setAutoId(autoCode.getAutoId()+1);
        creditAutoCodeMapper.insert(creditAutoCode);
        return code;
    }
    /**
     *
     * @param equipmentType : 单据前缀,年份
     * @param equipmentNo:自增编号
     * @return
     */
    public static String getNewEquipmentNo(String equipmentType, String equipmentNo){
        String newEquipmentNo = equipmentType + "00001";
        if(equipmentNo != null && !equipmentNo.isEmpty()){
            int no = Integer.parseInt(equipmentNo);
            int newEquipment = ++no;
            newEquipmentNo = String.format(equipmentType + "%05d", newEquipment);
        }
        return newEquipmentNo;
    }