package com.qianwen.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 java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collection;
|
import java.util.Collections;
|
import java.util.Deque;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.stream.Collectors;
|
import net.sf.jsqlparser.expression.BinaryExpression;
|
import net.sf.jsqlparser.expression.Expression;
|
import net.sf.jsqlparser.expression.Parenthesis;
|
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.MultiExpressionList;
|
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
|
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.FromItem;
|
import net.sf.jsqlparser.statement.select.Join;
|
import net.sf.jsqlparser.statement.select.ParenthesisFromItem;
|
import net.sf.jsqlparser.statement.select.PlainSelect;
|
import net.sf.jsqlparser.statement.select.Select;
|
import net.sf.jsqlparser.statement.select.SelectItem;
|
import net.sf.jsqlparser.statement.select.SubJoin;
|
import net.sf.jsqlparser.statement.update.Update;
|
import com.qianwen.core.secure.utils.AuthUtil;
|
import com.qianwen.core.tool.utils.CollectionUtil;
|
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
|
|
public class BladeTenantInterceptor extends TenantLineInnerInterceptor {
|
private TenantLineHandler tenantLineHandler;
|
private BladeTenantProperties tenantProperties;
|
private List<String> adminTenantTables = Arrays.asList("blade_top_menu", "blade_dict_biz");
|
|
public void setTenantProperties(final BladeTenantProperties tenantProperties) {
|
this.tenantProperties = tenantProperties;
|
}
|
|
public void setAdminTenantTables(final List<String> adminTenantTables) {
|
this.adminTenantTables = adminTenantTables;
|
}
|
|
public String toString() {
|
return "BladeTenantInterceptor(super=" + super.toString() + ", tenantLineHandler=" + getTenantLineHandler() + ", tenantProperties=" + getTenantProperties() + ", adminTenantTables=" + getAdminTenantTables() + ")";
|
}
|
|
public boolean equals(final Object o) {
|
if (o == this) {
|
return true;
|
}
|
if (o instanceof BladeTenantInterceptor) {
|
BladeTenantInterceptor other = (BladeTenantInterceptor) o;
|
if (other.canEqual(this) && super.equals(o)) {
|
Object this$tenantLineHandler = getTenantLineHandler();
|
Object other$tenantLineHandler = other.getTenantLineHandler();
|
if (this$tenantLineHandler == null) {
|
if (other$tenantLineHandler != null) {
|
return false;
|
}
|
} else if (!this$tenantLineHandler.equals(other$tenantLineHandler)) {
|
return false;
|
}
|
Object this$tenantProperties = getTenantProperties();
|
Object other$tenantProperties = other.getTenantProperties();
|
if (this$tenantProperties == null) {
|
if (other$tenantProperties != null) {
|
return false;
|
}
|
} else if (!this$tenantProperties.equals(other$tenantProperties)) {
|
return false;
|
}
|
Object this$adminTenantTables = getAdminTenantTables();
|
Object other$adminTenantTables = other.getAdminTenantTables();
|
return this$adminTenantTables == null ? other$adminTenantTables == null : this$adminTenantTables.equals(other$adminTenantTables);
|
}
|
return false;
|
}
|
return false;
|
}
|
|
protected boolean canEqual(final Object other) {
|
return other instanceof BladeTenantInterceptor;
|
}
|
|
public int hashCode() {
|
int result = super.hashCode();
|
Object $tenantLineHandler = getTenantLineHandler();
|
int result2 = (result * 59) + ($tenantLineHandler == null ? 43 : $tenantLineHandler.hashCode());
|
Object $tenantProperties = getTenantProperties();
|
int result3 = (result2 * 59) + ($tenantProperties == null ? 43 : $tenantProperties.hashCode());
|
Object $adminTenantTables = getAdminTenantTables();
|
return (result3 * 59) + ($adminTenantTables == null ? 43 : $adminTenantTables.hashCode());
|
}
|
|
public TenantLineHandler getTenantLineHandler() {
|
return this.tenantLineHandler;
|
}
|
|
public BladeTenantProperties getTenantProperties() {
|
return this.tenantProperties;
|
}
|
|
public List<String> getAdminTenantTables() {
|
return this.adminTenantTables;
|
}
|
|
public void setTenantLineHandler(TenantLineHandler tenantLineHandler) {
|
super.setTenantLineHandler(tenantLineHandler);
|
this.tenantLineHandler = tenantLineHandler;
|
}
|
|
protected void processInsert(Insert insert, int index, String sql, Object obj) {
|
if (!this.tenantProperties.getEnhance().booleanValue()) {
|
super.processInsert(insert, index, sql, obj);
|
return;
|
}
|
if (this.tenantLineHandler.ignoreTable(insert.getTable().getName()))
|
return;
|
List<Column> columns = insert.getColumns();
|
if (CollectionUtils.isEmpty(columns))
|
return;
|
String tenantIdColumn = this.tenantLineHandler.getTenantIdColumn();
|
if (columns.stream().map(Column::getColumnName).anyMatch(i -> i.equals(tenantIdColumn)))
|
return;
|
columns.add(new Column(tenantIdColumn));
|
List<Expression> duplicateUpdateColumns = insert.getDuplicateUpdateExpressionList();
|
if (CollectionUtils.isNotEmpty(duplicateUpdateColumns)) {
|
EqualsTo equalsTo = new EqualsTo();
|
equalsTo.setLeftExpression((Expression)new StringValue(tenantIdColumn));
|
equalsTo.setRightExpression(this.tenantLineHandler.getTenantId());
|
duplicateUpdateColumns.add(equalsTo);
|
}
|
Select select = insert.getSelect();
|
if (select != null) {
|
processInsertSelect(select.getSelectBody());
|
} else if (insert.getItemsList() != null) {
|
ItemsList itemsList = insert.getItemsList();
|
if (itemsList instanceof MultiExpressionList) {
|
((MultiExpressionList)itemsList).getExpressionLists().forEach(el -> el.getExpressions().add(this.tenantLineHandler.getTenantId()));
|
} else {
|
((ExpressionList)itemsList).getExpressions().add(this.tenantLineHandler.getTenantId());
|
}
|
} else {
|
throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId", new Object[0]);
|
}
|
}
|
|
protected void processPlainSelect(PlainSelect plainSelect) {
|
List<SelectItem> selectItems = plainSelect.getSelectItems();
|
if (CollectionUtils.isNotEmpty(selectItems)) {
|
selectItems.forEach(this::processSelectItem);
|
}
|
Expression where = plainSelect.getWhere();
|
processWhereSubSelect(where);
|
FromItem fromItem = plainSelect.getFromItem();
|
List<Table> list = processFromItem(fromItem);
|
List<Table> mainTables = new ArrayList<>(list);
|
List<Join> joins = plainSelect.getJoins();
|
if (CollectionUtils.isNotEmpty(joins)) {
|
mainTables = processJoins(mainTables, joins);
|
}
|
if (CollectionUtils.isNotEmpty(mainTables) && !doTenantFilters(mainTables)) {
|
plainSelect.setWhere(builderExpression(where, mainTables));
|
}
|
}
|
|
protected void processUpdate(Update update, int index, String sql, Object obj) {
|
Table table = update.getTable();
|
if (this.tenantLineHandler.ignoreTable(table.getName()) || doTenantFilter(table.getName())) {
|
return;
|
}
|
update.setWhere(andExpression(table, update.getWhere()));
|
}
|
|
protected void processDelete(Delete delete, int index, String sql, Object obj) {
|
Table table = delete.getTable();
|
if (this.tenantLineHandler.ignoreTable(table.getName()) || doTenantFilter(table.getName())) {
|
return;
|
}
|
delete.setWhere(andExpression(table, delete.getWhere()));
|
}
|
|
protected BinaryExpression andExpression(Table table, Expression where) {
|
EqualsTo equalsTo = new EqualsTo();
|
Expression aliasColumn = getAliasColumn(table);
|
//Column tenantId = this.tenantLineHandler.getTenantId();
|
// Column extends ASTNodeAccessImpl implements Expression
|
Expression tenantId = this.tenantLineHandler.getTenantId();
|
if (doTenantFilter(table.getName())) {
|
Expression stringValue = new StringValue("1");
|
tenantId = stringValue;
|
aliasColumn = stringValue;
|
}
|
equalsTo.setLeftExpression(aliasColumn);
|
equalsTo.setRightExpression(tenantId);
|
if (null != where) {
|
if (where instanceof OrExpression) {
|
return new AndExpression(equalsTo, new Parenthesis(where));
|
}
|
return new AndExpression(equalsTo, where);
|
}
|
return equalsTo;
|
|
}
|
|
protected Expression builderExpression(Expression currentExpression, List<Table> tables) {
|
if (CollectionUtils.isEmpty(tables)) {
|
return currentExpression;
|
}
|
Expression tenantId = this.tenantLineHandler.getTenantId();
|
List<EqualsTo> equalsTos = (List) tables.stream().filter(x -> {
|
return !this.tenantLineHandler.ignoreTable(x.getName());
|
}).filter(x2 -> {
|
return !doTenantFilter(x2.getName());
|
}).map(item -> {
|
return new EqualsTo(getAliasColumn(item), tenantId);
|
}).collect(Collectors.toList());
|
if (CollectionUtils.isEmpty(equalsTos)) {
|
return currentExpression;
|
}
|
Expression injectExpression = (Expression) equalsTos.get(0);
|
if (equalsTos.size() > 1) {
|
for (int i = 1; i < equalsTos.size(); i++) {
|
injectExpression = new AndExpression(injectExpression, (Expression) equalsTos.get(i));
|
}
|
}
|
if (currentExpression == null) {
|
return injectExpression;
|
}
|
if (currentExpression instanceof OrExpression) {
|
return new AndExpression(new Parenthesis(currentExpression), injectExpression);
|
}
|
return new AndExpression(currentExpression, injectExpression);
|
}
|
|
private List<Table> processFromItem(FromItem fromItem) {
|
while (fromItem instanceof ParenthesisFromItem) {
|
fromItem = ((ParenthesisFromItem) fromItem).getFromItem();
|
}
|
List<Table> mainTables = new ArrayList<>();
|
if (fromItem instanceof Table) {
|
Table fromTable = (Table) fromItem;
|
mainTables.add(fromTable);
|
} else if (fromItem instanceof SubJoin) {
|
List<Table> tables = processSubJoin((SubJoin) fromItem);
|
mainTables.addAll(tables);
|
} else {
|
processOtherFromItem(fromItem);
|
}
|
return mainTables;
|
}
|
|
private List<Table> processSubJoin(SubJoin subJoin) {
|
List<Table> mainTables = new ArrayList<>();
|
if (subJoin.getJoinList() != null) {
|
List<Table> list = processFromItem(subJoin.getLeft());
|
mainTables.addAll(list);
|
mainTables = processJoins(mainTables, subJoin.getJoinList());
|
}
|
return mainTables;
|
}
|
|
private List<Table> processJoins(List<Table> mainTables, List<Join> joins) {
|
Table mainTable = null;
|
Table leftTable = null;
|
if (mainTables == null) {
|
mainTables = new ArrayList<>();
|
} else if (mainTables.size() == 1) {
|
mainTable = mainTables.get(0);
|
leftTable = mainTable;
|
}
|
Deque<List<Table>> onTableDeque = new LinkedList<>();
|
for (Join join : joins) {
|
FromItem joinItem = join.getRightItem();
|
List<Table> joinTables = null;
|
if (joinItem instanceof Table) {
|
joinTables = new ArrayList<>();
|
joinTables.add((Table) joinItem);
|
} else if (joinItem instanceof SubJoin) {
|
joinTables = processSubJoin((SubJoin) joinItem);
|
}
|
if (joinTables != null) {
|
if (join.isSimple()) {
|
mainTables.addAll(joinTables);
|
} else {
|
Table joinTable = joinTables.get(0);
|
List<Table> onTables = null;
|
if (join.isRight()) {
|
mainTable = joinTable;
|
if (leftTable != null) {
|
onTables = Collections.singletonList(leftTable);
|
}
|
} else if (join.isLeft()) {
|
onTables = Collections.singletonList(joinTable);
|
} else if (join.isInner()) {
|
onTables = mainTable == null ? Collections.singletonList(joinTable) : Arrays.asList(mainTable, joinTable);
|
mainTable = null;
|
}
|
mainTables = new ArrayList<>();
|
if (mainTable != null) {
|
mainTables.add(mainTable);
|
}
|
Collection<Expression> originOnExpressions = join.getOnExpressions();
|
if (originOnExpressions.size() == 1 && onTables != null) {
|
List<Expression> onExpressions = new LinkedList<>();
|
onExpressions.add(builderExpression(originOnExpressions.iterator().next(), onTables));
|
join.setOnExpressions(onExpressions);
|
leftTable = joinTable;
|
} else {
|
onTableDeque.push(onTables);
|
if (originOnExpressions.size() > 1) {
|
Collection<Expression> onExpressions2 = new LinkedList<>();
|
for (Expression originOnExpression : originOnExpressions) {
|
List<Table> currentTableList = onTableDeque.poll();
|
if (CollectionUtils.isEmpty(currentTableList)) {
|
onExpressions2.add(originOnExpression);
|
} else {
|
onExpressions2.add(builderExpression(originOnExpression, currentTableList));
|
}
|
}
|
join.setOnExpressions(onExpressions2);
|
}
|
leftTable = joinTable;
|
}
|
}
|
} else {
|
processOtherFromItem(joinItem);
|
leftTable = null;
|
}
|
}
|
return mainTables;
|
}
|
|
public boolean doTenantFilter(String tableName) {
|
return AuthUtil.isAdministrator() && !this.adminTenantTables.contains(tableName);
|
}
|
|
public boolean doTenantFilters(List<Table> tables) {
|
List<String> tableNames = (List) tables.stream().map((v0) -> {
|
return v0.getName();
|
}).collect(Collectors.toList());
|
return AuthUtil.isAdministrator() && !CollectionUtil.containsAny(this.adminTenantTables, tableNames);
|
}
|
}
|