yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/BizNoUtils.java
@@ -1,29 +1,30 @@ package cn.iocoder.yudao.framework.common.util.number; import java.util.concurrent.ThreadLocalRandom; /** * ä¸å¡ç¼ç ï¼åæ®å· / ä¸»æ°æ®ç¼ç ï¼çæçå ¬å ±çº¦å®ã * * <p>éæ±ï¼ç³»ç»ä¸ææèªå¨çæçä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸å ¨ç³»ç»å¯ä¸ï¼ä»»æä¸¤æ¡ç¼ç é½ä¸éå¤ï¼ã * <p>éæ±ï¼ç³»ç»ä¸ææèªå¨çæçä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸**éæºçæãä¸ä½¿ç¨èªå¢/顺åº**ï¼ * åæ¶ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä»»æä¸¤æ¡ç¼ç é½ä¸éå¤ï¼ã * * <p>å®ç°çº¦å®ï¼å ¨ç³»ç»å ±ç¨åä¸ä¸ª Redis èªå¢ KEYï¼{@link #GLOBAL_SEQ_KEY}ï¼ï¼ * æ¯æ¬¡çææ¶å¯¹å ¶æ§è¡ INCR å¾å°åè°éå¢çåºåå·ï¼å左补 '0' å° {@link #CODE_LENGTH} ä½ã * ç±äºææç¼ç 齿¥èªå䏿¡éå¢åºåï¼æ 天ç¶ä¿è¯ãå ¨ç³»ç»å¯ä¸ãã * * <p>注æï¼ * <p>å®ç°çº¦å®ï¼ * <ul> * <li>该 KEY ä¸è®¾ç½®è¿ææ¶é´ï¼é¿å è¿æå½é¶å¯¼è´éå·ï¼</li> * <li>Redis è¥åçæ°æ®ä¸¢å¤± / æ¸ ç©ºï¼éè¦ä»æ°æ®åºç°æç¼ç çæå¤§å¼æ¢å¤è®¡æ°å¨ï¼å¦åå¯è½éå·ã</li> * <li>ç¼ç = éæº 16 使°åï¼èå´ 0 ~ 10^16-1ï¼å·¦ä¾§è¡¥ '0'ï¼ï¼</li> * <li>å¯ä¸æ§ç± Redis éå {@link #USED_SET_KEY} æ¥éä¿è¯ï¼éæºçæååå ¥éåï¼ * åæåï¼è¿å 1ï¼è¯´ææ²¡ç¨è¿æéç¨ï¼å¦åéè¯ï¼</li> * <li>åçæç¹ï¼è§ {@link #randomCode()} ä¸ {@link #MAX_RETRY}ã</li> * </ul> * * <p>注æï¼Redis éå丢失åï¼åå²ç¼ç å¯è½è¢«éæ°éæºå½ä¸ï¼åºç¨å¯å¨æ¶ä¼å°åºå å·²æç¼ç * éæ°è½½å ¥éåï¼è§ yudao-server çå¯å¨å åºï¼ã */ public class BizNoUtils { /** * å ¨ç³»ç»ä¸å¡ç¼ç ç»ä¸ä½¿ç¨ç Redis èªå¢ KEYã * * <p>æææ¨¡åï¼erp / crm / trade / aftersales / hrm / bpm / mesï¼å ±ç¨æ¤ KEYï¼ * 以ä¿è¯ãå ¨ç³»ç»å¯ä¸ãã * 已使ç¨ä¸å¡ç¼ç ç Redis éå KEYï¼ç¨äºéæºç¼ç æ¥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ã */ public static final String GLOBAL_SEQ_KEY = "biz:seq_no:global"; public static final String USED_SET_KEY = "biz:code:used"; /** * ä¸å¡ç¼ç çæ»é¿åº¦ï¼16 ä½ @@ -31,13 +32,24 @@ public static final int CODE_LENGTH = 16; /** * å°èªå¢åºåå·æ ¼å¼å为 16 ä½çº¯æ°åç¼ç ï¼å·¦ä¾§è¡¥ '0'ï¼ * * @param seq èªå¢åºåå· * @return 16 ä½çº¯æ°åç¼ç * éæºç¼ç ç空é´ä¸éï¼ä¸å«ï¼ï¼10^16 */ public static String format(Long seq) { return String.format("%0" + CODE_LENGTH + "d", seq); private static final long CODE_SPACE = 10_000_000_000_000_000L; /** * çæéæºç¼ç æ¶çæå¤§éè¯æ¬¡æ°ï¼å½ä¸å·²ç¨ç¼ç æ¶éè¯ï¼ */ public static final int MAX_RETRY = 10; /** * çæä¸ä¸ªéæº 16 ä½çº¯æ°åç¼ç ï¼å·¦ä¾§è¡¥ '0'ï¼ï¼**ä¸åæ¥é**ã * * <p>è°ç¨æ¹éèªè¡ç¨ {@link #USED_SET_KEY} æ¥éï¼å½ä¸åéè¯ã * * @return éæº 16 ä½çº¯æ°åç¼ç */ public static String randomCode() { return String.format("%0" + CODE_LENGTH + "d", ThreadLocalRandom.current().nextLong(CODE_SPACE)); } } yudao-module-aftersales/src/main/java/cn/iocoder/yudao/module/aftersales/dal/redis/no/AfterSaleNoRedisDAO.java
@@ -34,8 +34,15 @@ */ public String generate(String prefix) { // å ¨ç³»ç»å ±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å ¨ç³»ç»å¯ä¸ Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
@@ -27,8 +27,15 @@ */ public String generate(BpmModelMetaInfoVO.ProcessIdRule processIdRule) { // å ¨ç³»ç»å ±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å ¨ç³»ç»å¯ä¸ Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/dal/redis/no/CrmNoRedisDAO.java
@@ -47,8 +47,15 @@ */ public String generate(String prefix) { // å ¨ç³»ç»å ±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å ¨ç³»ç»å¯ä¸ Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/dal/redis/no/ErpNoRedisDAO.java
@@ -56,8 +56,15 @@ */ public String generate(String prefix) { // å ¨ç³»ç»å ±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å ¨ç³»ç»å¯ä¸ Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/redis/HrmNoRedisDAO.java
@@ -135,8 +135,15 @@ */ public String generate(String prefix, int digits) { // å ¨ç³»ç»å ±ç¨åä¸èªå¢åºåï¼ä¿è¯ç¼ç ã16 ä½çº¯æ°åãä¸å ¨ç³»ç»å¯ä¸ Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/redis/MesCodeRedisDAO.java
@@ -23,8 +23,15 @@ * @return 16 ä½çº¯æ°åç¼ç */ public String generate() { Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordServiceImpl.java
@@ -100,8 +100,15 @@ MesMdAutoCodeContext context) { // éæ±ï¼ææä¸å¡ç¼ç ç»ä¸ä¸ºã16 ä½çº¯æ°åãï¼ä¸å ¨ç³»ç»å¯ä¸ã // å æ¤ä¸åæè§ååæ®µæ¼è£ ï¼åºå®å符/æ¥ææ®µä¼å¸¦å ¥åæ¯ï¼ï¼æ¹ä¸ºåå ¨ç³»ç»ç»ä¸èªå¢åºåã Long no = stringRedisTemplate.opsForValue().increment(BizNoUtils.GLOBAL_SEQ_KEY); return BizNoUtils.format(no); // éæºçæ 16 ä½çº¯æ°åç¼ç ï¼å¹¶ç¨ Redis é忥éï¼ä¿è¯å ¨ç³»ç»å¯ä¸ï¼ä¸ä½¿ç¨èªå¢/顺åºï¼ for (int i = 0; i < BizNoUtils.MAX_RETRY; i++) { String code = BizNoUtils.randomCode(); Long added = stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, code); if (added != null && added > 0) { return code; } } throw new IllegalStateException("çæå¯ä¸ä¸å¡ç¼ç 失败ï¼è¯·éè¯"); } /** yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizCodeSetInitializer.java
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,87 @@ package cn.iocoder.yudao.server.framework.bizno; import cn.iocoder.yudao.framework.common.util.number.BizNoUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Component; import javax.sql.DataSource; import java.util.List; import java.util.Map; /** * å·²ç¨ä¸å¡ç¼ç éåå åºåå§åã * * <p>ä¸å¡ç¼ç 为ãéæº 16 ä½çº¯æ°åãï¼å¯ä¸æ§é Redis éåï¼{@link BizNoUtils#USED_SET_KEY}ï¼æ¥éã * è¥ Redis 丢失该éåï¼å·²çæçåå²ç¼ç ä¼è¢«"å¿è®°"ï¼ä¹åå¯è½è¢«éæ°éæºå½ä¸èéå·ã * * <p>å æ¤ï¼å¯å¨æ¶è¥åç°è¯¥éå **ä¸åå¨**ï¼å仿°æ®åºä¸æ«æææä¸å¡ç¼ç åéç * ã16 ä½çº¯æ°åãç¼ç ï¼éæ°è½½å ¥éåï¼æ¢å¤é²éè½åã * * <p>说æï¼ * <ul> * <li>ä» å¨éåç¼ºå¤±æ¶æ«æï¼æ£å¸¸å¯å¨æ é¢å¤å¼éï¼ï¼</li> * <li>best-effortï¼å¤±è´¥åªåè¦ãä¸å½±åå¯å¨ï¼</li> * <li>æ§ç另忝ç¼ç ä¼è¢«å¿½ç¥ã</li> * </ul> */ @Component @Slf4j public class BizCodeSetInitializer implements ApplicationRunner { /** éååå§åæ è®°ï¼é 16 ä½ï¼ä¸ä¼ä¸çå®ç¼ç å²çªï¼ï¼ç¨äºå¨åºå æ ç¼ç æ¶ä¹æ 记为已åå§å */ private static final String INIT_MARKER = "__initialized__"; private final StringRedisTemplate stringRedisTemplate; private final JdbcTemplate jdbcTemplate; public BizCodeSetInitializer(StringRedisTemplate stringRedisTemplate, DataSource dataSource) { this.stringRedisTemplate = stringRedisTemplate; this.jdbcTemplate = new JdbcTemplate(dataSource); } @Override public void run(ApplicationArguments args) { if (Boolean.TRUE.equals(stringRedisTemplate.hasKey(BizNoUtils.USED_SET_KEY))) { log.info("[run][å·²ç¨ç¼ç éåå åº] éåå·²åå¨ï¼è·³è¿åºå æ«æ"); return; } long start = System.currentTimeMillis(); long total = 0L; try { String schema = jdbcTemplate.queryForObject("SELECT DATABASE()", String.class); List<Map<String, Object>> columns = jdbcTemplate.queryForList( "SELECT table_name, column_name FROM information_schema.columns " + "WHERE table_schema = ? AND data_type IN ('varchar', 'char') " + "AND (column_name = 'no' OR column_name = 'code' OR column_name = 'temp_code' " + " OR column_name LIKE '%\\_no' OR column_name LIKE '%\\_code')", schema); for (Map<String, Object> column : columns) { String table = String.valueOf(column.get("table_name")); String col = String.valueOf(column.get("column_name")); if (table.toLowerCase().startsWith("qrtz_") || table.toLowerCase().startsWith("act_")) { continue; } List<String> codes = jdbcTemplate.queryForList( "SELECT `" + col + "` FROM `" + table + "` WHERE `" + col + "` REGEXP '^[0-9]{" + BizNoUtils.CODE_LENGTH + "}$'", String.class); if (!codes.isEmpty()) { stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, codes.toArray(new String[0])); total += codes.size(); } } // æ 记为已åå§åï¼é¿å 䏿¬¡å¯å¨é夿«æ stringRedisTemplate.opsForSet().add(BizNoUtils.USED_SET_KEY, INIT_MARKER); log.info("[run][å·²ç¨ç¼ç éåå åº] éå缺失ï¼å·²è½½å ¥åºå {} 个ç¼ç ", total); } catch (Exception e) { log.warn("[run][å·²ç¨ç¼ç éåå åº] åå§å失败ï¼ä¸å½±åå¯å¨ï¼ï¼è¯·ææ¥", e); } finally { log.info("[run][å·²ç¨ç¼ç éåå åº] åºå æ«æèæ¶ {} ms", System.currentTimeMillis() - start); } } } yudao-server/src/main/java/cn/iocoder/yudao/server/framework/bizno/BizNoSeqInitializer.java
ÎļþÒÑɾ³ý