diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenService.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenService.java new file mode 100644 index 00000000..d300a70c --- /dev/null +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenService.java @@ -0,0 +1,18 @@ +package cn.code.nl.module.base.service.codegen; + +/** + * 编码生成 Service 接口 + * + * @author zhouz + */ +public interface CodeGenService { + + /** + * 根据规则编码生成编码字符串 + * + * @param ruleCode 规则编码 + * @return 生成的编码 + */ + String generate(String ruleCode); + +} diff --git a/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenServiceImpl.java b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenServiceImpl.java new file mode 100644 index 00000000..ba869821 --- /dev/null +++ b/nl-module-base/nl-module-base-server/src/main/java/cn/code/nl/module/base/service/codegen/CodeGenServiceImpl.java @@ -0,0 +1,120 @@ +package cn.code.nl.module.base.service.codegen; + +import cn.code.nl.module.base.dal.dataobject.codegen.CodeRuleDO; +import cn.code.nl.module.base.service.codegen.dto.DateSegment; +import cn.code.nl.module.base.service.codegen.dto.PrefixSegment; +import cn.code.nl.module.base.service.codegen.dto.SegmentConfig; +import cn.code.nl.module.base.service.codegen.dto.SequenceSegment; +import cn.code.nl.module.base.service.codegen.enums.LetterCaseEnum; +import cn.code.nl.module.base.service.codegen.enums.SeqStrategyEnum; +import cn.hutool.core.util.StrUtil; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static cn.code.nl.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.code.nl.module.base.enums.ErrorCodeConstants.CODE_GEN_LENGTH_EXCEED; + +/** + * 编码生成引擎实现类 + * + * @author zhouz + */ +@Slf4j +@Service +@Validated +public class CodeGenServiceImpl implements CodeGenService { + + @Resource + private CodeRuleService codeRuleService; + + @Resource + private SequenceAllocator sequenceAllocator; + + @Override + public String generate(String ruleCode) { + // 1. 获取规则配置(带缓存) + CodeRuleDO rule = codeRuleService.getRuleByCode(ruleCode); + + // 2. 遍历分段配置,逐段生成 + List segments = rule.getSegmentConfig(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < segments.size(); i++) { + String segmentValue = buildSegment(rule, segments.get(i)); + sb.append(segmentValue); + // 段之间加分隔符 + if (i < segments.size() - 1 && StrUtil.isNotBlank(rule.getSeparator())) { + sb.append(rule.getSeparator()); + } + } + + // 3. 后处理 + return postProcess(sb.toString(), rule); + } + + /** + * 根据段类型分发处理,生成段值 + */ + private String buildSegment(CodeRuleDO rule, SegmentConfig segment) { + return switch (segment.getType()) { + case "PREFIX" -> buildPrefixSegment((PrefixSegment) segment); + case "DATE" -> buildDateSegment((DateSegment) segment); + case "SEQUENCE" -> buildSequenceSegment(rule, (SequenceSegment) segment); + default -> throw new IllegalArgumentException("不支持的段类型: " + segment.getType()); + }; + } + + /** + * 生成固定前缀段 + */ + private String buildPrefixSegment(PrefixSegment segment) { + return segment.getValue() != null ? segment.getValue() : ""; + } + + /** + * 生成日期段 + */ + private String buildDateSegment(DateSegment segment) { + String format = StrUtil.isNotBlank(segment.getFormat()) + ? segment.getFormat() : "yyyyMMdd"; + return LocalDate.now().format(DateTimeFormatter.ofPattern(format)); + } + + /** + * 生成流水序号段 + */ + private String buildSequenceSegment(CodeRuleDO rule, SequenceSegment segment) { + String strategy = rule.getSeqStrategy(); + if (SeqStrategyEnum.LOCK.getCode().equals(strategy)) { + return sequenceAllocator.allocateByLock(rule.getId(), segment); + } + return sequenceAllocator.allocateBySegment(rule.getId(), segment); + } + + /** + * 后处理:大小写转换 + 总长度校验 + */ + private String postProcess(String code, CodeRuleDO rule) { + // 大小写转换 + if (rule.getLetterCase() != null && rule.getLetterCase() == LetterCaseEnum.UPPER.getCode()) { + code = code.toUpperCase(); + } else if (rule.getLetterCase() != null && rule.getLetterCase() == LetterCaseEnum.LOWER.getCode()) { + code = code.toLowerCase(); + } + + // 总长度校验 + if (rule.getTotalLength() != null && rule.getTotalLength() > 0 && code.length() > rule.getTotalLength()) { + log.error("生成的编码超出总长度限制,code={}, length={}, maxLength={}", + code, code.length(), rule.getTotalLength()); + throw exception(CODE_GEN_LENGTH_EXCEED); + } + + return code; + } + +}