多租户实现 基于SpringBoot+MybtaisPlus ~ 表级别隔离实现

目标:实现同一个mysql实例下不同库相同表结构的表数据隔离处理

此处实现场景:请求中多租户Id 【tenant-id】值即为库名值,也为表中 tenant_id 多租户列值 

基于

 多租户实现 基于SpringBoot+MybtaisPlus ~ 行级别隔离实现_0110编程之路的博客-CSDN博客

扩展实现

1、Starter 封装 ~调整

①、propertis 增加 isolationRow isolationTable 表级别、行级别控制字段

package com.ap.properties;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.List;

/**
 * 类名:MultiTenantProperties.java
 * 描述:多租户配置属性类
 *
 * @author AP
 * @version 1.0
 * @date 2023/7/12 10:02
 */
@ConfigurationProperties(prefix = MultiTenantProperties.PREFIX)
public class MultiTenantProperties {


    public static final String PREFIX = "multi-tenant";

    /**
     * 是否启用
     */
    private boolean enabled;

    /**
     * 租户id列名称
     */
    private String tenantIdColumn;

    /**
     * 忽略多租户限制条件的库表名
     */
    private List<String> ignoreTables;

    /**
     * request請求header 中的多租户标识
     */
    private String headerTenantId;
    /**
     * 基于字段tenantIdColumn的行级别隔离
     */

    private boolean isolationRow;
    /**
     * 基于Schema.表名的表级别隔离
     */
    private boolean isolationTable;

    public boolean getIsolationRow() {
        return isolationRow;
    }

    public void setIsolationRow(boolean isolationRow) {
        this.isolationRow = isolationRow;
    }

    public boolean getIsolationTable() {
        return isolationTable;
    }

    public void setIsolationTable(boolean isolationTable) {
        this.isolationTable = isolationTable;
    }

    public String getHeaderTenantId() {
        return headerTenantId;
    }

    public void setHeaderTenantId(String headerTenantId) {
        this.headerTenantId = headerTenantId;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getTenantIdColumn() {
        return tenantIdColumn;
    }

    public void setTenantIdColumn(String tenantIdColumn) {
        this.tenantIdColumn = tenantIdColumn;
    }

    public List<String> getIgnoreTables() {
        return ignoreTables;
    }

    public void setIgnoreTables(List<String> ignoreTables) {
        this.ignoreTables = ignoreTables;
    }
}

②、AutoConfiguration配置调整

package com.ap.config;

/**
 * 类名:MultiTenantAutoConfiguration.java
 * 描述: 多租户自动配置处理类
 *
 * @author AP
 * @version 1.0
 * @date 2023/7/12 10:12
 */


import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
import com.troila.context.TenantContext;
import com.troila.properties.MultiTenantProperties;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

@Configuration
@EnableConfigurationProperties(MultiTenantProperties.class)
@ConditionalOnProperty(prefix = MultiTenantProperties.PREFIX, value = "enabled", havingValue = "true")
public class MultiTenantAutoConfiguration {

    @Resource
    MybatisPlusInterceptor mybatisPlusInterceptor;

    @Resource(type=MultiTenantProperties.class)
    MultiTenantProperties properties;

    @PostConstruct
    public void tenantLineInnerInterceptor(){
        // 多租户~字段拦截器
        if (properties.getIsolationRow()) {
            mybatisPlusInterceptor.addInnerInterceptor(
                    new TenantLineInnerInterceptor(
                            new TenantLineHandler() {
                                @Override
                                public Expression getTenantId() {
                                    return new StringValue(TenantContext.getRequiredTenantId());
                                }
                                // 租户id 列名值
                                @Override
                                public String getTenantIdColumn(){
                                    return properties.getTenantIdColumn();
                                }

                                // 返回 false 表示所有表都需要拼多租户条件
                                @Override
                                public boolean ignoreTable(String tableName) {
                                    List<String> ignoreTables = properties.getIgnoreTables();
                                    return !CollectionUtils.isEmpty(ignoreTables) && ignoreTables.contains(tableName);
                                }
                            }
                    )
            );
        }
        // 多租户~动态名拦截器
        if (properties.getIsolationTable()) {
            DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
            dynamicTableNameInnerInterceptor.setTableNameHandler((sql, tableName) -> {
                // 获取参数方法
                String tenantId = TenantContext.getRequiredTenantId();
                List<String> ignoreTables = properties.getIgnoreTables();
                // 忽略表处理
                if(!CollectionUtils.isEmpty(ignoreTables) && ignoreTables.contains(tableName)){
                    return tableName;
                }
                return tenantId.concat(".").concat(tableName);

            });
            mybatisPlusInterceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        }
    }
}

2、Starter使用 ~调整

①、yml 配置

# 多租户
multi-tenant:
  # 是否开启多租户处理 true 开启 false 关闭
  enabled: true
  # 表对应的租户字段名称
  tenant-id-column: "tenant_id"
  # 请求头中租户key值
  header-tenant-id: "tenant-id"
  # Schema table隔离 true 开启 false 关闭
  isolation-table: true
  # Row 隔离 true 开启 false 关闭
  isolation-row: true
  # 忽略处理表
  ignore-tables:
    - message
    - user

②、忽略插件处理

支持注解在 Mapper 上以及 Mapper.Method 上 同时存在则 Mapper.method 比 Mapper 优先级高
支持: true 和 false , 1 和 0 , on 和 off
各属性返回 true 表示不走插件(在配置了插件的情况下,不填则默认表示 false)

@InterceptorIgnore(tenantLine = "1", dynamicTableName = "1")

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值