1. 手动合并存在重复被合并的文件,并统一包名
This commit is contained in:
92
zt-framework/zt-spring-boot-starter-biz-tenant/pom.xml
Normal file
92
zt-framework/zt-spring-boot-starter-biz-tenant/pom.xml
Normal file
@@ -0,0 +1,92 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt-framework</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zt-spring-boot-starter-biz-tenant</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>多租户</description>
|
||||
<url>https://github.com/YunaiV/ruoyi-vue-pro</url>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-rpc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-job</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mq</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.kafka</groupId>
|
||||
<artifactId>spring-kafka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.amqp</groupId>
|
||||
<artifactId>spring-rabbit</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.rocketmq</groupId>
|
||||
<artifactId>rocketmq-spring-boot-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.zt.plat.framework.tenant.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 多租户配置
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "zt.tenant")
|
||||
@Data
|
||||
public class TenantProperties {
|
||||
|
||||
/**
|
||||
* 租户是否开启
|
||||
*/
|
||||
private static final Boolean ENABLE_DEFAULT = true;
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
private Boolean enable = ENABLE_DEFAULT;
|
||||
|
||||
/**
|
||||
* 需要忽略多租户的请求
|
||||
*
|
||||
* 默认情况下,每个请求需要带上 tenant-id 的请求头。但是,部分请求是无需带上的,例如说短信回调、支付回调等 Open API!
|
||||
*/
|
||||
private Set<String> ignoreUrls = new HashSet<>();
|
||||
|
||||
/**
|
||||
* 需要忽略跨(切换)租户访问的请求
|
||||
*
|
||||
* 原因是:某些接口,访问的是个人信息,在跨租户是获取不到的!
|
||||
*/
|
||||
private Set<String> ignoreVisitUrls = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* 需要忽略多租户的表
|
||||
*
|
||||
* 即默认所有表都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
|
||||
*/
|
||||
private Set<String> ignoreTables = Collections.emptySet();
|
||||
|
||||
/**
|
||||
* 需要忽略多租户的 Spring Cache 缓存
|
||||
*
|
||||
* 即默认所有缓存都开启多租户的功能,所以记得添加对应的 tenant_id 字段哟
|
||||
*/
|
||||
private Set<String> ignoreCaches = Collections.emptySet();
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
package com.zt.plat.framework.tenant.config;
|
||||
|
||||
import com.zt.plat.framework.common.biz.system.tenant.TenantCommonApi;
|
||||
import com.zt.plat.framework.tenant.core.rpc.TenantRequestInterceptor;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(prefix = "zt.tenant", value = "enable", matchIfMissing = true) // 允许使用 zt.tenant.enable=false 禁用多租户
|
||||
@EnableFeignClients(clients = TenantCommonApi.class) // 主要是引入相关的 API 服务
|
||||
public class ZtTenantRpcAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public TenantRequestInterceptor tenantRequestInterceptor() {
|
||||
return new TenantRequestInterceptor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.framework.tenant.core.aop;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 忽略单位切换,标记指定方法不进行租户切换的覆盖
|
||||
* @author chenbowen
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface CompanyVisitIgnore {
|
||||
|
||||
/**
|
||||
* 是否开启忽略租户,默认为 true 开启
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则满足条件,进行租户的忽略
|
||||
*/
|
||||
String enable() default "true";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zt.plat.framework.tenant.core.aop;
|
||||
|
||||
import com.zt.plat.framework.common.util.spring.SpringExpressionUtils;
|
||||
import com.zt.plat.framework.tenant.core.context.CompanyContextHolder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
/**
|
||||
* 忽略单位切换,标记指定方法不进行租户切换的覆盖,基于 {@link CompanyVisitIgnore} 注解实现,用于一些全局的逻辑。
|
||||
* 例如说,一个定时任务,读取所有数据,进行处理。
|
||||
* 又例如说,读取所有数据,进行缓存。
|
||||
* @author ZT
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class CompanyVisitIgnoreAspect {
|
||||
|
||||
@Around("@annotation(companyVisitIgnore)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, CompanyVisitIgnore companyVisitIgnore) throws Throwable {
|
||||
Boolean oldIgnore = CompanyContextHolder.isIgnore();
|
||||
try {
|
||||
// 计算条件,满足的情况下,才进行忽略
|
||||
Object enable = SpringExpressionUtils.parseExpression(companyVisitIgnore.enable());
|
||||
if (Boolean.TRUE.equals(enable)) {
|
||||
CompanyContextHolder.setIgnore(true);
|
||||
}
|
||||
|
||||
// 执行逻辑
|
||||
return joinPoint.proceed();
|
||||
} finally {
|
||||
CompanyContextHolder.setIgnore(oldIgnore);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.framework.tenant.core.aop;
|
||||
|
||||
import com.zt.plat.framework.tenant.config.TenantProperties;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 忽略租户,标记指定方法不进行租户的自动过滤
|
||||
*
|
||||
* 注意,只有 DB 的场景会过滤,其它场景暂时不过滤:
|
||||
* 1、Redis 场景:因为是基于 Key 实现多租户的能力,所以忽略没有意义,不像 DB 是一个 column 实现的
|
||||
* 2、MQ 场景:有点难以抉择,目前可以通过 Consumer 手动在消费的方法上,添加 @TenantIgnore 进行忽略
|
||||
*
|
||||
* 特殊:
|
||||
* 1、如果添加到 Controller 类上,则该 URL 自动添加到 {@link TenantProperties#getIgnoreUrls()} 中
|
||||
* 2、如果添加到 DO 实体类上,则它对应的表名“相当于”自动添加到 {@link TenantProperties#getIgnoreTables()} 中
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
public @interface TenantIgnore {
|
||||
|
||||
/**
|
||||
* 是否开启忽略租户,默认为 true 开启
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则满足条件,进行租户的忽略
|
||||
*/
|
||||
String enable() default "true";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.zt.plat.framework.tenant.core.aop;
|
||||
|
||||
import com.zt.plat.framework.common.util.spring.SpringExpressionUtils;
|
||||
import com.zt.plat.framework.tenant.core.context.TenantContextHolder;
|
||||
import com.zt.plat.framework.tenant.core.util.TenantUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
||||
/**
|
||||
* 忽略多租户的 Aspect,基于 {@link TenantIgnore} 注解实现,用于一些全局的逻辑。
|
||||
* 例如说,一个定时任务,读取所有数据,进行处理。
|
||||
* 又例如说,读取所有数据,进行缓存。
|
||||
*
|
||||
* 整体逻辑的实现,和 {@link TenantUtils#executeIgnore(Runnable)} 需要保持一致
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@Aspect
|
||||
@Slf4j
|
||||
public class TenantIgnoreAspect {
|
||||
|
||||
@Around("@annotation(tenantIgnore)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, TenantIgnore tenantIgnore) throws Throwable {
|
||||
Boolean oldIgnore = TenantContextHolder.isIgnore();
|
||||
try {
|
||||
// 计算条件,满足的情况下,才进行忽略
|
||||
Object enable = SpringExpressionUtils.parseExpression(tenantIgnore.enable());
|
||||
if (Boolean.TRUE.equals(enable)) {
|
||||
TenantContextHolder.setIgnore(true);
|
||||
}
|
||||
|
||||
// 执行逻辑
|
||||
return joinPoint.proceed();
|
||||
} finally {
|
||||
TenantContextHolder.setIgnore(oldIgnore);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.zt.plat.framework.tenant.core.context;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
|
||||
/**
|
||||
* 公司上下文 Holder
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
public class CompanyContextHolder {
|
||||
|
||||
/**
|
||||
* 当前公司编号
|
||||
*/
|
||||
private static final ThreadLocal<Long> COMPANY_ID = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 是否忽略公司
|
||||
*/
|
||||
private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 获得公司编号
|
||||
*
|
||||
* @return 公司编号
|
||||
*/
|
||||
public static Long getCompanyId() {
|
||||
return COMPANY_ID.get();
|
||||
}
|
||||
|
||||
public static void setCompanyId(Long companyId) {
|
||||
COMPANY_ID.set(companyId);
|
||||
}
|
||||
|
||||
public static void setIgnore(Boolean ignore) {
|
||||
IGNORE.set(ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否忽略公司
|
||||
*
|
||||
* @return 是否忽略
|
||||
*/
|
||||
public static boolean isIgnore() {
|
||||
return Boolean.TRUE.equals(IGNORE.get());
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
COMPANY_ID.remove();
|
||||
IGNORE.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.zt.plat.framework.tenant.core.context;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
import com.zt.plat.framework.common.enums.DocumentEnum;
|
||||
|
||||
/**
|
||||
* 多租户上下文 Holder
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
public class TenantContextHolder {
|
||||
|
||||
/**
|
||||
* 当前租户编号
|
||||
*/
|
||||
private static final ThreadLocal<Long> TENANT_ID = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 是否忽略租户
|
||||
*/
|
||||
private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 获得租户编号
|
||||
*
|
||||
* @return 租户编号
|
||||
*/
|
||||
public static Long getTenantId() {
|
||||
return TENANT_ID.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得租户编号。如果不存在,则抛出 NullPointerException 异常
|
||||
*
|
||||
* @return 租户编号
|
||||
*/
|
||||
public static Long getRequiredTenantId() {
|
||||
Long tenantId = getTenantId();
|
||||
if (tenantId == null) {
|
||||
throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"
|
||||
+ DocumentEnum.TENANT.getUrl());
|
||||
}
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public static void setTenantId(Long tenantId) {
|
||||
TENANT_ID.set(tenantId);
|
||||
}
|
||||
|
||||
public static void setIgnore(Boolean ignore) {
|
||||
IGNORE.set(ignore);
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前是否忽略租户
|
||||
*
|
||||
* @return 是否忽略
|
||||
*/
|
||||
public static boolean isIgnore() {
|
||||
return Boolean.TRUE.equals(IGNORE.get());
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
TENANT_ID.remove();
|
||||
IGNORE.remove();
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user