mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 04:59:21 +08:00
feat(extension/tenant): 新增 continew-starter-extension-tenant 多租户模块(暂时仅支持行级隔离)
This commit is contained in:
@@ -119,6 +119,11 @@ public class PropertiesConstants {
|
||||
*/
|
||||
public static final String MESSAGING_WEBSOCKET = MESSAGING + StringConstants.DOT + "websocket";
|
||||
|
||||
/**
|
||||
* 多租户配置
|
||||
*/
|
||||
public static final String TENANT = CONTINEW_STARTER + StringConstants.DOT + "tenant";
|
||||
|
||||
private PropertiesConstants() {
|
||||
}
|
||||
}
|
||||
|
@@ -346,14 +346,12 @@
|
||||
<artifactId>continew-starter-extension-crud-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 扩展模块 - CRUD - MyBatis Plus ORM 模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-crud-mp</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 扩展模块 - CRUD - MyBatis Flex ORM 模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
@@ -361,6 +359,19 @@
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 扩展模块 - 多租户 - 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-tenant-core</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<!-- 扩展模块 - 多租户 - MyBatis Plus ORM 模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-tenant-mp</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 认证模块 - JustAuth -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
|
@@ -0,0 +1,22 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-tenant</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-extension-tenant-core</artifactId>
|
||||
<description>ContiNew Starter 扩展模块 - 多租户 - 核心模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- TTL(线程间传递 ThreadLocal,异步执行时上下文传递的解决方案) -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>transmittable-thread-local</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.tenant.autoconfigure;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.extension.tenant.enums.TenantIsolationLevel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 租户配置属性
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
@ConfigurationProperties(PropertiesConstants.TENANT)
|
||||
public class TenantProperties {
|
||||
|
||||
/**
|
||||
* 是否启用多租户
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 租户隔离级别
|
||||
*/
|
||||
private TenantIsolationLevel isolationLevel = TenantIsolationLevel.LINE;
|
||||
|
||||
/**
|
||||
* 租户 ID 列名
|
||||
*/
|
||||
private String tenantIdColumn = "tenant_id";
|
||||
|
||||
/**
|
||||
* 超级租户 ID
|
||||
*/
|
||||
private Long superTenantId = 1L;
|
||||
|
||||
/**
|
||||
* 忽略表(忽略拼接多租户条件)
|
||||
*/
|
||||
private List<String> ignoreTables;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public TenantIsolationLevel getIsolationLevel() {
|
||||
return isolationLevel;
|
||||
}
|
||||
|
||||
public void setIsolationLevel(TenantIsolationLevel isolationLevel) {
|
||||
this.isolationLevel = isolationLevel;
|
||||
}
|
||||
|
||||
public String getTenantIdColumn() {
|
||||
return tenantIdColumn;
|
||||
}
|
||||
|
||||
public void setTenantIdColumn(String tenantIdColumn) {
|
||||
this.tenantIdColumn = tenantIdColumn;
|
||||
}
|
||||
|
||||
public Long getSuperTenantId() {
|
||||
return superTenantId;
|
||||
}
|
||||
|
||||
public void setSuperTenantId(Long superTenantId) {
|
||||
this.superTenantId = superTenantId;
|
||||
}
|
||||
|
||||
public List<String> getIgnoreTables() {
|
||||
return ignoreTables;
|
||||
}
|
||||
|
||||
public void setIgnoreTables(List<String> ignoreTables) {
|
||||
this.ignoreTables = ignoreTables;
|
||||
}
|
||||
}
|
@@ -0,0 +1,23 @@
|
||||
package top.continew.starter.extension.tenant.context;
|
||||
|
||||
/**
|
||||
* 租户上下文
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class TenantContext {
|
||||
|
||||
/**
|
||||
* 租户 ID
|
||||
*/
|
||||
private Long tenantId;
|
||||
|
||||
public Long getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(Long tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package top.continew.starter.extension.tenant.context;
|
||||
|
||||
import com.alibaba.ttl.TransmittableThreadLocal;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 租户上下文 Holder
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class TenantContextHolder {
|
||||
|
||||
private static final TransmittableThreadLocal<TenantContext> CONTEXT_HOLDER = new TransmittableThreadLocal<>();
|
||||
|
||||
private TenantContextHolder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上下文
|
||||
*
|
||||
* @param context 上下文
|
||||
*/
|
||||
public static void setContext(TenantContext context) {
|
||||
CONTEXT_HOLDER.set(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上下文
|
||||
*
|
||||
* @return 上下文
|
||||
*/
|
||||
public static TenantContext getContext() {
|
||||
return CONTEXT_HOLDER.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除上下文
|
||||
*/
|
||||
public static void clearContext() {
|
||||
CONTEXT_HOLDER.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取租户 ID
|
||||
*
|
||||
* @return 租户 ID
|
||||
*/
|
||||
public static Long getTenantId() {
|
||||
return Optional.ofNullable(getContext()).map(TenantContext::getTenantId).orElse(null);
|
||||
}
|
||||
}
|
@@ -0,0 +1,20 @@
|
||||
package top.continew.starter.extension.tenant.enums;
|
||||
|
||||
/**
|
||||
* 租户隔离级别
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public enum TenantIsolationLevel {
|
||||
|
||||
/**
|
||||
* 行级
|
||||
*/
|
||||
LINE,
|
||||
|
||||
/**
|
||||
* 数据源级
|
||||
*/
|
||||
DATASOURCE
|
||||
}
|
@@ -0,0 +1,35 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-tenant</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-extension-tenant-mp</artifactId>
|
||||
<description>ContiNew Starter 扩展模块 - 多租户 - MyBatis Plus ORM 模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension-tenant-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- MyBatis Plus(MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率) -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Dynamic Datasource(基于 Spring Boot 的快速集成多数据源的启动器) -->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.extension.tenant.autoconfigure;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
||||
import top.continew.starter.extension.tenant.handler.TenantLineHandlerImpl;
|
||||
|
||||
/**
|
||||
* 多租户自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(TenantProperties.class)
|
||||
@ConditionalOnProperty(prefix = PropertiesConstants.TENANT, name = PropertiesConstants.ENABLED, havingValue = "true", matchIfMissing = true)
|
||||
public class TenantAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TenantAutoConfiguration.class);
|
||||
|
||||
private TenantAutoConfiguration() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 租户隔离级别:行级
|
||||
*/
|
||||
@AutoConfiguration
|
||||
@ConditionalOnProperty(name = PropertiesConstants.TENANT + ".isolation-level", havingValue = "line", matchIfMissing = true)
|
||||
public static class Line {
|
||||
static {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Tenant-Line' completed initialization.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 租户行级隔离拦截器
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantLineHandler) {
|
||||
return new TenantLineInnerInterceptor(tenantLineHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* 租户行级隔离处理器
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public TenantLineHandler tenantLineHandler(TenantProperties properties) {
|
||||
return new TenantLineHandlerImpl(properties);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,46 @@
|
||||
package top.continew.starter.extension.tenant.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.LongValue;
|
||||
import top.continew.starter.extension.tenant.autoconfigure.TenantProperties;
|
||||
import top.continew.starter.extension.tenant.context.TenantContextHolder;
|
||||
|
||||
/**
|
||||
* 租户行级隔离处理器
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.7.0
|
||||
*/
|
||||
public class TenantLineHandlerImpl implements TenantLineHandler {
|
||||
|
||||
private final TenantProperties tenantProperties;
|
||||
|
||||
public TenantLineHandlerImpl(TenantProperties tenantProperties) {
|
||||
this.tenantProperties = tenantProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getTenantId() {
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
if (null != tenantId) {
|
||||
return new LongValue(tenantId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTenantIdColumn() {
|
||||
return tenantProperties.getTenantIdColumn();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ignoreTable(String tableName) {
|
||||
Long tenantId = TenantContextHolder.getTenantId();
|
||||
if (null != tenantId && tenantId.equals(tenantProperties.getSuperTenantId())) {
|
||||
return true;
|
||||
}
|
||||
return CollUtil.contains(tenantProperties.getIgnoreTables(), tableName);
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
top.continew.starter.extension.tenant.autoconfigure.TenantAutoConfiguration
|
@@ -0,0 +1,20 @@
|
||||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-extension</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-extension-tenant</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<description>ContiNew Starter 扩展模块 - 多租户</description>
|
||||
|
||||
<modules>
|
||||
<module>continew-starter-extension-tenant-core</module>
|
||||
<module>continew-starter-extension-tenant-mp</module>
|
||||
</modules>
|
||||
</project>
|
Reference in New Issue
Block a user