diff --git "a/doc/\351\200\232\347\224\250id\347\224\237\346\210\220\345\231\250\351\242\206\345\237\237/id.drawio" "b/doc/\351\200\232\347\224\250id\347\224\237\346\210\220\345\231\250\351\242\206\345\237\237/id.drawio" new file mode 100644 index 0000000000000000000000000000000000000000..f6b21373094dc3e9642e57ae75f534d74f98f15e --- /dev/null +++ "b/doc/\351\200\232\347\224\250id\347\224\237\346\210\220\345\231\250\351\242\206\345\237\237/id.drawio" @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pom.xml b/pom.xml index f59cd327541f51fafb3859aa700a9eb747bd2ef5..0bbc8250a734cf67258096d216f521c791a4adb9 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,20 @@ com.kongxiang kongxiang-spring 1.0-SNAPSHOT + jar + + org.springframework.boot + spring-boot-starter-parent + 2.3.11.RELEASE + + 1.8 UTF-8 UTF-8 - 2.3.7.RELEASE + 2.3.11.RELEASE 2.2.2.RELEASE Hoxton.SR9 @@ -41,38 +48,7 @@ - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud.version} - pom - import - - - org.springframework.boot - spring-boot-dependencies - ${spring-boot.version} - pom - import - - - com.alibaba.cloud - spring-cloud-alibaba-dependencies - ${spring-cloud-alibaba.version} - pom - import - - - com.alibaba.cloud - spring-cloud-alibaba-dependencies - ${spring-cloud-alibaba.version} - pom - import - - - + @@ -85,21 +61,11 @@ UTF-8 - diff --git a/src/main/java/com/kx/config/IdAutoConfiguration.java b/src/main/java/com/kx/config/IdAutoConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..ae73457f2e2e3cdf83ea7a76bcad1803c750e6a6 --- /dev/null +++ b/src/main/java/com/kx/config/IdAutoConfiguration.java @@ -0,0 +1,11 @@ +package com.kx.config; + + +import org.springframework.context.annotation.ComponentScan; + +/** + * @author kongxiang + */ +@ComponentScan("com.kx.utils.id") +public class IdAutoConfiguration { +} diff --git a/src/main/java/com/kx/utils/id/IdAlgorithmRegister.java b/src/main/java/com/kx/utils/id/IdAlgorithmRegister.java new file mode 100644 index 0000000000000000000000000000000000000000..180b53ecffcc92cf11b33b98e839edb457c9055b --- /dev/null +++ b/src/main/java/com/kx/utils/id/IdAlgorithmRegister.java @@ -0,0 +1,86 @@ +package com.kx.utils.id; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.DependsOn; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * id算法注册器 + * @author kongxiang + */ +@Component +@Slf4j +public class IdAlgorithmRegister { + /** + * 获取所有类型是 IdGenerator + */ + @Autowired + private List idGeneratorList; + + protected Map algorithmMap = new ConcurrentHashMap<>(8); + + @PostConstruct + public void init(){ + if (idGeneratorList!= null ){ + idGeneratorList.forEach(idGenerator -> { + algorithmMap.put(idGenerator.getAlgorithm(),idGenerator); + log.info(">> Load id generator successful -- : algorithm : [ {} ] ", idGenerator.getAlgorithm()); + }); + } + } + + + /** + * 注册生成算法 + * @param algorithm + * @param idGenerator + * @return 注册结果 + */ + protected boolean register(String algorithm, IdGenerator idGenerator){ + boolean registerStatus = false; + if (!StringUtils.isEmpty(algorithm) && idGenerator != null ){ + algorithmMap.put(algorithm,idGenerator); + registerStatus = true; + } + return registerStatus; + } + + /** + * 获取算法生成器类 + * @param algorithm 算法 + * @return 算法生成器 + */ + public IdGenerator getAlgorithm(String algorithm){ + IdGenerator idGenerator = this.algorithmMap.get(algorithm); + if (idGenerator == null ){ + throw new UnsupportedOperationException("id generate is not supported : " + algorithm); + } + return idGenerator; + } + + /** + * 是否存有算法生成器 + * @param algorithm 算法 + * @return + */ + protected boolean containAlgorithm(String algorithm){ + return this.algorithmMap.containsKey(algorithm); + } + + /** + * 列出所有支持的算法 + * @return + */ + protected Set supportAlgorithms(){ + return this.algorithmMap.keySet(); + } + +} diff --git a/src/main/java/com/kx/utils/id/IdGenerator.java b/src/main/java/com/kx/utils/id/IdGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..63b84bdc1d0b682382dd1a2166c4756977db43a5 --- /dev/null +++ b/src/main/java/com/kx/utils/id/IdGenerator.java @@ -0,0 +1,20 @@ +package com.kx.utils.id; + +/** + * Id 生成器 + * + * @author kongxiang + */ +public interface IdGenerator { + /** + * 具体生成id的算法实现 + * @return + */ + String generate(); + + /** + * 获取算法标识 + * @return + */ + String getAlgorithm(); +} diff --git a/src/main/java/com/kx/utils/id/IdService.java b/src/main/java/com/kx/utils/id/IdService.java new file mode 100644 index 0000000000000000000000000000000000000000..bf65c376a7f800c9c525d7408351d7eb5fa87680 --- /dev/null +++ b/src/main/java/com/kx/utils/id/IdService.java @@ -0,0 +1,40 @@ +package com.kx.utils.id; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * id 相关能力 + * @author kongxiang + */ +@Component +public class IdService { + @Autowired + private IdAlgorithmRegister idAlgorithmRegister; + + /** + * 生成指定算法的id + * @param algorithm 算法 + * @return id + */ + public String generate(String algorithm){ + return idAlgorithmRegister.getAlgorithm(algorithm).generate(); + } + /** + * 生成id 默认uuid算法 + * @return id + */ + public String generate(){ + return idAlgorithmRegister.getAlgorithm("uuid").generate(); + } + + /** + * 显示支持的所有算法 + * @return 支持的算法列表 + */ + public Set supports(){ + return idAlgorithmRegister.supportAlgorithms(); + } +} diff --git a/src/main/java/com/kx/utils/id/impl/LocalUuidGenerator.java b/src/main/java/com/kx/utils/id/impl/LocalUuidGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..041bc32496b45bf28aba9b2c7e30dab61e46f36e --- /dev/null +++ b/src/main/java/com/kx/utils/id/impl/LocalUuidGenerator.java @@ -0,0 +1,25 @@ +package com.kx.utils.id.impl; + +import com.kx.utils.id.IdGenerator; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +/** + * 本地机器uuid id 生成器 + * @author kongxiang + */ +@Component +public class LocalUuidGenerator implements IdGenerator { + + + @Override + public String generate() { + return UUID.randomUUID().toString().replace("-",""); + } + + @Override + public String getAlgorithm() { + return "uuid"; + } +} diff --git a/src/main/java/com/kx/utils/idempotent/annotation/Idempotent.java b/src/main/java/com/kx/utils/idempotent/annotation/Idempotent.java new file mode 100644 index 0000000000000000000000000000000000000000..975fc30df747df9c03837b7cc4b086e945cb5275 --- /dev/null +++ b/src/main/java/com/kx/utils/idempotent/annotation/Idempotent.java @@ -0,0 +1,13 @@ +package com.kx.utils.idempotent.annotation; + +/** + * 幂等注解 + * + */ +public @interface Idempotent { + + String value() default ""; + + + +} diff --git a/src/main/java/com/kx/utils/idempotent/impl/AntiDuplicateTokenHandler.java b/src/main/java/com/kx/utils/idempotent/impl/AntiDuplicateTokenHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..2d9aa1dbdb04a0a8af08112a03f6a7b0a0b4b2c1 --- /dev/null +++ b/src/main/java/com/kx/utils/idempotent/impl/AntiDuplicateTokenHandler.java @@ -0,0 +1,28 @@ +package com.kx.utils.idempotent.impl; + + +import org.springframework.stereotype.Component; + +/** + *
接口幂等性方案: 防重token令牌实现幂等性
+ * 
+ * + * 针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,此种操作就可以用 Token 的机制实现防止重复提交。 + * 简单的说就是调用方在调用接口的时候先向后端请求一个全局 ID(Token),请求的时候携带这个全局 ID 一起请求(Token 最好将其放到 Headers 中),后端需要对这个 Token 作为 Key,用户信息作为 Value 到 Redis 中进行键值内容校验,如果 Key 存在且 Value 匹配就执行删除命令,然后正常执行后面的业务逻辑。如果不存在对应的 Key 或 Value 不匹配就返回重复执行的错误信息,这样来保证幂等操作。 + *
+ *
+ * 使用操作:
+ *   插入操作
+ *   更新操作
+ *   删除操作
+ * 
+ * + * @author kongxiang + */ +@Component +public class AntiDuplicateTokenHandler { + + + + +} diff --git a/src/main/java/com/kx/utils/token/Token.java b/src/main/java/com/kx/utils/token/Token.java new file mode 100644 index 0000000000000000000000000000000000000000..35ba5441a755a1020df827e18434ea0b66d3e358 --- /dev/null +++ b/src/main/java/com/kx/utils/token/Token.java @@ -0,0 +1,36 @@ +package com.kx.utils.token; + +import lombok.Data; + +import java.util.Date; + +/** + * Token 令牌 + * 领域对象 + * @author kongxiang + */ +@Data +public class Token { + + /** + * token 值 + */ + private String value; + /** + * token生成时间 + */ + private Date createTime; + /** + * token过期时间 + */ + private Long expireMillSecond; + + /** + * 是否过期 + * @return + */ + public boolean isExpire(){ + return System.currentTimeMillis() - expireMillSecond > createTime.getTime(); + } + +} diff --git a/src/main/java/com/kx/utils/token/TokenGenerator.java b/src/main/java/com/kx/utils/token/TokenGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..f5364d99c358f27e46f602d85c4256bbbb063eac --- /dev/null +++ b/src/main/java/com/kx/utils/token/TokenGenerator.java @@ -0,0 +1,10 @@ +package com.kx.utils.token; + +/** + * @author kongxiang + */ +public interface TokenGenerator { + + + +} diff --git a/src/main/resources/META-INF/spring.factories b/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000000000000000000000000000000000..eb32f931972f795890d317d97ad793c85a5a9834 --- /dev/null +++ b/src/main/resources/META-INF/spring.factories @@ -0,0 +1,4 @@ + +# Auto config +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.kx.config.IdAutoConfiguration \ No newline at end of file diff --git a/src/test/java/com/kx/test/IdTest.java b/src/test/java/com/kx/test/IdTest.java new file mode 100644 index 0000000000000000000000000000000000000000..9aa1daa880cd811c78de659bfcebd1fee10a8570 --- /dev/null +++ b/src/test/java/com/kx/test/IdTest.java @@ -0,0 +1,16 @@ +package com.kx.test; + +import org.junit.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class IdTest { + + + + + @Test + public void IdGen(){ + + } +}