diff --git a/pom.xml b/pom.xml index 3d6a9d1..3ff5de8 100644 --- a/pom.xml +++ b/pom.xml @@ -24,6 +24,7 @@ 3.3.2 2.0.51 2.5.0 + 0.9.16 @@ -128,6 +129,11 @@ com.fasterxml.jackson.core jackson-databind + + org.perf4j + perf4j + ${perf4j.version} + diff --git a/src/main/java/com/cool/CoolApplication.java b/src/main/java/com/cool/CoolApplication.java index aff43b2..2ce3ff1 100644 --- a/src/main/java/com/cool/CoolApplication.java +++ b/src/main/java/com/cool/CoolApplication.java @@ -21,7 +21,7 @@ import org.springframework.scheduling.annotation.EnableAsync; @EnableAsync // 开启异步处理 @EnableCaching // 开启缓存 @SpringBootApplication -@MapperScan("com.cool.modules.*.mapper") // 扫描指定包中的MyBatis映射器 +@MapperScan("com.cool.**.mapper") // 扫描指定包中的MyBatis映射器 public class CoolApplication { private static volatile ConfigurableApplicationContext context; diff --git a/src/main/java/com/cool/core/init/IDGenInit.java b/src/main/java/com/cool/core/init/IDGenInit.java new file mode 100644 index 0000000..617e059 --- /dev/null +++ b/src/main/java/com/cool/core/init/IDGenInit.java @@ -0,0 +1,24 @@ +package com.cool.core.init; + +import com.cool.core.leaf.IDGenService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +/** + * 唯一ID 组件初始化 + **/ +@Slf4j +@Component +@RequiredArgsConstructor +public class IDGenInit implements ApplicationRunner { + + final private IDGenService idGenService; + + @Override + public void run(ApplicationArguments args) { + idGenService.init(); + } +} diff --git a/src/main/java/com/cool/core/leaf/IDGenService.java b/src/main/java/com/cool/core/leaf/IDGenService.java new file mode 100644 index 0000000..b004ce6 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/IDGenService.java @@ -0,0 +1,6 @@ +package com.cool.core.leaf; + +public interface IDGenService { + long next(String key); + void init(); +} diff --git a/src/main/java/com/cool/core/leaf/common/CheckVO.java b/src/main/java/com/cool/core/leaf/common/CheckVO.java new file mode 100644 index 0000000..0d207a7 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/common/CheckVO.java @@ -0,0 +1,27 @@ +package com.cool.core.leaf.common; + +public class CheckVO { + private long timestamp; + private int workID; + + public CheckVO(long timestamp, int workID) { + this.timestamp = timestamp; + this.workID = workID; + } + + public long getTimestamp() { + return timestamp; + } + + public void setTimestamp(long timestamp) { + this.timestamp = timestamp; + } + + public int getWorkID() { + return workID; + } + + public void setWorkID(int workID) { + this.workID = workID; + } +} diff --git a/src/main/java/com/cool/core/leaf/common/Result.java b/src/main/java/com/cool/core/leaf/common/Result.java new file mode 100644 index 0000000..d85b1c6 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/common/Result.java @@ -0,0 +1,39 @@ +package com.cool.core.leaf.common; + +public class Result { + private long id; + private Status status; + + public Result() { + + } + public Result(long id, Status status) { + this.id = id; + this.status = status; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public Status getStatus() { + return status; + } + + public void setStatus(Status status) { + this.status = status; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("Result{"); + sb.append("id=").append(id); + sb.append(", status=").append(status); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/com/cool/core/leaf/common/Status.java b/src/main/java/com/cool/core/leaf/common/Status.java new file mode 100644 index 0000000..ec615e9 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/common/Status.java @@ -0,0 +1,6 @@ +package com.cool.core.leaf.common; + +public enum Status { + SUCCESS, + EXCEPTION +} diff --git a/src/main/java/com/cool/core/leaf/package-info.java b/src/main/java/com/cool/core/leaf/package-info.java new file mode 100644 index 0000000..8278bae --- /dev/null +++ b/src/main/java/com/cool/core/leaf/package-info.java @@ -0,0 +1,5 @@ +/** + * 全局唯一id生成 + * 来源美团:https://github.com/Meituan-Dianping/Leaf + */ +package com.cool.core.leaf; diff --git a/src/main/java/com/cool/core/leaf/segment/SegmentIDGenImpl.java b/src/main/java/com/cool/core/leaf/segment/SegmentIDGenImpl.java new file mode 100644 index 0000000..483c8db --- /dev/null +++ b/src/main/java/com/cool/core/leaf/segment/SegmentIDGenImpl.java @@ -0,0 +1,309 @@ +package com.cool.core.leaf.segment; + +import static com.cool.core.leaf.segment.entity.table.LeafAllocEntityTableDef.LEAF_ALLOC_ENTITY; + +import com.cool.core.exception.CoolPreconditions; +import com.cool.core.leaf.IDGenService; +import com.cool.core.leaf.common.Result; +import com.cool.core.leaf.common.Status; +import com.cool.core.leaf.segment.entity.LeafAllocEntity; +import com.cool.core.leaf.segment.mapper.LeafAllocMapper; +import com.cool.core.leaf.segment.model.Segment; +import com.cool.core.leaf.segment.model.SegmentBuffer; +import com.mybatisflex.core.query.QueryWrapper; +import com.mybatisflex.core.update.UpdateChain; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicLong; +import lombok.RequiredArgsConstructor; +import org.perf4j.StopWatch; +import org.perf4j.slf4j.Slf4JStopWatch; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class SegmentIDGenImpl implements IDGenService { + + private static final Logger logger = LoggerFactory.getLogger(SegmentIDGenImpl.class); + + @Value("${leaf.segment.enable:false}") + private boolean enable; + + /** + * IDCache未初始化成功时的异常码 + */ + private static final long EXCEPTION_ID_IDCACHE_INIT_FALSE = -1; + /** + * key不存在时的异常码 + */ + private static final long EXCEPTION_ID_KEY_NOT_EXISTS = -2; + /** + * SegmentBuffer中的两个Segment均未从DB中装载时的异常码 + */ + private static final long EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL = -3; + /** + * 最大步长不超过100,0000 + */ + private static final int MAX_STEP = 1000000; + /** + * 一个Segment维持时间为15分钟 + */ + private static final long SEGMENT_DURATION = 15 * 60 * 1000L; + private ExecutorService service = new ThreadPoolExecutor(5, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue(), new UpdateThreadFactory()); + private volatile boolean initOK = false; + private Map cache = new ConcurrentHashMap(); + private final LeafAllocMapper leafAllocMapper; + + public static class UpdateThreadFactory implements ThreadFactory { + + private static int threadInitNumber = 0; + + private static synchronized int nextThreadNum() { + return threadInitNumber++; + } + + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "Thread-Segment-Update-" + nextThreadNum()); + } + } + + @Override + public long next(String key) { + Result result = get(key); + CoolPreconditions.check(result.getId() < 0, "获取失败,code值: {}", result.getId()); + return result.getId(); + } + + @Override + public void init() { + if (enable) { + // 确保加载到kv后才初始化成功 + updateCacheFromDb(); + initOK = true; + updateCacheFromDbAtEveryMinute(); + logger.info("唯一ID组件初始化成功 ..."); + } + } + + private void updateCacheFromDbAtEveryMinute() { + ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(r -> { + Thread t = new Thread(r); + t.setName("check-idCache-thread"); + t.setDaemon(true); + return t; + }); + service.scheduleWithFixedDelay(this::updateCacheFromDb, 60, 60, TimeUnit.SECONDS); + } + + private void updateCacheFromDb() { + logger.info("update cache from db"); + StopWatch sw = new Slf4JStopWatch(); + try { + List dbTags = leafAllocMapper.selectListByQuery(QueryWrapper.create().select( + LeafAllocEntity::getKey)).stream().map(LeafAllocEntity::getKey).toList(); + if (dbTags == null || dbTags.isEmpty()) { + return; + } + List cacheTags = new ArrayList(cache.keySet()); + Set insertTagsSet = new HashSet<>(dbTags); + Set removeTagsSet = new HashSet<>(cacheTags); + //db中新加的tags灌进cache + for(int i = 0; i < cacheTags.size(); i++){ + String tmp = cacheTags.get(i); + if(insertTagsSet.contains(tmp)){ + insertTagsSet.remove(tmp); + } + } + for (String tag : insertTagsSet) { + SegmentBuffer buffer = new SegmentBuffer(); + buffer.setKey(tag); + Segment segment = buffer.getCurrent(); + segment.setValue(new AtomicLong(0)); + segment.setMax(0); + segment.setStep(0); + cache.put(tag, buffer); + logger.info("Add tag {} from db to IdCache, SegmentBuffer {}", tag, buffer); + } + //cache中已失效的tags从cache删除 + for(int i = 0; i < dbTags.size(); i++){ + String tmp = dbTags.get(i); + if(removeTagsSet.contains(tmp)){ + removeTagsSet.remove(tmp); + } + } + for (String tag : removeTagsSet) { + cache.remove(tag); + logger.info("Remove tag {} from IdCache", tag); + } + } catch (Exception e) { + logger.warn("update cache from db exception", e); + } finally { + sw.stop("updateCacheFromDb"); + } + } + + private Result get(final String key) { + if (!initOK) { + return new Result(EXCEPTION_ID_IDCACHE_INIT_FALSE, Status.EXCEPTION); + } + CoolPreconditions.check(!initOK, "IDCache未初始化成功"); + if (cache.containsKey(key)) { + SegmentBuffer buffer = cache.get(key); + if (!buffer.isInitOk()) { + synchronized (buffer) { + if (!buffer.isInitOk()) { + try { + updateSegmentFromDb(key, buffer.getCurrent()); + logger.info("Init buffer. Update leafkey {} {} from db", key, buffer.getCurrent()); + buffer.setInitOk(true); + } catch (Exception e) { + logger.warn("Init buffer {} exception", buffer.getCurrent(), e); + } + } + } + } + return getIdFromSegmentBuffer(cache.get(key)); + } + return new Result(EXCEPTION_ID_KEY_NOT_EXISTS, Status.EXCEPTION); + } + + public void updateSegmentFromDb(String key, Segment segment) { + StopWatch sw = new Slf4JStopWatch(); + SegmentBuffer buffer = segment.getBuffer(); + LeafAllocEntity leafAllocEntity; + if (!buffer.isInitOk()) { + leafAllocEntity = updateMaxIdAndGetLeafAlloc(key); + buffer.setStep(leafAllocEntity.getStep()); + buffer.setMinStep(leafAllocEntity.getStep());//leafAlloc中的step为DB中的step + } else if (buffer.getUpdateTimestamp() == 0) { + leafAllocEntity = updateMaxIdAndGetLeafAlloc(key); + buffer.setUpdateTimestamp(System.currentTimeMillis()); + buffer.setStep(leafAllocEntity.getStep()); + buffer.setMinStep(leafAllocEntity.getStep());//leafAlloc中的step为DB中的step + } else { + long duration = System.currentTimeMillis() - buffer.getUpdateTimestamp(); + int nextStep = buffer.getStep(); + if (duration < SEGMENT_DURATION) { + if (nextStep * 2 > MAX_STEP) { + //do nothing + } else { + nextStep = nextStep * 2; + } + } else if (duration < SEGMENT_DURATION * 2) { + //do nothing with nextStep + } else { + nextStep = nextStep / 2 >= buffer.getMinStep() ? nextStep / 2 : nextStep; + } + logger.info("leafKey[{}], step[{}], duration[{}mins], nextStep[{}]", key, buffer.getStep(), String.format("%.2f",((double)duration / (1000 * 60))), nextStep); + LeafAllocEntity temp = new LeafAllocEntity(); + temp.setKey(key); + temp.setStep(nextStep); + leafAllocEntity = updateMaxIdByCustomStepAndGetLeafAlloc(temp); + buffer.setUpdateTimestamp(System.currentTimeMillis()); + buffer.setStep(nextStep); + buffer.setMinStep(leafAllocEntity.getStep());//leafAlloc的step为DB中的step + } + // must set value before set max + long value = leafAllocEntity.getMaxId() - buffer.getStep(); + segment.getValue().set(value); + segment.setMax(leafAllocEntity.getMaxId()); + segment.setStep(buffer.getStep()); + sw.stop("updateSegmentFromDb", key + " " + segment); + } + + private LeafAllocEntity updateMaxIdByCustomStepAndGetLeafAlloc(LeafAllocEntity temp) { + UpdateChain.of(LeafAllocEntity.class) + .setRaw(LeafAllocEntity::getMaxId, LEAF_ALLOC_ENTITY.MAX_ID.getName() + " + " + temp.getStep()) + .where(LeafAllocEntity::getKey).eq(temp.getKey()) + .update(); + return leafAllocMapper.selectOneByQuery(QueryWrapper.create().select( + LEAF_ALLOC_ENTITY.KEY, LEAF_ALLOC_ENTITY.MAX_ID, LEAF_ALLOC_ENTITY.STEP).eq(LeafAllocEntity::getKey, temp.getKey())); + } + + private LeafAllocEntity updateMaxIdAndGetLeafAlloc(String key) { + UpdateChain.of(LeafAllocEntity.class) + .setRaw(LeafAllocEntity::getMaxId, LEAF_ALLOC_ENTITY.MAX_ID.getName() + " + " + LEAF_ALLOC_ENTITY.STEP.getName()) + .where(LeafAllocEntity::getKey).eq(key) + .update(); + return leafAllocMapper.selectOneByQuery(QueryWrapper.create().select( + LEAF_ALLOC_ENTITY.KEY, LEAF_ALLOC_ENTITY.MAX_ID, LEAF_ALLOC_ENTITY.STEP).eq(LeafAllocEntity::getKey, key)); + } + + public Result getIdFromSegmentBuffer(final SegmentBuffer buffer) { + while (true) { + buffer.rLock().lock(); + try { + final Segment segment = buffer.getCurrent(); + if (!buffer.isNextReady() && (segment.getIdle() < 0.9 * segment.getStep()) && buffer.getThreadRunning().compareAndSet(false, true)) { + service.execute(new Runnable() { + @Override + public void run() { + Segment next = buffer.getSegments()[buffer.nextPos()]; + boolean updateOk = false; + try { + updateSegmentFromDb(buffer.getKey(), next); + updateOk = true; + logger.info("update segment {} from db {}", buffer.getKey(), next); + } catch (Exception e) { + logger.warn(buffer.getKey() + " updateSegmentFromDb exception", e); + } finally { + if (updateOk) { + buffer.wLock().lock(); + buffer.setNextReady(true); + buffer.getThreadRunning().set(false); + buffer.wLock().unlock(); + } else { + buffer.getThreadRunning().set(false); + } + } + } + }); + } + long value = segment.getValue().getAndIncrement(); + if (value < segment.getMax()) { + return new Result(value, Status.SUCCESS); + } + } finally { + buffer.rLock().unlock(); + } + waitAndSleep(buffer); + buffer.wLock().lock(); + try { + final Segment segment = buffer.getCurrent(); + long value = segment.getValue().getAndIncrement(); + if (value < segment.getMax()) { + return new Result(value, Status.SUCCESS); + } + if (buffer.isNextReady()) { + buffer.switchPos(); + buffer.setNextReady(false); + } else { + logger.error("Both two segments in {} are not ready!", buffer); + return new Result(EXCEPTION_ID_TWO_SEGMENTS_ARE_NULL, Status.EXCEPTION); + } + } finally { + buffer.wLock().unlock(); + } + } + } + + private void waitAndSleep(SegmentBuffer buffer) { + int roll = 0; + while (buffer.getThreadRunning().get()) { + roll += 1; + if(roll > 10000) { + try { + TimeUnit.MILLISECONDS.sleep(10); + break; + } catch (InterruptedException e) { + logger.warn("Thread {} Interrupted",Thread.currentThread().getName()); + break; + } + } + } + } +} diff --git a/src/main/java/com/cool/core/leaf/segment/entity/LeafAllocEntity.java b/src/main/java/com/cool/core/leaf/segment/entity/LeafAllocEntity.java new file mode 100644 index 0000000..d9b36bf --- /dev/null +++ b/src/main/java/com/cool/core/leaf/segment/entity/LeafAllocEntity.java @@ -0,0 +1,27 @@ +package com.cool.core.leaf.segment.entity; + +import com.cool.core.base.BaseEntity; +import com.mybatisflex.annotation.Table; +import com.tangzc.mybatisflex.autotable.annotation.ColumnDefine; +import com.tangzc.mybatisflex.autotable.annotation.UniIndex; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Table(value = "leaf_alloc", comment = "唯一id分配") +public class LeafAllocEntity extends BaseEntity { + + @UniIndex + @ColumnDefine(comment = "业务key ,比如orderId", length = 20, notNull = true) + private String key; + + @ColumnDefine(comment = "当前最大id", defaultValue = "1", notNull = true) + private Long maxId; + + @ColumnDefine(comment = "步长", defaultValue = "500", notNull = true) + private Integer step; + + @ColumnDefine(comment = "描述") + private String description; +} diff --git a/src/main/java/com/cool/core/leaf/segment/mapper/LeafAllocMapper.java b/src/main/java/com/cool/core/leaf/segment/mapper/LeafAllocMapper.java new file mode 100644 index 0000000..1f492b6 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/segment/mapper/LeafAllocMapper.java @@ -0,0 +1,7 @@ +package com.cool.core.leaf.segment.mapper; + +import com.cool.core.leaf.segment.entity.LeafAllocEntity; +import com.mybatisflex.core.BaseMapper; + +public interface LeafAllocMapper extends BaseMapper { +} diff --git a/src/main/java/com/cool/core/leaf/segment/model/Segment.java b/src/main/java/com/cool/core/leaf/segment/model/Segment.java new file mode 100644 index 0000000..6908a36 --- /dev/null +++ b/src/main/java/com/cool/core/leaf/segment/model/Segment.java @@ -0,0 +1,59 @@ +package com.cool.core.leaf.segment.model; + +import java.util.concurrent.atomic.AtomicLong; + +public class Segment { + private AtomicLong value = new AtomicLong(0); + private volatile long max; + private volatile int step; + private SegmentBuffer buffer; + + public Segment(SegmentBuffer buffer) { + this.buffer = buffer; + } + + public AtomicLong getValue() { + return value; + } + + public void setValue(AtomicLong value) { + this.value = value; + } + + public long getMax() { + return max; + } + + public void setMax(long max) { + this.max = max; + } + + public int getStep() { + return step; + } + + public void setStep(int step) { + this.step = step; + } + + public SegmentBuffer getBuffer() { + return buffer; + } + + public long getIdle() { + return this.getMax() - getValue().get(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("Segment("); + sb.append("value:"); + sb.append(value); + sb.append(",max:"); + sb.append(max); + sb.append(",step:"); + sb.append(step); + sb.append(")"); + return sb.toString(); + } +} diff --git a/src/main/java/com/cool/core/leaf/segment/model/SegmentBuffer.java b/src/main/java/com/cool/core/leaf/segment/model/SegmentBuffer.java new file mode 100644 index 0000000..44c33da --- /dev/null +++ b/src/main/java/com/cool/core/leaf/segment/model/SegmentBuffer.java @@ -0,0 +1,129 @@ +package com.cool.core.leaf.segment.model; + +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +/** + * 双buffer + */ +public class SegmentBuffer { + private String key; + private Segment[] segments; //双buffer + private volatile int currentPos; //当前的使用的segment的index + private volatile boolean nextReady; //下一个segment是否处于可切换状态 + private volatile boolean initOk; //是否初始化完成 + private final AtomicBoolean threadRunning; //线程是否在运行中 + private final ReadWriteLock lock; + + private volatile int step; + private volatile int minStep; + private volatile long updateTimestamp; + + public SegmentBuffer() { + segments = new Segment[]{new Segment(this), new Segment(this)}; + currentPos = 0; + nextReady = false; + initOk = false; + threadRunning = new AtomicBoolean(false); + lock = new ReentrantReadWriteLock(); + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Segment[] getSegments() { + return segments; + } + + public Segment getCurrent() { + return segments[currentPos]; + } + + public int getCurrentPos() { + return currentPos; + } + + public int nextPos() { + return (currentPos + 1) % 2; + } + + public void switchPos() { + currentPos = nextPos(); + } + + public boolean isInitOk() { + return initOk; + } + + public void setInitOk(boolean initOk) { + this.initOk = initOk; + } + + public boolean isNextReady() { + return nextReady; + } + + public void setNextReady(boolean nextReady) { + this.nextReady = nextReady; + } + + public AtomicBoolean getThreadRunning() { + return threadRunning; + } + + public Lock rLock() { + return lock.readLock(); + } + + public Lock wLock() { + return lock.writeLock(); + } + + public int getStep() { + return step; + } + + public void setStep(int step) { + this.step = step; + } + + public int getMinStep() { + return minStep; + } + + public void setMinStep(int minStep) { + this.minStep = minStep; + } + + public long getUpdateTimestamp() { + return updateTimestamp; + } + + public void setUpdateTimestamp(long updateTimestamp) { + this.updateTimestamp = updateTimestamp; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("SegmentBuffer{"); + sb.append("key='").append(key).append('\''); + sb.append(", segments=").append(Arrays.toString(segments)); + sb.append(", currentPos=").append(currentPos); + sb.append(", nextReady=").append(nextReady); + sb.append(", initOk=").append(initOk); + sb.append(", threadRunning=").append(threadRunning); + sb.append(", step=").append(step); + sb.append(", minStep=").append(minStep); + sb.append(", updateTimestamp=").append(updateTimestamp); + sb.append('}'); + return sb.toString(); + } +} diff --git a/src/main/java/com/cool/core/util/MappingAlgorithm.java b/src/main/java/com/cool/core/util/MappingAlgorithm.java new file mode 100644 index 0000000..783aa77 --- /dev/null +++ b/src/main/java/com/cool/core/util/MappingAlgorithm.java @@ -0,0 +1,21 @@ +package com.cool.core.util; + +/** + * 自定义映射算法 + * 将 ID 转换为一个混淆形式的数字,然后能够逆向转换回原始 ID。 + * 场景:混淆订单id + */ +public class MappingAlgorithm { + + private static final long ENCRYPTION_KEY = 123456789L; // 任意密钥 + + // 将 ID 转换为混淆的数字 + public static long encrypt(long id) { + return id ^ ENCRYPTION_KEY; // 使用异或操作进行混淆 + } + + // 将混淆的数字恢复为原始的 ID + public static long decrypt(long encryptedId) { + return encryptedId ^ ENCRYPTION_KEY; // 逆操作恢复原始 ID + } +} diff --git a/src/main/java/com/cool/modules/base/controller/admin/AdminBaseCommController.java b/src/main/java/com/cool/modules/base/controller/admin/AdminBaseCommController.java index 8e1fc59..8bf7920 100644 --- a/src/main/java/com/cool/modules/base/controller/admin/AdminBaseCommController.java +++ b/src/main/java/com/cool/modules/base/controller/admin/AdminBaseCommController.java @@ -5,6 +5,7 @@ import com.cool.core.annotation.CoolRestController; import com.cool.core.annotation.TokenIgnore; import com.cool.core.eps.CoolEps; import com.cool.core.file.FileUploadStrategyFactory; +import com.cool.core.leaf.IDGenService; import com.cool.core.request.R; import com.cool.modules.base.entity.sys.BaseSysUserEntity; import com.cool.modules.base.service.sys.BaseSysLoginService; @@ -41,10 +42,15 @@ public class AdminBaseCommController { final private FileUploadStrategyFactory fileUploadStrategyFactory; + final private IDGenService idGenService; + @TokenIgnore @Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务") @GetMapping("/eps") public R eps() { + long orderId = idGenService.next("orderId"); + + System.out.println(orderId); return R.ok(coolEps.getAdmin()); } diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 3fd6e43..7a4a8df 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -18,7 +18,7 @@ auto-table: # 建表的时候,父类的字段排序是在子类后面还是前面 superInsertPosition: before # 模型包路径 - model-package: com.cool.modules.*.entity.* + model-package: com.cool.**.entity.* # Cool相关配置 cool: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 86f4429..8a19cad 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -91,6 +91,7 @@ ignored: # 忽略记录请求日志url logUrls: - / + - /**/eps - /app/** - /css/* - /js/* @@ -111,7 +112,7 @@ mybatis-flex: # configuration: #MyBatis Mapper 所对应的 XML 文件位置,如果在 Mapper 中有自定义的方法(XML 中有自定义的实现),需要进行该配置,指定 Mapper 所对应的 XML 文件位置 mapper-locations: [ "classpath*:/mapper/**/*.xml" ] - type-aliases-package: com.cool.modules.*.entity.* + type-aliases-package: com.cool.**.entity.* global-config: print-banner: false @@ -150,3 +151,7 @@ cool: # AutoTable配置,根据实体类自动生成表 auto-table: show-banner: false + +leaf: + segment: + enable: true \ No newline at end of file