首页 > 编程语言 >【Java】单号创建服务

【Java】单号创建服务

时间:2022-12-16 23:44:50浏览次数:47  
标签:服务 String int 创建 length newCode import Java condition

 

需求:ERP项目存在若干个业务功能,每个业务的单子的单号创建规则需要被统一规划

1、每个业务有自己对应的标识

2、业务单号必须以英文字母为前缀,长度在2 - 4个字符

3、单号的组成 = [ 前缀 ] + [ 日期单位(8) ] + [ 当前序列 ]

4、日期单位可以灵活设置,按年,月,日为单位,即中间的8位精确到什么日期单位

5、结尾对【当前序列】自增后进行补位填充,拼接后就是新的单号

 

设计的表结构:

1、业务标识 + 前缀 + 日期单位(年,月,日) 组合为唯一键

2、表的维护全靠建单逻辑执行(只有新增和更新操作)

CREATE TABLE `sys_co_servcode` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '系统编码 主键,初始值为“100001”',
  `sc_serv_ident` varchar(32) NOT NULL COMMENT '业务标识 参见业务标识对照表<类:ServiceIdentEnum>',
  `sc_prifix` varchar(4) NOT NULL COMMENT '编码前缀 默认用两位,最长四位;',
  `sc_year` char(4) NOT NULL COMMENT '所属年',
  `sc_month` char(2) NOT NULL COMMENT '所属月',
  `sc_day` char(2) NOT NULL COMMENT '所属日',
  `sc_num` int(11) NOT NULL COMMENT '当前编号',
  `create_time` datetime NOT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=100012 DEFAULT CHARSET=utf8 COMMENT='业务编码表';

  

设计的接口服务:

1、接口设定了单号长度设置,需要校验单号长度是否不足

2、日期根据字段信息,需要自己计算年月日,所以这里弄成枚举类型作为入参

package cn.hyite.amerp.system.common.servcode.service;

import cn.hyite.amerp.system.common.servcode.dto.DateUnit;

/**
 * sys_co_servcode 业务编码表 服务类
 *
 * @author OnCloud9
 * @version 1.0
 * @project server
 * @date 2022-12-15
 */
public interface ISysCoServcodeService {

    /**
     * 根据 [业务标识] + [前缀定义] + [日期精度] + [单号总长度] 创建最新的单号
     * @param servIdent 业务标识
     * @param codePrefix 编号前缀定义(2 ~ 4)字符长度
     * @param dateUnit 日期单位 [year, month, day]
     * @param length 单号总长度
     * @return String 最新业务编号
     * @author OnCloud9
     * @date 2022/12/15 14:08
     *
     */
    String createServiceCode(String servIdent, String codePrefix, DateUnit dateUnit, Integer length);
}

 

考虑到单号可变长度,每个日期枚举对应设置了长度限制,方便接口实现做长度计算校验

package cn.hyite.amerp.system.common.servcode.dto;

import lombok.Getter;

/**
 * 日期单位枚举类
 *
 * @author OnCloud9
 * @version 1.0
 * @project server
 * @date 2022年12月15日 14:36
 */
@Getter
public enum DateUnit {
    YEAR(4),
    MONTH(6),
    DAY(8)
    ;
    public static final int TOTAL_LENGTH = 8;
    private final int length;
    DateUnit(int length) {
        this.length = length;
    }
}

  

接口实现:

1、一个新的业务建单规则没有使用时,调用后记录规则,返回单号

2、再次调用时,根据记录获取最新单号,更新记录的单号后,返回单号

package cn.hyite.amerp.system.common.servcode.service.impl;

import cn.hyite.amerp.common.ResultMessage;
import cn.hyite.amerp.common.service.BaseService;
import cn.hyite.amerp.common.util.Assert;
import cn.hyite.amerp.system.common.servcode.dao.SysCoServcodeDAO;
import cn.hyite.amerp.system.common.servcode.dto.DateUnit;
import cn.hyite.amerp.system.common.servcode.dto.SysCoServcodeDTO;
import cn.hyite.amerp.system.common.servcode.service.ISysCoServcodeService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.text.NumberFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Objects;

