更新sql和代码规范修改
This commit is contained in:
@ -27,14 +27,14 @@ public class TenantProperties {
|
||||
|
||||
/**
|
||||
* 需要忽略多租户的请求
|
||||
*
|
||||
* <p>
|
||||
* 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!
|
||||
*/
|
||||
private Set<String> ignoreUrls = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* 需要忽略多租户的表
|
||||
*
|
||||
* <p>
|
||||
* 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
|
||||
*/
|
||||
private Set<String> ignoreTables = Collections.emptySet();
|
||||
|
@ -36,7 +36,8 @@ import org.springframework.data.redis.core.RedisTemplate;
|
||||
import java.util.Objects;
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(prefix = "yshop.tenant", value = "enable", matchIfMissing = true) // 允许使用 yshop.tenant.enable=false 禁用多租户
|
||||
@ConditionalOnProperty(prefix = "yshop.tenant", value = "enable", matchIfMissing = true)
|
||||
// 允许使用 yshop.tenant.enable=false 禁用多租户
|
||||
@EnableConfigurationProperties(TenantProperties.class)
|
||||
public class YshopTenantAutoConfiguration {
|
||||
|
||||
|
@ -4,7 +4,7 @@ import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 忽略租户,标记指定方法不进行租户的自动过滤
|
||||
*
|
||||
* <p>
|
||||
* 注意,只有 DB 的场景会过滤,其它场景暂时不过滤:
|
||||
* 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的
|
||||
* 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略
|
||||
|
@ -11,7 +11,7 @@ import org.aspectj.lang.annotation.Aspect;
|
||||
* 忽略多租户的 Aspect,基于 {@link TenantIgnore} 注解实现,用于一些全局的逻辑。
|
||||
* 例如说,一个定时任务,读取所有数据,进行处理。
|
||||
* 又例如说,读取所有数据,进行缓存。
|
||||
*
|
||||
* <p>
|
||||
* 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -38,7 +38,7 @@ public class TenantContextHolder {
|
||||
Long tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
|
||||
+ DocumentEnum.TENANT.getUrl());
|
||||
+ DocumentEnum.TENANT.getUrl());
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ public class TenantDatabaseInterceptor implements TenantLineHandler {
|
||||
@Override
|
||||
public boolean ignoreTable(String tableName) {
|
||||
return TenantContextHolder.isIgnore() // 情况一,全局忽略多租户
|
||||
|| CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
|
||||
|| CollUtil.contains(ignoreTables, tableName); // 情况二,忽略多租户的表
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* 多租户 JobHandler 装饰器
|
||||
* 任务执行时,会按照租户逐个执行 Job 的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,需要保证 JobHandler 的幂等性。因为 Job 因为某个租户执行失败重试时,之前执行成功的租户也会再次执行。
|
||||
*
|
||||
* @author yshop
|
||||
|
@ -9,7 +9,7 @@ import static co.yixiang.yshop.framework.web.core.util.WebFrameworkUtils.HEADER_
|
||||
|
||||
/**
|
||||
* 多租户 {@link AbstractRedisMessage} 拦截器
|
||||
*
|
||||
* <p>
|
||||
* 1. Producer 发送消息时,将 {@link TenantContextHolder} 租户编号,添加到消息的 Header 中
|
||||
* 2. Consumer 消费消息时,将消息的 Header 的租户编号,添加到 {@link TenantContextHolder} 中
|
||||
*
|
||||
|
@ -9,7 +9,7 @@ import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
|
||||
/**
|
||||
* 多租户的 {@link RedisCacheManager} 实现类
|
||||
*
|
||||
* <p>
|
||||
* 操作指定 name 的 {@link Cache} 时,自动拼接租户后缀,格式为 name + ":" + tenantId + 后缀
|
||||
*
|
||||
* @author airhead
|
||||
@ -26,7 +26,7 @@ public class TenantRedisCacheManager extends RedisCacheManager {
|
||||
public Cache getCache(String name) {
|
||||
// 如果开启多租户,则 name 拼接租户后缀
|
||||
if (!TenantContextHolder.isIgnore()
|
||||
&& TenantContextHolder.getTenantId() != null) {
|
||||
&& TenantContextHolder.getTenantId() != null) {
|
||||
name = name + ":" + TenantContextHolder.getTenantId();
|
||||
}
|
||||
|
||||
|
@ -8,12 +8,12 @@ import java.time.Duration;
|
||||
|
||||
/**
|
||||
* 多租户拓展的 RedisKeyDefine 实现类
|
||||
*
|
||||
* <p>
|
||||
* 由于 Redis 不同于 MySQL 有 column 字段,无法通过类似 WHERE tenant_id = ? 的方式过滤
|
||||
* 所以需要通过在 Redis Key 上增加后缀的方式,进行租户之间的隔离。具体的步骤是:
|
||||
* 1. 假设 Redis Key 是 user:%d,示例是 user:1;对应到多租户的 Redis Key 是 user:%d:%d,
|
||||
* 2. 在 Redis DAO 中,需要使用 {@link #formatKey(Object...)} 方法,进行 Redis Key 的格式化
|
||||
*
|
||||
* <p>
|
||||
* 注意,大多数情况下,并不用使用 TenantRedisKeyDefine 实现。主要的使用场景,还是 Redis Key 可能存在冲突的情况。
|
||||
* 例如说,租户 1 和 2 都有一个手机号作为 Key,则他们会存在冲突的问题
|
||||
*
|
||||
|
@ -62,7 +62,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
|
||||
if (tenantId == null) {
|
||||
tenantId = user.getTenantId();
|
||||
TenantContextHolder.setTenantId(tenantId);
|
||||
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
||||
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
||||
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
|
||||
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
|
||||
user.getTenantId(), user.getId(), user.getUserType(),
|
||||
|
@ -16,7 +16,7 @@ public class TenantUtils {
|
||||
|
||||
/**
|
||||
* 使用指定租户,执行对应的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
|
||||
* 当然,执行完成后,还是会恢复回去
|
||||
*
|
||||
@ -39,7 +39,7 @@ public class TenantUtils {
|
||||
|
||||
/**
|
||||
* 使用指定租户,执行对应的逻辑
|
||||
*
|
||||
* <p>
|
||||
* 注意,如果当前是忽略租户的情况下,会被强制设置成不忽略租户
|
||||
* 当然,执行完成后,还是会恢复回去
|
||||
*
|
||||
|
@ -7,11 +7,10 @@
|
||||
* 5. Job:在 JobHandler 执行任务时,会按照每个租户,都独立并行执行一次。
|
||||
* 6. MQ:在 Producer 发送消息时,Header 带上 tenant-id 租户编号;在 Consumer 消费消息时,将 Header 的 tenant-id 租户编号,添加到租户上下文。
|
||||
* 7. Async:异步需要保证 ThreadLocal 的传递性,通过使用阿里开源的 TransmittableThreadLocal 实现。相关的改造点,可见:
|
||||
* 1)Spring Async:
|
||||
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
|
||||
* 2)Spring Security:
|
||||
* TransmittableThreadLocalSecurityContextHolderStrategy
|
||||
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
|
||||
*
|
||||
* 1)Spring Async:
|
||||
* {@link co.yixiang.yshop.framework.quartz.config.YshopAsyncAutoConfiguration#threadPoolTaskExecutorBeanPostProcessor()}
|
||||
* 2)Spring Security:
|
||||
* TransmittableThreadLocalSecurityContextHolderStrategy
|
||||
* 和 YshopSecurityAutoConfiguration#securityContextHolderMethodInvokingFactoryBean() 方法
|
||||
*/
|
||||
package co.yixiang.yshop.framework.tenant;
|
||||
|
Reference in New Issue
Block a user