liyong
6 天以前 536774eea8902efc088c5b904ff75bbe0af33418
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package cn.iocoder.yudao.module.mes.service.md.autocode;
 
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodePartDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRecordDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.autocode.MesMdAutoCodeRuleDO;
import cn.iocoder.yudao.module.mes.dal.mysql.md.autocode.MesMdAutoCodeRecordMapper;
import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodePaddedMethodEnum;
import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodeContext;
import cn.iocoder.yudao.module.mes.service.md.autocode.strategy.MesMdAutoCodePartStrategy;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
 
import java.util.List;
import java.util.Map;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/**
 * MES 编码生成记录 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class MesMdAutoCodeRecordServiceImpl implements MesMdAutoCodeRecordService {
 
    private static final int GENERATE_MAX_RETRY_COUNT = 10;
 
    @Resource
    private MesMdAutoCodeRecordMapper recordMapper;
 
    @Resource
    private MesMdAutoCodeRuleService ruleService;
    @Resource
    private MesMdAutoCodePartService partService;
 
    @Resource
    private List<MesMdAutoCodePartStrategy> strategyList;
    private Map<Integer, MesMdAutoCodePartStrategy> strategyMap;
 
    @PostConstruct
    public void init() {
        strategyMap = CollectionUtils.convertMap(strategyList, MesMdAutoCodePartStrategy::getType);
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generateAutoCode(String ruleCode, String inputChar) {
        // 1.1 查询规则
        MesMdAutoCodeRuleDO rule = ruleService.getAutoCodeRuleByCode(ruleCode);
        if (rule == null) {
            throw exception(AUTO_CODE_RULE_NOT_EXISTS);
        }
        // 1.2 查询规则组成
        List<MesMdAutoCodePartDO> parts = partService.getAutoCodePartListByRuleId(rule.getId());
        if (CollUtil.isEmpty(parts)) {
            throw exception(AUTO_CODE_GENERATE_FAILED);
        }
 
        // 2. 循环生成编码,跳过因 Redis 流水号落后导致的历史重复编码
        for (int i = 0; i < GENERATE_MAX_RETRY_COUNT; i++) {
            // 2.1 生成编码
            MesMdAutoCodeContext context = new MesMdAutoCodeContext()
                    .setRule(rule).setParts(parts).setInputChar(inputChar);
            String result = generateCode(rule, parts, context);
            // 2.2 二次校验(防止重复)
            MesMdAutoCodeRecordDO existRecord = recordMapper.selectByResult(result);
            if (existRecord != null) {
                continue;
            }
            // 2.3 保存生成记录
            MesMdAutoCodeRecordDO record = new MesMdAutoCodeRecordDO()
                    .setRuleId(rule.getId()).setResult(result)
                    .setSerialNo(context.getSerialNo()).setInputChar(inputChar);
            recordMapper.insert(record);
            return result;
        }
 
        // 3. 重试多次后仍然失败,抛出异常
        throw exception(AUTO_CODE_GENERATE_FAILED);
    }
 
    /**
     * 生成编码
     */
    private String generateCode(MesMdAutoCodeRuleDO rule, List<MesMdAutoCodePartDO> parts,
                                MesMdAutoCodeContext context) {
        StringBuilder codeBuilder = new StringBuilder();
        for (MesMdAutoCodePartDO part : parts) {
            MesMdAutoCodePartStrategy strategy = strategyMap.get(part.getType());
            Assert.notNull(strategy, () -> exception(AUTO_CODE_GENERATE_FAILED));
            // 生成分段编码
            String partCode = strategy.generate(part, context);
            // 统一截取指定长度
            partCode = StrUtil.sub(partCode, 0, part.getLength());
            // 拼接分段编码
            codeBuilder.append(partCode);
        }
        // 补齐处理
        String result = codeBuilder.toString();
        if (Boolean.TRUE.equals(rule.getPadded()) && rule.getMaxLength() != null) {
            result = padCode(result, rule);
        }
        return result;
    }
 
    /**
     * 补齐编码
     */
    private String padCode(String code, MesMdAutoCodeRuleDO rule) {
        if (code.length() >= rule.getMaxLength()) {
            return StrUtil.sub(code, 0, rule.getMaxLength());
        }
        String paddedChar = StrUtil.emptyToDefault(rule.getPaddedChar(), "0");
        Integer paddedMethod = rule.getPaddedMethod() != null ? rule.getPaddedMethod() : MesMdAutoCodePaddedMethodEnum.LEFT.getMethod();
        if (MesMdAutoCodePaddedMethodEnum.LEFT.getMethod().equals(paddedMethod)) {
            // 左补齐
            return StrUtil.padPre(code, rule.getMaxLength(), paddedChar.charAt(0));
        } else {
            // 右补齐
            return StrUtil.padAfter(code, rule.getMaxLength(), paddedChar.charAt(0));
        }
    }
 
}