|
|
@@ -1,9 +1,15 @@
|
|
|
package com.lc.ibps.cloud.identifier.provider;
|
|
|
|
|
|
+import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Optional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
|
|
|
+import com.lc.ibps.base.web.context.ContextUtil;
|
|
|
+import com.lc.ibps.common.system.helper.IdentityBuilder;
|
|
|
+import com.lc.ibps.components.cache.redis.entity.SwiftConfig;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.web.bind.annotation.RequestBody;
|
|
|
import org.springframework.web.bind.annotation.RequestParam;
|
|
|
@@ -33,6 +39,7 @@ import io.swagger.annotations.ApiOperation;
|
|
|
import io.swagger.annotations.ApiParam;
|
|
|
import io.swagger.annotations.Extension;
|
|
|
import io.swagger.annotations.ExtensionProperty;
|
|
|
+import org.codehaus.jackson.map.ObjectMapper;
|
|
|
|
|
|
@Api(tags = "编号中心", value = "流水号")
|
|
|
@Service
|
|
|
@@ -264,5 +271,129 @@ public class IdentityProvider extends GenericProvider implements IIdentifierServ
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 回收格式化编号,从格式化编号中解析出序列号并回收到Redis回收池中供后续复用。
|
|
|
+ * 仅川北中医环境(CBYY=true)会执行回收逻辑,其他环境直接跳过。
|
|
|
+ *
|
|
|
+ * @param alias 流水号别名,用于查找对应的流水号配置
|
|
|
+ * @param formattedNumber 已格式化的编号字符串,如 "BFH-2026-05"
|
|
|
+ * @return APIResult<Void> 操作结果,成功时message为"流水号回收成功"
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ @ApiOperation(value = "回收格式化编号", notes = "从格式化编号中解析序列号并回收")
|
|
|
+ public APIResult<Void> recycleFormattedNumber(
|
|
|
+ @ApiParam(name = "alias", value = "别名", required = true)
|
|
|
+ @RequestParam(name = "alias", required = true) String alias,
|
|
|
+ @ApiParam(name = "formattedNumber", value = "格式化编号", required = true)
|
|
|
+ @RequestParam(name = "formattedNumber", required = true) String formattedNumber){
|
|
|
+ APIResult<Void> result = new APIResult<>();
|
|
|
+ try{
|
|
|
+ String setting = ContextUtil.getSetting();
|
|
|
+ boolean isDgyy = false;//后续可以通过该按钮关闭该功能
|
|
|
+ if (org.apache.commons.lang3.StringUtils.isNotEmpty(setting)) {
|
|
|
+ ObjectMapper objectMapper = new ObjectMapper();
|
|
|
+ HashMap<String, Object> map = (HashMap) objectMapper.readValue(setting, Map.class);
|
|
|
+ String cbyy = Optional.ofNullable(map)
|
|
|
+ .map(m -> m.get("CBYY"))
|
|
|
+ .map(Object::toString)
|
|
|
+ .orElse("");
|
|
|
+ isDgyy = Boolean.parseBoolean(cbyy);
|
|
|
+ }
|
|
|
+ if (!isDgyy) {
|
|
|
+ result.setMessage("非川北中医环境, 跳过编号回收");
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ //logger.warn("【编号回收】开始warn, alias={}, formattedNumber={}", alias, formattedNumber);
|
|
|
+ //logger.info("【编号回收】开始info, alias={}, formattedNumber={}", alias, formattedNumber);
|
|
|
+ IdentityPo po = identityRepository.getPoByAlias(alias);
|
|
|
+ if(BeanUtils.isNotEmpty(po)){
|
|
|
+ SwiftConfig swiftConfig = new SwiftConfig();
|
|
|
+ swiftConfig = IdentityBuilder.builderSwiftConfig(po, swiftConfig);
|
|
|
+ swiftConfig.setAlias(alias);
|
|
|
+
|
|
|
+ //logger.warn("【编号回收】模板tpl={}, noLength={}, genType={}", swiftConfig.getTpl(), swiftConfig.getSwiftNumberLen(), swiftConfig.getSwiftGenType());
|
|
|
+
|
|
|
+ long seqNum = extractSequenceNumber(formattedNumber, swiftConfig);
|
|
|
+
|
|
|
+ String cacheKey = swiftConfig.getCacheKey() + alias;
|
|
|
+ int expireSeconds = swiftConfig.getCacheDays();
|
|
|
+ //logger.warn("【编号回收】提取序列号={}, cacheKey={}, expireSeconds={}", seqNum, cacheKey, expireSeconds);
|
|
|
+
|
|
|
+ com.lc.ibps.components.cache.redis.RedisUtil.Singleton.getInstance()
|
|
|
+ .recycleNumber(cacheKey, seqNum, expireSeconds);
|
|
|
+ //logger.warn("【编号回收】回收成功, 序列号={} 已推入回收池", seqNum);
|
|
|
+ System.out.println("【编号回收】回收成功, 序列号="+seqNum+" 已推入回收池");
|
|
|
+ result.setMessage("流水号回收成功");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ throw new BaseException("流水号别名[" + alias + "]不存在");
|
|
|
+ }
|
|
|
+ }catch(Exception e){
|
|
|
+ logger.error("【编号回收】异常, alias={}, formattedNumber={}", alias, formattedNumber, e);
|
|
|
+ setExceptionResult(result, StateEnum.ERROR_IDENTITIFIER.getCode(), I18nUtil.getMessage(StateEnum.ERROR_IDENTITIFIER.getCode()+""), e);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 从格式化编号中提取纯序列号部分。
|
|
|
+ * 提取策略按优先级依次为:前缀匹配 → 正则匹配 → 末位数字兜底。
|
|
|
+ *
|
|
|
+ * @param formattedNumber 已格式化的编号字符串,如 "BFH-2026-05",
|
|
|
+ * 注意必须是ibps_system_identity.REGULATION_中值{NO}在末尾才可以
|
|
|
+ * @param swiftConfig 流水号配置,包含模板tpl和序列号长度noLength
|
|
|
+ * @return 提取出的纯序列号数值,如 5
|
|
|
+ */
|
|
|
+ private long extractSequenceNumber(String formattedNumber, SwiftConfig swiftConfig) {
|
|
|
+ String tpl = swiftConfig.getTpl();
|
|
|
+ int noLen = swiftConfig.getSwiftNumberLen();
|
|
|
+
|
|
|
+ String prefix;
|
|
|
+ if (tpl.contains("{NO}")) {
|
|
|
+ int noIdx = tpl.indexOf("{NO}");
|
|
|
+ prefix = tpl.substring(0, noIdx);
|
|
|
+ } else {
|
|
|
+ int noIdx = tpl.indexOf("{no}");
|
|
|
+ prefix = tpl.substring(0, noIdx);
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> dateParams = new HashMap<>();
|
|
|
+ dateParams.put("{yyyy}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowY());
|
|
|
+ dateParams.put("{yy}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowPart("yy"));
|
|
|
+ dateParams.put("{MM}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowPart("MM"));
|
|
|
+ dateParams.put("{M}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowPart("M"));
|
|
|
+ dateParams.put("{dd}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowPart("dd"));
|
|
|
+ dateParams.put("{d}", com.lc.ibps.base.core.util.time.DateFormatUtil.getNowPart("d"));
|
|
|
+ for (Map.Entry<String, String> entry : dateParams.entrySet()) {
|
|
|
+ prefix = prefix.replace(entry.getKey(), entry.getValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.info("【编号提取】formattedNumber={}, 前缀prefix={}, noLength={}", formattedNumber, prefix, noLen);
|
|
|
+
|
|
|
+ if (formattedNumber.startsWith(prefix)) {
|
|
|
+ String seqPart = formattedNumber.substring(prefix.length());
|
|
|
+ logger.info("【编号提取】前缀匹配成功, 序列部分={}", seqPart);
|
|
|
+ return Long.parseLong(seqPart);
|
|
|
+ }
|
|
|
+
|
|
|
+ logger.warn("【编号提取】前缀匹配失败, 尝试正则匹配. prefix={}, formattedNumber={}", prefix, formattedNumber);
|
|
|
+ java.util.regex.Pattern p = java.util.regex.Pattern.compile(
|
|
|
+ java.util.regex.Pattern.quote(prefix) + "(\\d+)");
|
|
|
+ java.util.regex.Matcher m = p.matcher(formattedNumber);
|
|
|
+ if (m.matches()) {
|
|
|
+ logger.info("【编号提取】正则匹配成功, 序列号={}", m.group(1));
|
|
|
+ return Long.parseLong(m.group(1));
|
|
|
+ }
|
|
|
+
|
|
|
+ String digits = formattedNumber.replaceAll("\\D+", "");
|
|
|
+ logger.warn("【编号提取】正则匹配也失败, 走fallback. 所有数字={}, noLength={}", digits, noLen);
|
|
|
+ if (digits.length() >= noLen) {
|
|
|
+ long fallback = Long.parseLong(digits.substring(digits.length() - noLen));
|
|
|
+ logger.warn("【编号提取】fallback取末{}位={}", noLen, fallback);
|
|
|
+ return fallback;
|
|
|
+ }
|
|
|
+ return Long.parseLong(digits);
|
|
|
+ }
|
|
|
+
|
|
|
}
|