完善ruoyi-common-tenant模块
This commit is contained in:
parent
a03742f481
commit
c14f8d098f
@ -0,0 +1,84 @@
|
||||
package com.ruoyi.common.tenant.config;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.mybatisflex.core.tenant.TenantFactory;
|
||||
import com.ruoyi.common.core.utils.reflect.ReflectUtils;
|
||||
import com.ruoyi.common.orm.config.MyBatisFlexConfig;
|
||||
import com.ruoyi.common.redis.config.RedisConfig;
|
||||
import com.ruoyi.common.redis.config.properties.RedissonProperties;
|
||||
import com.ruoyi.common.tenant.core.TenantSaTokenDao;
|
||||
import com.ruoyi.common.tenant.handle.MyTenantFactory;
|
||||
import com.ruoyi.common.tenant.handle.TenantKeyPrefixHandler;
|
||||
import com.ruoyi.common.tenant.manager.TenantSpringCacheManager;
|
||||
import com.ruoyi.common.tenant.properties.TenantProperties;
|
||||
import org.redisson.config.ClusterServersConfig;
|
||||
import org.redisson.config.SingleServerConfig;
|
||||
import org.redisson.spring.starter.RedissonAutoConfigurationCustomizer;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* 租户配置类
|
||||
*
|
||||
* @author Lion Li
|
||||
* @author 数据小王子
|
||||
*/
|
||||
@EnableConfigurationProperties(TenantProperties.class)
|
||||
@AutoConfiguration(after = {RedisConfig.class, MyBatisFlexConfig.class})
|
||||
@ConditionalOnProperty(value = "tenant.enable", havingValue = "true")
|
||||
public class TenantConfig {
|
||||
|
||||
|
||||
/**
|
||||
* 多租户工厂,用于获取当前租户ID
|
||||
*/
|
||||
@Bean
|
||||
public TenantFactory tenantFactory() {
|
||||
return new MyTenantFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedissonAutoConfigurationCustomizer tenantRedissonCustomizer(RedissonProperties redissonProperties) {
|
||||
return config -> {
|
||||
TenantKeyPrefixHandler nameMapper = new TenantKeyPrefixHandler(redissonProperties.getKeyPrefix());
|
||||
SingleServerConfig singleServerConfig = ReflectUtils.invokeGetter(config, "singleServerConfig");
|
||||
if (ObjectUtil.isNotNull(singleServerConfig)) {
|
||||
// 使用单机模式
|
||||
// 设置多租户 redis key前缀
|
||||
singleServerConfig.setNameMapper(nameMapper);
|
||||
ReflectUtils.invokeSetter(config, "singleServerConfig", singleServerConfig);
|
||||
}
|
||||
ClusterServersConfig clusterServersConfig = ReflectUtils.invokeGetter(config, "clusterServersConfig");
|
||||
// 集群配置方式 参考下方注释
|
||||
if (ObjectUtil.isNotNull(clusterServersConfig)) {
|
||||
// 设置多租户 redis key前缀
|
||||
clusterServersConfig.setNameMapper(nameMapper);
|
||||
ReflectUtils.invokeSetter(config, "clusterServersConfig", clusterServersConfig);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 多租户缓存管理器
|
||||
*/
|
||||
@Primary
|
||||
@Bean
|
||||
public CacheManager tenantCacheManager() {
|
||||
return new TenantSpringCacheManager();
|
||||
}
|
||||
|
||||
/**
|
||||
* 多租户鉴权dao实现
|
||||
*/
|
||||
@Primary
|
||||
@Bean
|
||||
public SaTokenDao tenantSaTokenDao() {
|
||||
return new TenantSaTokenDao();
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package com.ruoyi.common.tenant.core;
|
||||
|
||||
import com.ruoyi.common.core.validate.EditGroup;
|
||||
import com.ruoyi.common.orm.core.domain.BaseEntity;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 租户基类
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TenantEntity extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package com.ruoyi.common.tenant.handle;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.mybatisflex.core.tenant.TenantFactory;
|
||||
import com.ruoyi.common.security.utils.LoginHelper;
|
||||
import com.ruoyi.common.tenant.helper.TenantHelper;
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
/**
|
||||
* 自定义租户处理器
|
||||
*
|
||||
* @author 数据小王子
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
public class MyTenantFactory implements TenantFactory {
|
||||
|
||||
@Override
|
||||
public Object[] getTenantIds() {
|
||||
Long tenantId = LoginHelper.getTenantId();
|
||||
if (ObjectUtil.isNull(tenantId)) {
|
||||
return null;
|
||||
}
|
||||
Long dynamicTenantId = TenantHelper.getDynamic();
|
||||
if (ObjectUtil.isNotNull(dynamicTenantId)) {
|
||||
// 返回动态租户
|
||||
return new Object[]{dynamicTenantId};
|
||||
}
|
||||
// 返回固定租户
|
||||
return new Object[]{tenantId};
|
||||
}
|
||||
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
package com.ruoyi.common.tenant.handle;
|
||||
|
||||
import cn.hutool.core.collection.ListUtil;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.security.utils.LoginHelper;
|
||||
import com.ruoyi.common.tenant.helper.TenantHelper;
|
||||
import com.ruoyi.common.tenant.properties.TenantProperties;
|
||||
import lombok.AllArgsConstructor;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.NullValue;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 自定义租户处理器
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
//public class PlusTenantLineHandler implements TenantLineHandler {
|
||||
public class PlusTenantLineHandler {
|
||||
|
||||
private final TenantProperties tenantProperties;
|
||||
|
||||
public Expression getTenantId() {
|
||||
String tenantId = LoginHelper.getTenantId().toString();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
return new NullValue();
|
||||
}
|
||||
String dynamicTenantId = TenantHelper.getDynamic();
|
||||
if (StringUtils.isNotBlank(dynamicTenantId)) {
|
||||
// 返回动态租户
|
||||
return new StringValue(dynamicTenantId);
|
||||
}
|
||||
// 返回固定租户
|
||||
return new StringValue(tenantId);
|
||||
}
|
||||
|
||||
public boolean ignoreTable(String tableName) {
|
||||
String tenantId = LoginHelper.getTenantId().toString();
|
||||
// 判断是否有租户
|
||||
if (StringUtils.isNotBlank(tenantId)) {
|
||||
// 不需要过滤租户的表
|
||||
List<String> excludes = tenantProperties.getExcludes();
|
||||
// 非业务表
|
||||
List<String> tables = ListUtil.toList(
|
||||
"gen_table",
|
||||
"gen_table_column"
|
||||
);
|
||||
tables.addAll(excludes);
|
||||
return tables.contains(tableName);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -1,15 +1,19 @@
|
||||
package com.ruoyi.common.tenant.handle;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.ruoyi.common.core.constant.GlobalConstants;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.redis.handler.KeyPrefixHandler;
|
||||
import com.ruoyi.common.tenant.helper.TenantHelper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 多租户redis缓存key前缀处理
|
||||
*
|
||||
* @author Lion Li
|
||||
* @author 数据小王子
|
||||
*/
|
||||
@Slf4j
|
||||
public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
||||
|
||||
public TenantKeyPrefixHandler(String keyPrefix) {
|
||||
@ -27,8 +31,11 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
||||
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
||||
return super.map(name);
|
||||
}
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.startsWith(name, tenantId)) {
|
||||
Long tenantId = TenantHelper.getTenantId();
|
||||
if (ObjectUtil.isNull(tenantId)) {
|
||||
log.error("无法获取有效的租户id -> Null");
|
||||
}
|
||||
if (StringUtils.startsWith(name, tenantId + "")) {
|
||||
// 如果存在则直接返回
|
||||
return super.map(name);
|
||||
}
|
||||
@ -47,8 +54,8 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler {
|
||||
if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) {
|
||||
return super.unmap(name);
|
||||
}
|
||||
String tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.startsWith(unmap, tenantId)) {
|
||||
Long tenantId = TenantHelper.getTenantId();
|
||||
if (StringUtils.startsWith(unmap, tenantId + "")) {
|
||||
// 如果存在则删除
|
||||
return unmap.substring((tenantId + ":").length());
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package com.ruoyi.common.tenant.helper;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.spring.SpringMVCUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.mybatisflex.core.tenant.TenantManager;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -19,6 +21,7 @@ import java.util.function.Supplier;
|
||||
* 租户助手
|
||||
*
|
||||
* @author Lion Li
|
||||
* @author 数据小王子
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@ -26,7 +29,7 @@ public class TenantHelper {
|
||||
|
||||
private static final String DYNAMIC_TENANT_KEY = GlobalConstants.GLOBAL_REDIS_KEY + "dynamicTenant";
|
||||
|
||||
private static final ThreadLocal<String> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>();
|
||||
private static final ThreadLocal<Long> TEMP_DYNAMIC_TENANT = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 租户功能是否启用
|
||||
@ -39,14 +42,14 @@ public class TenantHelper {
|
||||
* 开启忽略租户(开启后需手动调用 {@link #disableIgnore()} 关闭)
|
||||
*/
|
||||
public static void enableIgnore() {
|
||||
//InterceptorIgnoreHelper.handle(IgnoreStrategy.builder().tenantLine(true).build());
|
||||
TenantManager.ignoreTenantCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭忽略租户
|
||||
*/
|
||||
public static void disableIgnore() {
|
||||
//InterceptorIgnoreHelper.clearIgnoreStrategy();
|
||||
TenantManager.restoreTenantCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +85,7 @@ public class TenantHelper {
|
||||
* <p>
|
||||
* 如果为非web环境 那么只在当前线程内生效
|
||||
*/
|
||||
public static void setDynamic(String tenantId) {
|
||||
public static void setDynamic(Long tenantId) {
|
||||
if (!SpringMVCUtil.isWeb()) {
|
||||
TEMP_DYNAMIC_TENANT.set(tenantId);
|
||||
return;
|
||||
@ -97,13 +100,13 @@ public class TenantHelper {
|
||||
* <p>
|
||||
* 如果为非web环境 那么只在当前线程内生效
|
||||
*/
|
||||
public static String getDynamic() {
|
||||
public static Long getDynamic() {
|
||||
if (!SpringMVCUtil.isWeb()) {
|
||||
return TEMP_DYNAMIC_TENANT.get();
|
||||
}
|
||||
String cacheKey = DYNAMIC_TENANT_KEY + ":" + LoginHelper.getUserId();
|
||||
String tenantId = (String) SaHolder.getStorage().get(cacheKey);
|
||||
if (StringUtils.isNotBlank(tenantId)) {
|
||||
Long tenantId = (Long) SaHolder.getStorage().get(cacheKey);
|
||||
if (ObjectUtil.isNotNull(tenantId)) {
|
||||
return tenantId;
|
||||
}
|
||||
tenantId = RedisUtils.getCacheObject(cacheKey);
|
||||
@ -124,13 +127,44 @@ public class TenantHelper {
|
||||
SaHolder.getStorage().delete(cacheKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 在动态租户中执行
|
||||
*
|
||||
* @param handle 处理执行方法
|
||||
*/
|
||||
public static void dynamic(Long tenantId, Runnable handle) {
|
||||
setDynamic(tenantId);
|
||||
try {
|
||||
handle.run();
|
||||
} finally {
|
||||
clearDynamic();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在动态租户中执行
|
||||
*
|
||||
* @param handle 处理执行方法
|
||||
*/
|
||||
public static <T> T dynamic(Long tenantId, Supplier<T> handle) {
|
||||
setDynamic(tenantId);
|
||||
try {
|
||||
return handle.get();
|
||||
} finally {
|
||||
clearDynamic();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前租户id(动态租户优先)
|
||||
*/
|
||||
public static String getTenantId() {
|
||||
String tenantId = TenantHelper.getDynamic();
|
||||
if (StringUtils.isBlank(tenantId)) {
|
||||
tenantId = LoginHelper.getTenantId().toString();
|
||||
public static Long getTenantId() {
|
||||
if (!isEnable()) {
|
||||
return null;
|
||||
}
|
||||
Long tenantId = TenantHelper.getDynamic();
|
||||
if (ObjectUtil.isNull(tenantId)) {
|
||||
tenantId = LoginHelper.getTenantId();
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
com.ruoyi.common.tenant.config.TenantConfig
|
@ -1,7 +1,5 @@
|
||||
package com.ruoyi.system.mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.ruoyi.system.domain.SysPost;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
Loading…
Reference in New Issue
Block a user