/**
 * sys_co_servcode 业务编码表 服务实现类
 *
 * @project server
 * @author OnCloud9
 * @date 2022-12-15
 * @version 1.0
 */
@Service("sysCoServcodeService")
public class SysCoServcodeServiceImpl extends BaseService<SysCoServcodeDAO, SysCoServcodeDTO> implements ISysCoServcodeService {

    private static final Integer PREFIX_LIMIT = 4;
    private static final String SPACER = "00";
    private static final String FIELD_YEAR = "sc_year";
    private static final String FIELD_MONTH = "sc_month";
    private static final String FIELD_DAY = "sc_day";

    @Override
    public String createServiceCode(String servIdent, String codePrefix, DateUnit dateUnit, Integer length) {
        /* Step1 校验入参合法性 */
        Assert.isTrue(StringUtils.isBlank(servIdent), ResultMessage.NULL_ERROR, "业务标识");
        Assert.isTrue(StringUtils.isBlank(codePrefix), ResultMessage.NULL_ERROR, "业务前缀");
        final int prefixLen = codePrefix.length();
        Assert.isTrue(prefixLen > PREFIX_LIMIT, ResultMessage.CUSTOM_ERROR, "业务前缀长度超出限制!" + prefixLen);
        final int dateUnitLength = DateUnit.TOTAL_LENGTH;
        Assert.isTrue(prefixLen + dateUnitLength + 1 > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!");

        /* Step2 组建查询条件, 封装日期单位条件 */
        QueryWrapper<SysCoServcodeDTO> condition = Wrappers.query();
        condition.eq("sc_serv_ident", servIdent);
        condition.eq("sc_prifix", codePrefix);

        LocalDateTime nowTime = LocalDateTime.now();
        String year = String.valueOf(nowTime.getYear());
        String month = String.valueOf(nowTime.getMonth().getValue());
        String day = String.valueOf(nowTime.getDayOfMonth());
        switch (dateUnit) {
            case YEAR:
                condition.eq(FIELD_YEAR, year);
                condition.eq(FIELD_MONTH, SPACER);
                condition.eq(FIELD_DAY, SPACER);
                break;
            case MONTH:
                condition.eq(FIELD_YEAR, year);
                condition.eq(FIELD_MONTH, month);
                condition.eq(FIELD_DAY, SPACER);
                break;
            case DAY:
                condition.eq(FIELD_YEAR, year);
                condition.eq(FIELD_MONTH, month);
                condition.eq(FIELD_DAY, day);
                break;
        }

        /* Step3 查询是否存在此规则的建单记录 */
        SysCoServcodeDTO serviceCode = baseMapper.selectOne(condition);
        boolean isEmpty = Objects.isNull(serviceCode);

        if (isEmpty) {
            /* 二次校验总长度 */
            int totalLength = prefixLen + dateUnitLength + 1;
            Assert.isTrue(totalLength > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!(新建时)");

            /* 新建记录,新记录时,设置新的日期单位 */
            int newNum = 1;
            String dateCode = "";
            SysCoServcodeDTO newCode = new SysCoServcodeDTO();
            newCode.setScServIdent(servIdent);
            newCode.setScPrifix(codePrefix);
            newCode.setCreateTime(new Date());
            newCode.setScNum(newNum);
            newCode.setScYear(year);
            switch (dateUnit) {
                case YEAR:
                    newCode.setScMonth(SPACER);
                    newCode.setScDay(SPACER);
                    dateCode += (year + SPACER + SPACER);
                    break;
                case MONTH:
                    newCode.setScMonth(month);
                    newCode.setScDay(SPACER);
                    dateCode += (year + month + SPACER);
                    break;
                case DAY:
                    newCode.setScMonth(month);
                    newCode.setScDay(day);
                    dateCode += (year + month + day);
                    break;
            }
            baseMapper.insert(newCode);

            int remainLen = length - (prefixLen + dateUnitLength);

            /* 返回单号 */
            return codePrefix + dateCode + formatNumDigit(remainLen, newNum);
        } else {
            /* 取当前单号 */
            Integer currentNum = serviceCode.getScNum();
            ++ currentNum;

            /* 更新最新单号 */
            serviceCode.setScNum(currentNum);
            baseMapper.updateById(serviceCode);

            String numStr = String.valueOf(currentNum);
            final int numLength = numStr.length();

            /* 二次校验总长度 */
            int totalLength = prefixLen + dateUnitLength + numLength;
            Assert.isTrue(totalLength > length, ResultMessage.CUSTOM_ERROR, "单号总长溢出!(更新时)");

            int remainLen = length - (prefixLen + dateUnitLength);
            /* 返回单号 */
            return codePrefix + serviceCode.getScYear() + serviceCode.getScMonth() + serviceCode.getScDay() + formatNumDigit(remainLen, currentNum);
        }
    }

    /**
     * 计数值补位
     * @param remainLen 剩余长度
     * @param serial 序列计数值
     * @return java.lang.String 补位后的序列值
     * @author OnCloud9
     * @date 2022/12/15 16:49
     *
     */
    private String formatNumDigit(int remainLen, int serial) {
        NumberFormat formatter = NumberFormat.getNumberInstance();
        formatter.setMinimumIntegerDigits(remainLen);
        formatter.setGroupingUsed(false);
        return formatter.format(serial);
    }

}

  

 

标签:服务,String,int,创建,length,newCode,import,Java,condition
From: https://www.cnblogs.com/mindzone/p/16988505.html

相关文章

  • JAVA学习日记--Scanner类
     1。导包import包路径.类名称;如果需要使用的目标类,和当前类位于同一个包下。则可以省略导包语句不写。只有java.Lang包下的内容不需要导包,其他的包都需要import语句。2......
  • 【java-02】Nginx以及前后端分离项目在linux上的部署
    目录写在开头Nginx重点目录/文件配置文件结构server块反向代理负载均衡写在开头本篇主要介绍了nginx的简单使用,包括目录结构、配置文件结构、反向代理和负载均衡等。以及......
  • Linux下突破限制实现高并发量服务器
    1、修改用户进程可打开文件数限制在Linux平台上,无论编写客户端程序还是服务端程序,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文......
  • Java亿级项目架构设计与落地应用 学习计划 最后附上下载地址
    Java亿级项目架构设计与落地应用 学习计划最后附上下载地址从分析应用到实际落地,完成支撑高并发读(60万/秒)的架构方案。学习架构演变的过程,同时将核心功能应用向服务器进......
  • 【Azure 存储服务】Azure Storage Account Queue中因数据格式无法处理而在一个小时内
    问题描述在从StorageAccount队列中获取数据(Queue),在门户中,明显看见有数据,但是通过消费端代码去获取的时候,就是无法获取到有效数据的情况。获取消息的代码如下:  ......
  • 设计模式--创建型模式
    创建型模式      创建型模式的作用就是创建对象,说到创建一个对象,最熟悉的就是new一个对象,然后set相关属性。但是,在很多场景下,我们需要给客户端提供更加友......
  • Javascript | 分别用async await异步方法和Promise来实现一个简易的求职程序
     关注公众号,一起交流,微信搜一搜:LiOnTalKING JavaScriptPromisePromise是一个ECMAScript6提供的类,目的是更加优雅地书写复杂的异步任务。如何创建一个Pro......
  • JAVA并发-Disruptor框架
    JAVA并发-Disruptor框架Disruptor简介最好的方法去理解Disruptor就是将它和容易理解并且相似的队列,例如BlockingQueue。Disruptor其实就像一个队列一样,用于在不同的线程......
  • Java虚拟机定义
    虚拟机是一种抽象化的​​计算机​​​,通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机有自己完善的​​​硬体​​​架构,如​​​处理器​​......
  • 【公众号】JAVA微信公众号技术大佬文章精选
    ​​百亿规模API网关服务Shepherd的设计与实现​​ ​​面渣逆袭:Redis连环五十二问!三万字+八十图详解!​​​​面渣逆袭:Spring三十五问,四万字+五十图详解!建议收藏!​​​​面......