com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
zlt-common-spring-boot-starter
公共通用组件
diff --git a/zlt-commons/zlt-db-spring-boot-starter/pom.xml b/zlt-commons/zlt-db-spring-boot-starter/pom.xml
index 8b49397103b40bf1676b6602cb0a395515511c3e..cc8201b065e26dfd3f0981a0c929abe62c25c69d 100644
--- a/zlt-commons/zlt-db-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-db-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/MybatisPlusAutoConfigure.java b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/MybatisPlusAutoConfigure.java
index 801322890b842f4ec60e4c884f690ae704f30abd..2b1e855e26863526c5affe28212fcd34c9e2148a 100644
--- a/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/MybatisPlusAutoConfigure.java
+++ b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/MybatisPlusAutoConfigure.java
@@ -1,12 +1,12 @@
package com.central.db.config;
-import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
-import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
-import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.central.common.properties.TenantProperties;
+import com.central.db.interceptor.CustomTenantInterceptor;
import com.central.db.properties.MybatisPlusAutoFillProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -26,10 +26,7 @@ import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties(MybatisPlusAutoFillProperties.class)
public class MybatisPlusAutoConfigure {
@Autowired
- private TenantHandler tenantHandler;
-
- @Autowired
- private ISqlParserFilter sqlParserFilter;
+ private TenantLineHandler tenantLineHandler;
@Autowired
private TenantProperties tenantProperties;
@@ -41,17 +38,17 @@ public class MybatisPlusAutoConfigure {
* 分页插件,自动识别数据库类型
*/
@Bean
- public PaginationInterceptor paginationInterceptor() {
- PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
+ public MybatisPlusInterceptor paginationInterceptor() {
+ MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
+ mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
boolean enableTenant = tenantProperties.getEnable();
//是否开启多租户隔离
if (enableTenant) {
- TenantSqlParser tenantSqlParser = new TenantSqlParser()
- .setTenantHandler(tenantHandler);
- paginationInterceptor.setSqlParserList(CollUtil.toList(tenantSqlParser));
- paginationInterceptor.setSqlParserFilter(sqlParserFilter);
+ CustomTenantInterceptor tenantInterceptor = new CustomTenantInterceptor(
+ tenantLineHandler, tenantProperties.getIgnoreSqls());
+ mpInterceptor.addInnerInterceptor(tenantInterceptor);
}
- return paginationInterceptor;
+ return mpInterceptor;
}
@Bean
diff --git a/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/TenantAutoConfigure.java b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/TenantAutoConfigure.java
index 40f38d6efbc6401beae62f65eef9e9b61f327998..8778dd6d76d04b57f18b1f143864ea82e40e8379 100644
--- a/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/TenantAutoConfigure.java
+++ b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/config/TenantAutoConfigure.java
@@ -1,14 +1,11 @@
package com.central.db.config;
-import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
-import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
-import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
+import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.central.common.context.TenantContextHolder;
import com.central.common.properties.TenantProperties;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.StringValue;
-import org.apache.ibatis.mapping.MappedStatement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
@@ -25,13 +22,13 @@ public class TenantAutoConfigure {
private TenantProperties tenantProperties;
@Bean
- public TenantHandler tenantHandler() {
- return new TenantHandler() {
+ public TenantLineHandler tenantLineHandler() {
+ return new TenantLineHandler() {
/**
* 获取租户id
*/
@Override
- public Expression getTenantId(boolean where) {
+ public Expression getTenantId() {
String tenant = TenantContextHolder.getTenant();
if (tenant != null) {
return new StringValue(TenantContextHolder.getTenant());
@@ -39,37 +36,16 @@ public class TenantAutoConfigure {
return new NullValue();
}
- /**
- * 获取租户列名
- */
- @Override
- public String getTenantIdColumn() {
- return "tenant_id";
- }
-
/**
* 过滤不需要根据租户隔离的表
* @param tableName 表名
*/
@Override
- public boolean doTableFilter(String tableName) {
+ public boolean ignoreTable(String tableName) {
return tenantProperties.getIgnoreTables().stream().anyMatch(
(e) -> e.equalsIgnoreCase(tableName)
);
}
};
}
-
- /**
- * 过滤不需要根据租户隔离的MappedStatement
- */
- @Bean
- public ISqlParserFilter sqlParserFilter() {
- return metaObject -> {
- MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
- return tenantProperties.getIgnoreSqls().stream().anyMatch(
- (e) -> e.equalsIgnoreCase(ms.getId())
- );
- };
- }
}
diff --git a/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/interceptor/CustomTenantInterceptor.java b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/interceptor/CustomTenantInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2083e7f231c6777bb95662bd8914972166f0cc9
--- /dev/null
+++ b/zlt-commons/zlt-db-spring-boot-starter/src/main/java/com/central/db/interceptor/CustomTenantInterceptor.java
@@ -0,0 +1,44 @@
+package com.central.db.interceptor;
+
+import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
+import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * MyBatis-plus租户拦截器
+ *
+ * @author zlt
+ * @version 1.0
+ * @date 2022/5/6
+ *
+ * Blog: https://zlt2000.gitee.io
+ * Github: https://github.com/zlt2000
+ */
+public class CustomTenantInterceptor extends TenantLineInnerInterceptor {
+ private List ignoreSqls;
+
+ public CustomTenantInterceptor(TenantLineHandler tenantLineHandler, List ignoreSqls) {
+ super(tenantLineHandler);
+ this.ignoreSqls = ignoreSqls;
+ }
+
+ @Override
+ public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds
+ , ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
+ if (isIgnoreMappedStatement(ms.getId())) {
+ return;
+ }
+ super.beforeQuery(executor, ms, parameter, rowBounds, resultHandler, boundSql);
+ }
+
+ private boolean isIgnoreMappedStatement(String msId) {
+ return ignoreSqls.stream().anyMatch((e) -> e.equalsIgnoreCase(msId));
+ }
+}
diff --git a/zlt-commons/zlt-elasticsearch-spring-boot-starter/pom.xml b/zlt-commons/zlt-elasticsearch-spring-boot-starter/pom.xml
index f938340323988b0730e7ee927f13771f3e0918b2..4d2bce09a8ea9b39b0c7e3bbaf33f0269dad9206 100644
--- a/zlt-commons/zlt-elasticsearch-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-elasticsearch-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/pom.xml b/zlt-commons/zlt-loadbalancer-spring-boot-starter/pom.xml
index 925d7d098574b197ba3d9507476bbcbd3ddaef38..8336ea38d3de7f50c67623401eb609092cdf2028 100644
--- a/zlt-commons/zlt-loadbalancer-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/IRuleChooser.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/IRuleChooser.java
new file mode 100644
index 0000000000000000000000000000000000000000..356d2c7da04a6b682df1ec02a6348abcabea1885
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/IRuleChooser.java
@@ -0,0 +1,14 @@
+package com.central.common.lb.chooser;
+
+import org.springframework.cloud.client.ServiceInstance;
+
+import java.util.List;
+
+/**
+ * service选择器类
+ *
+ * @author jarvis create by 2022/3/13
+ */
+public interface IRuleChooser {
+ ServiceInstance choose(List instances);
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RandomRuleChooser.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RandomRuleChooser.java
new file mode 100644
index 0000000000000000000000000000000000000000..aec8257319a1b1b4fcbe91ce98acf8473032636a
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RandomRuleChooser.java
@@ -0,0 +1,27 @@
+package com.central.common.lb.chooser;
+
+import com.alibaba.nacos.common.utils.CollectionUtils;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.cloud.client.ServiceInstance;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * 随机的选择器
+ *
+ * @author jarvis create by 2022/3/13
+ */
+@Log4j2
+public class RandomRuleChooser implements IRuleChooser {
+ @Override
+ public ServiceInstance choose(List instances) {
+ if(CollectionUtils.isNotEmpty(instances)){
+ int randomValue = ThreadLocalRandom.current().nextInt(instances.size());
+ ServiceInstance serviceInstance = instances.get(randomValue);
+ log.info("选择了ip为{}, 端口为:{}的服务", serviceInstance.getHost(), serviceInstance.getPort());
+ return serviceInstance;
+ }
+ return null;
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RoundRuleChooser.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RoundRuleChooser.java
new file mode 100644
index 0000000000000000000000000000000000000000..2817f0a914a866823520c6768dbfa70419bd20c8
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/chooser/RoundRuleChooser.java
@@ -0,0 +1,33 @@
+package com.central.common.lb.chooser;
+
+import com.alibaba.nacos.common.utils.CollectionUtils;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.cloud.client.ServiceInstance;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 轮询选择器
+ *
+ * @author jarvis create by 2022/3/13
+ */
+@Log4j2
+public class RoundRuleChooser implements IRuleChooser{
+
+ private AtomicInteger position;
+
+ public RoundRuleChooser() {
+ this.position = new AtomicInteger(1000);
+ }
+
+ @Override
+ public ServiceInstance choose(List instances) {
+ if(CollectionUtils.isNotEmpty(instances)){
+ ServiceInstance serviceInstance = instances.get(Math.abs(position.incrementAndGet() % instances.size()));
+ log.info("选择了ip为{}, 端口为:{}的服务", serviceInstance.getHost(), serviceInstance.getPort());
+ return serviceInstance;
+ }
+ return null;
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/FeignHttpInterceptorConfig.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/FeignHttpInterceptorConfig.java
index 7140c7bae63e2b7a7009b1d02547120f607bad2b..4e0e006a247aefd92d429a3c2b0f4f6ebb3e223b 100644
--- a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/FeignHttpInterceptorConfig.java
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/FeignHttpInterceptorConfig.java
@@ -2,7 +2,10 @@ package com.central.common.lb.config;
import com.central.common.constant.CommonConstant;
import com.central.common.constant.SecurityConstants;
+import com.central.common.lb.utils.QueryUtils;
import feign.RequestInterceptor;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@@ -12,6 +15,7 @@ import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
+import java.util.Map;
/**
* feign拦截器,只包含http相关数据
@@ -37,6 +41,7 @@ public class FeignHttpInterceptorConfig {
* 使用feign client访问别的微服务时,将上游传过来的access_token、username、roles等信息放入header传递给下一个服务
*/
@Bean
+ @ConditionalOnClass(HttpServletRequest.class)
public RequestInterceptor httpFeignInterceptor() {
return template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VerionIsolationAutoConfig.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VerionIsolationAutoConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..2ecd516621b9270fc840d67a2787e24ca9534ba8
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VerionIsolationAutoConfig.java
@@ -0,0 +1,17 @@
+package com.central.common.lb.config;
+
+import com.central.common.constant.ConfigConstants;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
+import org.springframework.context.annotation.Import;
+
+/**
+ *
+ *
+ * @author jarvis create by 2022/4/10
+ */
+@LoadBalancerClients(defaultConfiguration = VersionLoadBalancerConfig.class)
+@ConditionalOnProperty(prefix = ConfigConstants.CONFIG_LOADBALANCE_ISOLATION, name = "enabled", havingValue = "true", matchIfMissing = false)
+@Import({VersionRegisterBeanPostProcessor.class})
+public class VerionIsolationAutoConfig {
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionLoadBalancerConfig.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionLoadBalancerConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..e34964e742deceebc176b735c96e020ffbdd356b
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionLoadBalancerConfig.java
@@ -0,0 +1,68 @@
+package com.central.common.lb.config;
+
+import com.central.common.constant.ConfigConstants;
+import com.central.common.lb.chooser.IRuleChooser;
+import com.central.common.lb.chooser.RoundRuleChooser;
+import com.central.common.lb.loadbalancer.VersionLoadBalancer;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.env.Environment;
+import org.springframework.util.ClassUtils;
+
+/**
+ * 版本控制的路由选择类配置
+ *
+ * @author jarvis create by 2022/3/9
+ */
+@Log4j2
+public class VersionLoadBalancerConfig{
+
+ private IRuleChooser defaultRuleChooser = null;
+
+ @Bean
+ @ConditionalOnMissingBean(IRuleChooser.class)
+ @ConditionalOnProperty(prefix = ConfigConstants.CONFIG_LOADBALANCE_ISOLATION, value = "chooser")
+ public IRuleChooser customRuleChooser(Environment environment, ApplicationContext context){
+
+ IRuleChooser chooser = new RoundRuleChooser();
+ if (environment.containsProperty(ConfigConstants.CONFIG_LOADBALANCE_ISOLATION_CHOOSER)) {
+ String chooserRuleClassString = environment.getProperty(ConfigConstants.CONFIG_LOADBALANCE_ISOLATION_CHOOSER);
+ if(StringUtils.isNotBlank(chooserRuleClassString)){
+ try {
+ Class> ruleClass = ClassUtils.forName(chooserRuleClassString, context.getClassLoader());
+ chooser = (IRuleChooser) ruleClass.newInstance();
+ } catch (ClassNotFoundException e) {
+ log.error("没有找到定义的选择器,将使用内置的选择器", e);
+ } catch (InstantiationException e) {
+ log.error("没法创建定义的选择器,将使用内置的选择器", e);
+ } catch (IllegalAccessException e) {
+ log.error("没法创建定义的选择器,将使用内置的选择器", e);
+ }
+ }
+ }
+ return chooser;
+ }
+
+ @Bean
+ @ConditionalOnMissingBean(value = IRuleChooser.class)
+ public IRuleChooser defaultRuleChooser(){
+ return new RoundRuleChooser();
+ }
+
+
+ @Bean
+ @ConditionalOnProperty(prefix = ConfigConstants.CONFIG_LOADBALANCE_ISOLATION, name = "enabled", havingValue = "true", matchIfMissing = false)
+ public ReactorServiceInstanceLoadBalancer versionServiceLoadBalancer(Environment environment
+ , LoadBalancerClientFactory loadBalancerClientFactory, IRuleChooser ruleChooser){
+ String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
+ return new VersionLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class)
+ , name, ruleChooser);
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionRegisterBeanPostProcessor.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionRegisterBeanPostProcessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..7f5a3d1fff3c012dde69568ac6a7fa739a5594e1
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/config/VersionRegisterBeanPostProcessor.java
@@ -0,0 +1,27 @@
+package com.central.common.lb.config;
+
+import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
+import com.alibaba.nacos.common.utils.StringUtils;
+import com.central.common.constant.CommonConstant;
+import com.central.common.constant.ConfigConstants;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+
+/**
+ * 将版本注册到注册中心的组件
+ *
+ * @author jarvis create by 2022/3/20
+ */
+public class VersionRegisterBeanPostProcessor implements BeanPostProcessor {
+ @Value("${"+ ConfigConstants.CONFIG_LOADBALANCE_VERSION+":}")
+ private String version;
+ @Override
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ if(bean instanceof NacosDiscoveryProperties && StringUtils.isNotBlank(version)){
+ NacosDiscoveryProperties nacosDiscoveryProperties = (NacosDiscoveryProperties) bean;
+ nacosDiscoveryProperties.getMetadata().putIfAbsent(CommonConstant.METADATA_VERSION, version);
+ }
+ return bean;
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/loadbalancer/VersionLoadBalancer.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/loadbalancer/VersionLoadBalancer.java
new file mode 100644
index 0000000000000000000000000000000000000000..6b8c4acd9e2ed1105dfaf2151f996aceb681084f
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/loadbalancer/VersionLoadBalancer.java
@@ -0,0 +1,100 @@
+package com.central.common.lb.loadbalancer;
+
+import com.central.common.constant.CommonConstant;
+import com.central.common.lb.chooser.IRuleChooser;
+import com.central.common.lb.utils.QueryUtils;
+import lombok.extern.log4j.Log4j2;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.cloud.client.ServiceInstance;
+import org.springframework.cloud.client.loadbalancer.*;
+import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
+import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
+import reactor.core.publisher.Mono;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 自定义版本路由选择
+ *
+ * @author jarvis create by 2022/3/9
+ */
+@Log4j2
+public class VersionLoadBalancer implements ReactorServiceInstanceLoadBalancer {
+
+ private final static String KEY_DEFAULT = "default";
+
+ private ObjectProvider serviceInstanceListSuppliers;
+
+ private String serviceId;
+
+ private IRuleChooser ruleChooser;
+
+ public VersionLoadBalancer(ObjectProvider serviceInstanceListSuppliers, String serviceId, IRuleChooser ruleChooser) {
+ this.serviceInstanceListSuppliers = serviceInstanceListSuppliers;
+ this.serviceId = serviceId;
+ this.ruleChooser = ruleChooser;
+ }
+
+ @Override
+ public Mono> choose(Request request) {
+ // 从request中获取版本,兼容webflux方式
+ RequestData requestData = ((RequestDataContext) (request.getContext())).getClientRequest();
+ String version = getVersionFromRequestData(requestData);
+ log.debug("选择的版本号为:{}", version);
+ return serviceInstanceListSuppliers.getIfAvailable().get(request).next().map(instanceList->{
+ return getInstanceResponse(instanceList, version);
+ });
+ }
+
+ private String getVersionFromRequestData(RequestData requestData){
+ Map queryMap = QueryUtils.getQueryMap(requestData.getUrl());
+ if(MapUtils.isNotEmpty(queryMap)&& queryMap.containsKey(CommonConstant.Z_L_T_VERSION)&& StringUtils.isNotBlank(queryMap.get(CommonConstant.Z_L_T_VERSION))){
+ return queryMap.get(CommonConstant.Z_L_T_VERSION);
+ }else if(requestData.getHeaders().containsKey(CommonConstant.Z_L_T_VERSION)){
+ return requestData.getHeaders().get(CommonConstant.Z_L_T_VERSION).get(0);
+ }
+ return null;
+ }
+ /**
+ * 1. 先获取到拦截的版本,如果不为空的话就将service列表过滤,寻找metadata中哪个服务是配置的版本,
+ * 如果版本为空则不需要进行过滤直接提交给service选择器进行选择
+ * 2. 如果没有找到版本对应的实例,则找所有版本为空或者版本号为default的实例
+ * 3.将instance列表提交到选择器根据对应的策略返回一个instance
+ * @param instances
+ * @return
+ */
+ private Response getInstanceResponse(Listinstances, String version){
+ List filteredServiceIstanceList = instances;
+ if(StringUtils.isNotBlank(version)){
+ if(CollectionUtils.isNotEmpty(instances)){
+ filteredServiceIstanceList = instances.stream()
+ .filter(item->item.getMetadata().containsKey(CommonConstant.METADATA_VERSION)&&
+ version.equals(item.getMetadata().get(CommonConstant.METADATA_VERSION)))
+ .collect(Collectors.toList());
+ }
+ }
+ // 如果没有找到对应的版本实例时,选择版本号为空的或这版本为default的实例
+ if(CollectionUtils.isEmpty(filteredServiceIstanceList)){
+ filteredServiceIstanceList = instances.stream()
+ .filter(item->!item.getMetadata().containsKey(CommonConstant.METADATA_VERSION)||
+ StringUtils.isBlank(item.getMetadata().get(CommonConstant.METADATA_VERSION))
+ || "default".equals(item.getMetadata().get(CommonConstant.METADATA_VERSION)))
+ .collect(Collectors.toList());
+ }
+ // 经过两轮过滤后如果能找到的话就选择,不然返回空
+ if(CollectionUtils.isNotEmpty(filteredServiceIstanceList)){
+ ServiceInstance serviceInstance = this.ruleChooser.choose(filteredServiceIstanceList);
+ if(!Objects.isNull(serviceInstance)){
+ log.debug("使用serviceId为:{}服务, 选择version为:{}, 地址:{}:{},", serviceId, version
+ , serviceInstance.getHost(), serviceInstance.getPort());
+ return new DefaultResponse(serviceInstance);
+ }
+ }
+ // 返回空的返回体
+ return new EmptyResponse();
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/utils/QueryUtils.java b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/utils/QueryUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..2321d5bfbfd1145f1cf20b3f285f8aa9d7ec07d1
--- /dev/null
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/java/com/central/common/lb/utils/QueryUtils.java
@@ -0,0 +1,42 @@
+package com.central.common.lb.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 解析request的query参数工具
+ *
+ * @author jarvis create by 2022/5/8
+ */
+public class QueryUtils {
+ /**
+ * 通过query字符串得到参数的map
+ * @param queryString ?后的字符
+ * @return
+ */
+ public static Map getQueryMap(String queryString){
+ if(StringUtils.isNotBlank(queryString)){
+ return Arrays.stream(queryString.split("&")).map(item -> item.split("="))
+ .collect(Collectors.toMap(key -> key[0], value -> value.length > 1 && StringUtils.isNotBlank(value[1]) ? value[1] : ""));
+ }
+ return Collections.emptyMap();
+ }
+
+ /**
+ * 通过url获取参数map
+ * @param uri
+ * @return
+ */
+ public static Map getQueryMap(URI uri){
+ if(Objects.nonNull(uri)){
+ return getQueryMap(uri.getQuery());
+ }
+ return Collections.emptyMap();
+ }
+}
diff --git a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/resources/META-INF/spring.factories b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/resources/META-INF/spring.factories
index bd79ca62c65affa32e75f16deeb086e575c1e1b1..6154b24d4a8fdd857d63cbf308dd61b83a692479 100644
--- a/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/resources/META-INF/spring.factories
+++ b/zlt-commons/zlt-loadbalancer-spring-boot-starter/src/main/resources/META-INF/spring.factories
@@ -1,2 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-com.central.common.lb.RestTemplateAutoConfigure
\ No newline at end of file
+com.central.common.lb.RestTemplateAutoConfigure,\
+com.central.common.lb.config.VerionIsolationAutoConfig
\ No newline at end of file
diff --git a/zlt-commons/zlt-log-spring-boot-starter/pom.xml b/zlt-commons/zlt-log-spring-boot-starter/pom.xml
index 69e428dac1750a5b2398f9b97c194eaff691e770..6ba3e818ab888d6909b4269ef1bf4cdbf32ed73b 100644
--- a/zlt-commons/zlt-log-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-log-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-oss-spring-boot-starter/pom.xml b/zlt-commons/zlt-oss-spring-boot-starter/pom.xml
index b68157ec9b21f007552bcc20f73e705df7f0582b..207c770957c9e30ec0515f1a605bb35a4f339a77 100644
--- a/zlt-commons/zlt-oss-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-oss-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-redis-spring-boot-starter/pom.xml b/zlt-commons/zlt-redis-spring-boot-starter/pom.xml
index 212df02e8db2c3af2a7dec3c36ebf4117c98d4e3..29fa499fd41d6c6e574bb6eddd3df2b0914b87d7 100644
--- a/zlt-commons/zlt-redis-spring-boot-starter/pom.xml
+++ b/zlt-commons/zlt-redis-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
com.zlt
zlt-commons
- 5.2.0
+ 5.3.0
4.0.0
jar
diff --git a/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java b/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java
index d6c1162d844c5c0892556ccb81e53edf244a1590..7c80302fcff600a0a3e933338f862e2835bf230d 100644
--- a/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java
+++ b/zlt-commons/zlt-redis-spring-boot-starter/src/main/java/com/central/common/redis/template/RedisRepository.java
@@ -1,473 +1,498 @@
-package com.central.common.redis.template;
-
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.dao.DataAccessException;
-import org.springframework.data.redis.connection.RedisClusterNode;
-import org.springframework.data.redis.connection.RedisConnection;
-import org.springframework.data.redis.connection.RedisConnectionFactory;
-import org.springframework.data.redis.connection.RedisServerCommands;
-import org.springframework.data.redis.core.*;
-import org.springframework.data.redis.serializer.RedisSerializer;
-import org.springframework.data.redis.serializer.SerializationUtils;
-import org.springframework.util.Assert;
-
-import java.util.*;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Redis Repository
- * redis 基本操作 可扩展,基本够用了
- *
- * @author zlt
- *
- * Blog: https://zlt2000.gitee.io
- * Github: https://github.com/zlt2000
- */
-@Slf4j
-public class RedisRepository {
- /**
- * Spring Redis Template
- */
- private RedisTemplate redisTemplate;
-
- public RedisRepository(RedisTemplate redisTemplate) {
- this.redisTemplate = redisTemplate;
- }
-
- /**
- * 获取链接工厂
- */
- public RedisConnectionFactory getConnectionFactory() {
- return this.redisTemplate.getConnectionFactory();
- }
-
- /**
- * 获取 RedisTemplate对象
- */
- public RedisTemplate getRedisTemplate() {
- return redisTemplate;
- }
-
- /**
- * 清空DB
- *
- * @param node redis 节点
- */
- public void flushDB(RedisClusterNode node) {
- this.redisTemplate.opsForCluster().flushDb(node);
- }
-
- /**
- * 添加到带有 过期时间的 缓存
- *
- * @param key redis主键
- * @param value 值
- * @param time 过期时间(单位秒)
- */
- public void setExpire(final byte[] key, final byte[] value, final long time) {
- redisTemplate.execute((RedisCallback) connection -> {
- connection.setEx(key, time, value);
- return 1L;
- });
- }
-
- /**
- * 添加到带有 过期时间的 缓存
- *
- * @param key redis主键
- * @param value 值
- * @param time 过期时间
- * @param timeUnit 过期时间单位
- */
- public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit) {
- redisTemplate.opsForValue().set(key, value, time, timeUnit);
- }
- public void setExpire(final String key, final Object value, final long time) {
- this.setExpire(key, value, time, TimeUnit.SECONDS);
- }
- public void setExpire(final String key, final Object value, final long time, final TimeUnit timeUnit, RedisSerializer