package cn.iocoder.yudao.framework.tenant.core.db; import cn.iocoder.yudao.framework.tenant.config.TenantProperties; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import com.baomidou.mybatisplus.core.metadata.TableInfo; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler; import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; import java.util.HashMap; import java.util.Map; /** * 基于 MyBatis Plus 多租户的功能,实现 DB 层面的多租户的功能 * * @author 芋道源码 */ public class TenantDatabaseInterceptor implements TenantLineHandler { /** * 忽略的表 * * KEY:表名 * VALUE:是否忽略 */ private final Map ignoreTables = new HashMap<>(); public TenantDatabaseInterceptor(TenantProperties properties) { // 不同 DB 下,大小写的习惯不同,所以需要都添加进去 properties.getIgnoreTables().forEach(table -> { addIgnoreTable(table, true); }); // 在 OracleKeyGenerator 中,生成主键时,会查询这个表,查询这个表后,会自动拼接 TENANT_ID 导致报错 addIgnoreTable("DUAL", true); } @Override public Expression getTenantId() { return new LongValue(TenantContextHolder.getRequiredTenantId()); } @Override public boolean ignoreTable(String tableName) { // 情况一,全局忽略多租户 if (TenantContextHolder.isIgnore()) { return true; } // 情况二,忽略多租户的表 tableName = SqlParserUtils.removeWrapperSymbol(tableName); Boolean ignore = ignoreTables.get(tableName.toLowerCase()); if (ignore == null) { ignore = computeIgnoreTable(tableName); synchronized (ignoreTables) { addIgnoreTable(tableName, ignore); } } return ignore; } private void addIgnoreTable(String tableName, boolean ignore) { ignoreTables.put(tableName.toLowerCase(), ignore); ignoreTables.put(tableName.toUpperCase(), ignore); } private boolean computeIgnoreTable(String tableName) { // 找不到的表,说明不是 yudao 项目里的,不进行拦截(忽略租户) TableInfo tableInfo = TableInfoHelper.getTableInfo(tableName); if (tableInfo == null) { return true; } // 如果继承了 TenantBaseDO 基类,显然不忽略租户 if (TenantBaseDO.class.isAssignableFrom(tableInfo.getEntityType())) { return false; } // 如果添加了 @TenantIgnore 注解,则忽略租户 TenantIgnore tenantIgnore = tableInfo.getEntityType().getAnnotation(TenantIgnore.class); return tenantIgnore != null; } }