fix bugs
This commit is contained in:
47
blade-starter-tenant/pom.xml
Normal file
47
blade-starter-tenant/pom.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?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>
|
||||
<artifactId>BladeX-Tool</artifactId>
|
||||
<groupId>org.springblade</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>blade-starter-tenant</artifactId>
|
||||
<name>${project.artifactId}</name>
|
||||
<version>${project.parent.version}</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!--Blade-->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-starter-cache</artifactId>
|
||||
</dependency>
|
||||
<!-- Druid -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-3-starter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--Dynamic-->
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Auto -->
|
||||
<dependency>
|
||||
<groupId>org.springblade</groupId>
|
||||
<artifactId>blade-core-auto</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfo;
|
||||
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tenant.annotation.TableExclude;
|
||||
import org.springblade.core.tool.constant.BladeConstant;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.core.tool.utils.SpringUtil;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 租户信息处理器
|
||||
*
|
||||
* @author Chill, L.cm
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class BladeTenantHandler implements TenantLineHandler, SmartInitializingSingleton {
|
||||
/**
|
||||
* 匹配的多租户表
|
||||
*/
|
||||
private final List<String> tenantTableList = new ArrayList<>();
|
||||
/**
|
||||
* 需要排除进行自定义的多租户表
|
||||
*/
|
||||
private final List<String> excludeTableList = Arrays.asList("blade_user", "blade_dept", "blade_role", "blade_tenant", "act_de_model");
|
||||
/**
|
||||
* 多租户配置
|
||||
*/
|
||||
private final BladeTenantProperties tenantProperties;
|
||||
|
||||
/**
|
||||
* 获取租户ID
|
||||
*
|
||||
* @return 租户ID
|
||||
*/
|
||||
@Override
|
||||
public Expression getTenantId() {
|
||||
return new StringValue(Func.toStr(AuthUtil.getTenantId(), BladeConstant.ADMIN_TENANT_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取租户字段名称
|
||||
*
|
||||
* @return 租户字段名称
|
||||
*/
|
||||
@Override
|
||||
public String getTenantIdColumn() {
|
||||
return tenantProperties.getColumn();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表名判断是否忽略拼接多租户条件
|
||||
* 默认都要进行解析并拼接多租户条件
|
||||
*
|
||||
* @param tableName 表名
|
||||
* @return 是否忽略, true:表示忽略,false:需要解析并拼接多租户条件
|
||||
*/
|
||||
@Override
|
||||
public boolean ignoreTable(String tableName) {
|
||||
if (BladeTenantHolder.isIgnore()) {
|
||||
return true;
|
||||
}
|
||||
return !(tenantTableList.contains(tableName) && StringUtil.isNotBlank(AuthUtil.getTenantId()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSingletonsInstantiated() {
|
||||
ApplicationContext context = SpringUtil.getContext();
|
||||
if (tenantProperties.getAnnotationExclude() && context != null) {
|
||||
Map<String, Object> tables = context.getBeansWithAnnotation(TableExclude.class);
|
||||
List<String> excludeTables = tenantProperties.getExcludeTables();
|
||||
for (Object o : tables.values()) {
|
||||
TableExclude annotation = o.getClass().getAnnotation(TableExclude.class);
|
||||
String value = annotation.value();
|
||||
excludeTables.add(value);
|
||||
}
|
||||
}
|
||||
List<TableInfo> tableInfos = TableInfoHelper.getTableInfos();
|
||||
tableFor:
|
||||
for (TableInfo tableInfo : tableInfos) {
|
||||
String tableName = tableInfo.getTableName();
|
||||
if (tenantProperties.getExcludeTables().contains(tableName) ||
|
||||
excludeTableList.contains(tableName.toLowerCase()) ||
|
||||
excludeTableList.contains(tableName.toUpperCase())) {
|
||||
continue;
|
||||
}
|
||||
List<TableFieldInfo> fieldList = tableInfo.getFieldList();
|
||||
for (TableFieldInfo fieldInfo : fieldList) {
|
||||
String column = fieldInfo.getColumn();
|
||||
if (tenantProperties.getColumn().equals(column)) {
|
||||
tenantTableList.add(tableName);
|
||||
continue tableFor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
||||
/**
|
||||
* 租户线程处理
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeTenantHolder {
|
||||
|
||||
private static final ThreadLocal<Boolean> TENANT_KEY_HOLDER = new NamedThreadLocal<Boolean>("blade-tenant") {
|
||||
@Override
|
||||
protected Boolean initialValue() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
};
|
||||
|
||||
public static void setIgnore(Boolean ignore) {
|
||||
TENANT_KEY_HOLDER.set(ignore);
|
||||
}
|
||||
|
||||
public static Boolean isIgnore() {
|
||||
return TENANT_KEY_HOLDER.get();
|
||||
}
|
||||
|
||||
|
||||
public static void clear() {
|
||||
TENANT_KEY_HOLDER.remove();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
import org.springblade.core.tool.utils.RandomType;
|
||||
import org.springblade.core.tool.utils.StringUtil;
|
||||
|
||||
/**
|
||||
* blade租户id生成器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class BladeTenantId implements TenantId {
|
||||
@Override
|
||||
public String generate() {
|
||||
return StringUtil.random(6, RandomType.INT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,433 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.Parenthesis;
|
||||
import net.sf.jsqlparser.expression.RowConstructor;
|
||||
import net.sf.jsqlparser.expression.StringValue;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
||||
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.schema.Table;
|
||||
import net.sf.jsqlparser.statement.delete.Delete;
|
||||
import net.sf.jsqlparser.statement.insert.Insert;
|
||||
import net.sf.jsqlparser.statement.select.*;
|
||||
import net.sf.jsqlparser.statement.update.Update;
|
||||
import net.sf.jsqlparser.statement.update.UpdateSet;
|
||||
import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.utils.CollectionUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 租户拦截器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BladeTenantInterceptor extends TenantLineInnerInterceptor {
|
||||
|
||||
/**
|
||||
* 租户处理器
|
||||
*/
|
||||
private TenantLineHandler tenantLineHandler;
|
||||
/**
|
||||
* 租户配置文件
|
||||
*/
|
||||
private BladeTenantProperties tenantProperties;
|
||||
/**
|
||||
* 超管需要启用租户过滤的表
|
||||
*/
|
||||
private List<String> adminTenantTables = Arrays.asList("blade_top_menu", "blade_dict_biz");
|
||||
|
||||
@Override
|
||||
public void setTenantLineHandler(TenantLineHandler tenantLineHandler) {
|
||||
super.setTenantLineHandler(tenantLineHandler);
|
||||
this.tenantLineHandler = tenantLineHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processInsert(Insert insert, int index, String sql, Object obj) {
|
||||
// 未启用租户增强,则使用原版逻辑
|
||||
if (!tenantProperties.getEnhance()) {
|
||||
super.processInsert(insert, index, sql, obj);
|
||||
return;
|
||||
}
|
||||
if (tenantLineHandler.ignoreTable(insert.getTable().getName())) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
List<Column> columns = insert.getColumns();
|
||||
if (CollectionUtils.isEmpty(columns)) {
|
||||
// 针对不给列名的insert 不处理
|
||||
return;
|
||||
}
|
||||
String tenantIdColumn = tenantLineHandler.getTenantIdColumn();
|
||||
if (tenantLineHandler.ignoreInsert(columns, tenantIdColumn)) {
|
||||
// 针对已给出租户列的insert 不处理
|
||||
return;
|
||||
}
|
||||
columns.add(new Column(tenantIdColumn));
|
||||
|
||||
// fixed gitee pulls/141 duplicate update
|
||||
List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList();
|
||||
if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
|
||||
EqualsTo equalsTo = new EqualsTo();
|
||||
equalsTo.setLeftExpression(new StringValue(tenantIdColumn));
|
||||
equalsTo.setRightExpression(tenantLineHandler.getTenantId());
|
||||
duplicateUpdateColumns.add(equalsTo);
|
||||
}
|
||||
|
||||
Select select = insert.getSelect();
|
||||
if (select != null && (select.getSelectBody() instanceof PlainSelect)) { //fix github issue 4998 修复升级到4.5版本的问题
|
||||
this.processInsertSelect(select.getSelectBody(), (String) obj);
|
||||
} else if (insert.getItemsList() != null) {
|
||||
// fixed github pull/295
|
||||
ItemsList itemsList = insert.getItemsList();
|
||||
Expression tenantId = tenantLineHandler.getTenantId();
|
||||
if (itemsList instanceof MultiExpressionList) {
|
||||
((MultiExpressionList) itemsList).getExpressionLists().forEach(el -> el.getExpressions().add(tenantId));
|
||||
} else {
|
||||
List<Expression> expressions = ((ExpressionList) itemsList).getExpressions();
|
||||
if (CollectionUtils.isNotEmpty(expressions)) {//fix github issue 4998 jsqlparse 4.5 批量insert ItemsList不是MultiExpressionList 了,需要特殊处理
|
||||
int len = expressions.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
Expression expression = expressions.get(i);
|
||||
if (expression instanceof RowConstructor) {
|
||||
((RowConstructor) expression).getExprList().getExpressions().add(tenantId);
|
||||
} else if (expression instanceof Parenthesis) {
|
||||
RowConstructor rowConstructor = new RowConstructor()
|
||||
.withExprList(new ExpressionList(((Parenthesis) expression).getExpression(), tenantId));
|
||||
expressions.set(i, rowConstructor);
|
||||
} else {
|
||||
if (len - 1 == i) { // (?,?) 只有最后一个expre的时候才拼接tenantId
|
||||
expressions.add(tenantId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
expressions.add(tenantId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 PlainSelect
|
||||
*/
|
||||
@Override
|
||||
protected void processPlainSelect(final PlainSelect plainSelect, final String whereSegment) {
|
||||
//#3087 github
|
||||
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
||||
if (CollectionUtils.isNotEmpty(selectItems)) {
|
||||
selectItems.forEach(selectItem -> processSelectItem(selectItem, whereSegment));
|
||||
}
|
||||
|
||||
// 处理 where 中的子查询
|
||||
Expression where = plainSelect.getWhere();
|
||||
processWhereSubSelect(where, whereSegment);
|
||||
|
||||
// 处理 fromItem
|
||||
FromItem fromItem = plainSelect.getFromItem();
|
||||
List<Table> list = processFromItem(fromItem, whereSegment);
|
||||
List<Table> mainTables = new ArrayList<>(list);
|
||||
|
||||
// 处理 join
|
||||
List<Join> joins = plainSelect.getJoins();
|
||||
if (CollectionUtils.isNotEmpty(joins)) {
|
||||
mainTables = processJoins(mainTables, joins, whereSegment);
|
||||
}
|
||||
|
||||
// 当有 mainTable 时,进行 where 条件追加
|
||||
if (CollectionUtils.isNotEmpty(mainTables) && !doTenantFilters(mainTables)) {
|
||||
plainSelect.setWhere(builderExpression(where, mainTables, whereSegment));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* update 语句处理
|
||||
*/
|
||||
@Override
|
||||
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
||||
final Table table = update.getTable();
|
||||
if (tenantLineHandler.ignoreTable(table.getName())) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
if (doTenantFilter(table.getName())) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
ArrayList<UpdateSet> sets = update.getUpdateSets();
|
||||
if (!CollectionUtils.isEmpty(sets)) {
|
||||
sets.forEach(us -> us.getExpressions().forEach(ex -> {
|
||||
if (ex instanceof SubSelect) {
|
||||
processSelectBody(((SubSelect) ex).getSelectBody(), (String) obj);
|
||||
}
|
||||
}));
|
||||
}
|
||||
update.setWhere(this.andExpression(table, update.getWhere(), (String) obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete 语句处理
|
||||
*/
|
||||
@Override
|
||||
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
||||
final Table table = delete.getTable();
|
||||
if (tenantLineHandler.ignoreTable(table.getName())) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
if (doTenantFilter(table.getName())) {
|
||||
// 过滤退出执行
|
||||
return;
|
||||
}
|
||||
delete.setWhere(this.andExpression(table, delete.getWhere(), (String) obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* delete update 语句 where 处理
|
||||
*/
|
||||
@Override
|
||||
protected Expression andExpression(Table table, Expression where, final String whereSegment) {
|
||||
//获得where条件表达式
|
||||
final Expression expression = buildTableExpression(table, where, whereSegment);
|
||||
if (expression == null) {
|
||||
return where;
|
||||
}
|
||||
if (where != null) {
|
||||
if (where instanceof OrExpression) {
|
||||
return new AndExpression(new Parenthesis(where), expression);
|
||||
} else {
|
||||
return new AndExpression(where, expression);
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建租户条件表达式
|
||||
*
|
||||
* @param table 表对象
|
||||
* @param where 当前where条件
|
||||
* @param whereSegment 所属Mapper对象全路径(在原租户拦截器功能中,这个参数并不需要参与相关判断)
|
||||
* @return 租户条件表达式
|
||||
*/
|
||||
@Override
|
||||
public Expression buildTableExpression(final Table table, final Expression where, final String whereSegment) {
|
||||
//若是忽略的表则不进行数据隔离
|
||||
if (tenantLineHandler.ignoreTable(table.getName())) {
|
||||
return null;
|
||||
}
|
||||
//若是超管则不进行数据隔离
|
||||
if (doTenantFilter(table.getName())) {
|
||||
return null;
|
||||
}
|
||||
//获得条件表达式
|
||||
return new EqualsTo(getAliasColumn(table), tenantLineHandler.getTenantId());
|
||||
}
|
||||
|
||||
private List<Table> processFromItem(FromItem fromItem, final String whereSegment) {
|
||||
// 处理括号括起来的表达式
|
||||
while (fromItem instanceof ParenthesisFromItem) {
|
||||
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
||||
}
|
||||
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
// 无 join 时的处理逻辑
|
||||
if (fromItem instanceof Table) {
|
||||
Table fromTable = (Table) fromItem;
|
||||
mainTables.add(fromTable);
|
||||
} else if (fromItem instanceof SubJoin) {
|
||||
// SubJoin 类型则还需要添加上 where 条件
|
||||
List<Table> tables = processSubJoin((SubJoin) fromItem, whereSegment);
|
||||
mainTables.addAll(tables);
|
||||
} else {
|
||||
// 处理下 fromItem
|
||||
processOtherFromItem(fromItem, whereSegment);
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理 sub join
|
||||
*
|
||||
* @param subJoin subJoin
|
||||
* @return Table subJoin 中的主表
|
||||
*/
|
||||
private List<Table> processSubJoin(SubJoin subJoin, final String whereSegment) {
|
||||
List<Table> mainTables = new ArrayList<>();
|
||||
if (subJoin.getJoinList() != null) {
|
||||
List<Table> list = processFromItem(subJoin.getLeft(), whereSegment);
|
||||
mainTables.addAll(list);
|
||||
mainTables = processJoins(mainTables, subJoin.getJoinList(), whereSegment);
|
||||
}
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理 joins
|
||||
*
|
||||
* @param mainTables 可以为 null
|
||||
* @param joins join 集合
|
||||
* @return List<Table> 右连接查询的 Table 列表
|
||||
*/
|
||||
private List<Table> processJoins(List<Table> mainTables, List<Join> joins, final String whereSegment) {
|
||||
// join 表达式中最终的主表
|
||||
Table mainTable = null;
|
||||
// 当前 join 的左表
|
||||
Table leftTable = null;
|
||||
|
||||
if (mainTables.size() == 1) {
|
||||
mainTable = mainTables.get(0);
|
||||
leftTable = mainTable;
|
||||
}
|
||||
|
||||
//对于 on 表达式写在最后的 join,需要记录下前面多个 on 的表名
|
||||
Deque<List<Table>> onTableDeque = new LinkedList<>();
|
||||
for (Join join : joins) {
|
||||
// 处理 on 表达式
|
||||
FromItem joinItem = join.getRightItem();
|
||||
|
||||
// 获取当前 join 的表,subJoint 可以看作是一张表
|
||||
List<Table> joinTables = null;
|
||||
if (joinItem instanceof Table) {
|
||||
joinTables = new ArrayList<>();
|
||||
joinTables.add((Table) joinItem);
|
||||
} else if (joinItem instanceof SubJoin) {
|
||||
joinTables = processSubJoin((SubJoin) joinItem, whereSegment);
|
||||
}
|
||||
|
||||
if (joinTables != null) {
|
||||
|
||||
// 如果是隐式内连接
|
||||
if (join.isSimple()) {
|
||||
mainTables.addAll(joinTables);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 当前表是否忽略
|
||||
Table joinTable = joinTables.get(0);
|
||||
|
||||
List<Table> onTables = null;
|
||||
// 如果不要忽略,且是右连接,则记录下当前表
|
||||
if (join.isRight()) {
|
||||
mainTable = joinTable;
|
||||
mainTables.clear();
|
||||
if (leftTable != null) {
|
||||
onTables = Collections.singletonList(leftTable);
|
||||
}
|
||||
} else if (join.isInner()) {
|
||||
if (mainTable == null) {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
} else {
|
||||
onTables = Arrays.asList(mainTable, joinTable);
|
||||
}
|
||||
mainTable = null;
|
||||
mainTables.clear();
|
||||
} else {
|
||||
onTables = Collections.singletonList(joinTable);
|
||||
}
|
||||
|
||||
if (mainTable != null && !mainTables.contains(mainTable)) {
|
||||
mainTables.add(mainTable);
|
||||
}
|
||||
|
||||
// 获取 join 尾缀的 on 表达式列表
|
||||
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
||||
// 正常 join on 表达式只有一个,立刻处理
|
||||
if (originOnExpressions.size() == 1 && onTables != null) {
|
||||
List<Expression> onExpressions = new LinkedList<>();
|
||||
onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables, whereSegment));
|
||||
join.setOnExpressions(onExpressions);
|
||||
leftTable = mainTable == null ? joinTable : mainTable;
|
||||
continue;
|
||||
}
|
||||
// 表名压栈,忽略的表压入 null,以便后续不处理
|
||||
onTableDeque.push(onTables);
|
||||
// 尾缀多个 on 表达式的时候统一处理
|
||||
if (originOnExpressions.size() > 1) {
|
||||
Collection<Expression> onExpressions = new LinkedList<>();
|
||||
for (Expression originOnExpression : originOnExpressions) {
|
||||
List<Table> currentTableList = onTableDeque.poll();
|
||||
if (CollectionUtils.isEmpty(currentTableList)) {
|
||||
onExpressions.add(originOnExpression);
|
||||
} else {
|
||||
onExpressions.add(builderExpression(originOnExpression, currentTableList, whereSegment));
|
||||
}
|
||||
}
|
||||
join.setOnExpressions(onExpressions);
|
||||
}
|
||||
leftTable = joinTable;
|
||||
} else {
|
||||
processOtherFromItem(joinItem, whereSegment);
|
||||
leftTable = null;
|
||||
}
|
||||
}
|
||||
|
||||
return mainTables;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断当前操作是否需要进行过滤
|
||||
*
|
||||
* @param tableName 表名
|
||||
*/
|
||||
public boolean doTenantFilter(String tableName) {
|
||||
return AuthUtil.isAdministrator() && !adminTenantTables.contains(tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前操作是否需要进行过滤
|
||||
*
|
||||
* @param tables 表名
|
||||
*/
|
||||
public boolean doTenantFilters(List<Table> tables) {
|
||||
List<String> tableNames = tables.stream().map(Table::getName).collect(Collectors.toList());
|
||||
return AuthUtil.isAdministrator() && !CollectionUtil.containsAny(adminTenantTables, tableNames);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 多租户配置
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "blade.tenant")
|
||||
public class BladeTenantProperties {
|
||||
|
||||
/**
|
||||
* 是否增强多租户
|
||||
*/
|
||||
private Boolean enhance = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 是否开启授权码校验
|
||||
*/
|
||||
private Boolean license = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 是否开启动态数据源功能
|
||||
*/
|
||||
private Boolean dynamicDatasource = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 是否开启动态数据源全局扫描
|
||||
*/
|
||||
private Boolean dynamicGlobal = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 多租户字段名称
|
||||
*/
|
||||
private String column = "tenant_id";
|
||||
|
||||
/**
|
||||
* 是否开启注解排除
|
||||
*/
|
||||
private Boolean annotationExclude = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 需要排除进行自定义的多租户表
|
||||
*/
|
||||
private List<String> excludeTables = new ArrayList<>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant;
|
||||
|
||||
/**
|
||||
* 租户id生成器
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface TenantId {
|
||||
|
||||
/**
|
||||
* 生成自定义租户id
|
||||
*
|
||||
* @return tenantId
|
||||
*/
|
||||
String generate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 排除租户数据源自动切换.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface NonDS {
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.annotation;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 指定租户表排除.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
|
||||
@Component
|
||||
public @interface TableExclude {
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.annotation;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 指定租户动态数据源切换.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@DS("#token.tenantId")
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TenantDS {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 排除租户逻辑.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TenantIgnore {
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.annotation;
|
||||
|
||||
import com.baomidou.dynamic.datasource.annotation.DS;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 指定租户ID动态数据源切换.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@DS("#tenantId")
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface TenantParamDS {
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
|
||||
package org.springblade.core.tenant.aspect;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springblade.core.tenant.BladeTenantHolder;
|
||||
import org.springblade.core.tenant.annotation.TenantIgnore;
|
||||
|
||||
/**
|
||||
* 自定义租户切面
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
public class BladeTenantAspect {
|
||||
|
||||
@Around("@annotation(tenantIgnore)")
|
||||
public Object around(ProceedingJoinPoint point, TenantIgnore tenantIgnore) throws Throwable {
|
||||
try {
|
||||
//开启忽略
|
||||
BladeTenantHolder.setIgnore(Boolean.TRUE);
|
||||
//执行方法
|
||||
return point.proceed();
|
||||
} finally {
|
||||
//关闭忽略
|
||||
BladeTenantHolder.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.config;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springblade.core.mp.config.MybatisPlusConfiguration;
|
||||
import org.springblade.core.tenant.*;
|
||||
import org.springblade.core.tenant.aspect.BladeTenantAspect;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
/**
|
||||
* 多租户配置类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@AutoConfiguration(before = MybatisPlusConfiguration.class)
|
||||
@EnableConfigurationProperties(BladeTenantProperties.class)
|
||||
public class TenantConfiguration {
|
||||
|
||||
/**
|
||||
* 自定义多租户处理器
|
||||
*
|
||||
* @param tenantProperties 多租户配置类
|
||||
* @return TenantHandler
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public TenantLineHandler bladeTenantHandler(BladeTenantProperties tenantProperties) {
|
||||
return new BladeTenantHandler(tenantProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义租户拦截器
|
||||
*
|
||||
* @param tenantHandler 多租户处理器
|
||||
* @param tenantProperties 多租户配置类
|
||||
* @return BladeTenantInterceptor
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantLineHandler tenantHandler, BladeTenantProperties tenantProperties) {
|
||||
BladeTenantInterceptor tenantInterceptor = new BladeTenantInterceptor();
|
||||
tenantInterceptor.setTenantLineHandler(tenantHandler);
|
||||
tenantInterceptor.setTenantProperties(tenantProperties);
|
||||
return tenantInterceptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义租户id生成器
|
||||
*
|
||||
* @return TenantId
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(TenantId.class)
|
||||
public TenantId tenantId() {
|
||||
return new BladeTenantId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义租户切面
|
||||
*/
|
||||
@Bean
|
||||
public BladeTenantAspect bladeTenantAspect() {
|
||||
return new BladeTenantAspect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.constant;
|
||||
|
||||
/**
|
||||
* 租户常量.
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public interface TenantBaseConstant {
|
||||
|
||||
/**
|
||||
* 租户数据源缓存名
|
||||
*/
|
||||
String TENANT_DATASOURCE_CACHE = "blade:datasource";
|
||||
|
||||
/**
|
||||
* 租户数据源缓存键
|
||||
*/
|
||||
String TENANT_DATASOURCE_KEY = "tenant:id:";
|
||||
|
||||
/**
|
||||
* 租户数据源缓存键
|
||||
*/
|
||||
String TENANT_DATASOURCE_EXIST_KEY = "tenant:exist:";
|
||||
|
||||
/**
|
||||
* 租户动态数据源键
|
||||
*/
|
||||
String TENANT_DYNAMIC_DATASOURCE_PROP = "blade.tenant.dynamic-datasource";
|
||||
|
||||
/**
|
||||
* 租户全局动态数据源切面键
|
||||
*/
|
||||
String TENANT_DYNAMIC_GLOBAL_PROP = "blade.tenant.dynamic-global";
|
||||
|
||||
/**
|
||||
* 租户是否存在数据源
|
||||
*/
|
||||
String TENANT_DATASOURCE_EXIST_STATEMENT = "select datasource_id from blade_tenant WHERE is_deleted = 0 AND tenant_id = ?";
|
||||
|
||||
/**
|
||||
* 租户数据源基础SQL
|
||||
*/
|
||||
String TENANT_DATASOURCE_BASE_STATEMENT = "SELECT category, tenant_id as tenantId, driver_class as driverClass, url, username, password, sharding_config as shardingConfig from blade_tenant tenant LEFT JOIN blade_datasource datasource ON tenant.datasource_id = datasource.id ";
|
||||
|
||||
/**
|
||||
* 租户单数据源SQL
|
||||
*/
|
||||
String TENANT_DATASOURCE_SINGLE_STATEMENT = TENANT_DATASOURCE_BASE_STATEMENT + "WHERE tenant.is_deleted = 0 AND tenant.tenant_id = ?";
|
||||
|
||||
/**
|
||||
* 租户集动态数据源SQL
|
||||
*/
|
||||
String TENANT_DATASOURCE_GROUP_STATEMENT = TENANT_DATASOURCE_BASE_STATEMENT + "WHERE tenant.is_deleted = 0";
|
||||
|
||||
/**
|
||||
* 租户未找到返回信息
|
||||
*/
|
||||
String TENANT_DATASOURCE_NOT_FOUND = "未找到租户信息,数据源加载失败!";
|
||||
|
||||
/**
|
||||
* oracle驱动类
|
||||
*/
|
||||
String ORACLE_DRIVER_CLASS = "oracle.jdbc.OracleDriver";
|
||||
|
||||
/**
|
||||
* oracle校验
|
||||
*/
|
||||
String ORACLE_VALIDATE_STATEMENT = "select 1 from dual";
|
||||
|
||||
/**
|
||||
* 通用校验
|
||||
*/
|
||||
String COMMON_VALIDATE_STATEMENT = "select 1";
|
||||
|
||||
/**
|
||||
* jdbc数据源分类
|
||||
*/
|
||||
int JDBC_CATEGORY = 1;
|
||||
|
||||
/**
|
||||
* sharding数据源分类
|
||||
*/
|
||||
int SHARDING_CATEGORY = 2;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.exception;
|
||||
|
||||
/**
|
||||
* 租户数据源异常
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
public class TenantDataSourceException extends RuntimeException {
|
||||
|
||||
public TenantDataSourceException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 提高性能
|
||||
*
|
||||
* @return Throwable
|
||||
*/
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Throwable doFillInStackTrace() {
|
||||
return super.fillInStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* BladeX Commercial License Agreement
|
||||
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||
* <p>
|
||||
* Use of this software is governed by the Commercial License Agreement
|
||||
* obtained after purchasing a license from BladeX.
|
||||
* <p>
|
||||
* 1. This software is for development use only under a valid license
|
||||
* from BladeX.
|
||||
* <p>
|
||||
* 2. Redistribution of this software's source code to any third party
|
||||
* without a commercial license is strictly prohibited.
|
||||
* <p>
|
||||
* 3. Licensees may copyright their own code but cannot use segments
|
||||
* from this software for such purposes. Copyright of this software
|
||||
* remains with BladeX.
|
||||
* <p>
|
||||
* Using this software signifies agreement to this License, and the software
|
||||
* must not be used for illegal purposes.
|
||||
* <p>
|
||||
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
|
||||
* not liable for any claims arising from secondary or illegal development.
|
||||
* <p>
|
||||
* Author: Chill Zhuang (bladejava@qq.com)
|
||||
*/
|
||||
package org.springblade.core.tenant.mp;
|
||||
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import org.springblade.core.mp.base.BaseEntity;
|
||||
|
||||
/**
|
||||
* 租户基础实体类
|
||||
*
|
||||
* @author Chill
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TenantEntity extends BaseEntity {
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@Schema(description = "租户ID")
|
||||
private String tenantId;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user