mybatis租户


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections;
import org.reflections.scanners.Scanner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;


public class EntityDataTenantHolder implements DataTenantHolder {
    private Map<String, Boolean> entityBooleanMap = new HashMap(500);
    private Map<String, Boolean> entityTenantBooleanMap = new HashMap(500);
    @Autowired
    private DataTenantConfig dataTenantConfig;

    public EntityDataTenantHolder() {
    }

    @PostConstruct
    public void init() {
        if (StringUtils.isNotBlank(this.dataTenantConfig.getModelPackage())) {
            String[] modelPackStrs = this.dataTenantConfig.getModelPackage().split(",");
            String[] var2 = modelPackStrs;
            int var3 = modelPackStrs.length;

            for(int var4 = 0; var4 < var3; ++var4) {
                String modelPackStr = var2[var4];
                Reflections reflections = new Reflections(modelPackStr, new Scanner[0]);
                Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(TableName.class);
                classSet.forEach((cls) -> {
                    TableName tableName = (TableName)cls.getAnnotation(TableName.class);
                    if (Objects.nonNull(tableName)) {
                        if (ReflectionUtils.findField(cls, this.dataTenantConfig.getDataTenantIdField()) != null) {
                            this.entityBooleanMap.put(tableName.value(), true);
                        } else {
                            this.entityBooleanMap.put(tableName.value(), false);
                        }

                        if (ReflectionUtils.findField(cls, this.dataTenantConfig.getTenantIdField()) != null) {
                            this.entityTenantBooleanMap.put(tableName.value(), true);
                        } else {
                            this.entityTenantBooleanMap.put(tableName.value(), false);
                        }
                    }

                });
            }
        } else {
            List<TableInfo> tableInfos = TableInfoHelper.getTableInfos();
            if (CollectionUtils.isNotEmpty(tableInfos)) {
                Iterator var9 = tableInfos.iterator();

                while(var9.hasNext()) {
                    TableInfo tableInfo = (TableInfo)var9.next();
                    if (ReflectionUtils.findField(tableInfo.getEntityType(), this.dataTenantConfig.getDataTenantIdField()) != null) {
                        this.entityBooleanMap.put(tableInfo.getTableName(), true);
                    } else {
                        this.entityBooleanMap.put(tableInfo.getTableName(), false);
                    }

                    if (ReflectionUtils.findField(tableInfo.getEntityType(), this.dataTenantConfig.getTenantIdField()) != null) {
                        this.entityTenantBooleanMap.put(tableInfo.getTableName(), true);
                    } else {
                        this.entityTenantBooleanMap.put(tableInfo.getTableName(), false);
                    }
                }
            }
        }

        LogTools.info("初始化需要租户的实体类:{}", new Object[]{JSON.toJSONString(this.entityBooleanMap)});
    }

    public boolean containEntityMap(String databaseName, String tableName) {
        if (StringUtils.isNotBlank(databaseName)) {
            String fullName = databaseName + "." + tableName;
            return this.entityBooleanMap.get(fullName) != null ? (Boolean)this.entityBooleanMap.get(fullName) : false;
        } else {
            return this.entityBooleanMap.get(tableName) != null ? (Boolean)this.entityBooleanMap.get(tableName) : false;
        }
    }

    public boolean containEntityTenantMap(String databaseName, String tableName) {
        if (StringUtils.isNotBlank(databaseName)) {
            String fullName = databaseName + "." + tableName;
            return this.entityTenantBooleanMap.get(fullName) != null ? (Boolean)this.entityTenantBooleanMap.get(fullName) : false;
        } else {
            return this.entityTenantBooleanMap.get(tableName) != null ? (Boolean)this.entityTenantBooleanMap.get(tableName) : false;
        }
    }
}

import com.baomidou.mybatisplus.core.parser.AbstractJsqlParser;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import net.sf.jsqlparser.expression.BinaryExpression;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.Parenthesis;
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.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.expression.operators.relational.MultiExpressionList;
import net.sf.jsqlparser.expression.operators.relational.SupportsOldOracleJoinSyntax;
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.LateralSubSelect;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.SelectBody;
import net.sf.jsqlparser.statement.select.SelectExpressionItem;
import net.sf.jsqlparser.statement.select.SetOperationList;
import net.sf.jsqlparser.statement.select.SubJoin;
import net.sf.jsqlparser.statement.select.SubSelect;
import net.sf.jsqlparser.statement.select.ValuesList;
import net.sf.jsqlparser.statement.select.WithItem;
import net.sf.jsqlparser.statement.update.Update;
public class DataTenantSqlParser extends AbstractJsqlParser {
    private DataTenantHandler dataTenantHandler;

    public void processSelectBody(SelectBody selectBody) {
        if (selectBody instanceof PlainSelect) {
            this.processPlainSelect((PlainSelect)selectBody);
        } else if (selectBody instanceof WithItem) {
            WithItem withItem = (WithItem)selectBody;
            if (withItem.getSelectBody() != null) {
                this.processSelectBody(withItem.getSelectBody());
            }
        } else {
            SetOperationList operationList = (SetOperationList)selectBody;
            if (operationList.getSelects() != null && operationList.getSelects().size() > 0) {
                operationList.getSelects().forEach(this::processSelectBody);
            }
        }

    }

    public void processInsert(Insert insert) {
        Table table = insert.getTable();
        if (!this.dataTenantHandler.doTableFilter(table.getSchemaName(), table.getName())) {
            Expression expression = this.dataTenantHandler.getDataTenantId(false, "insert");
            if (!Objects.isNull(expression)) {
                List<Column> insertColumns = insert.getColumns();
                Iterator var5 = insertColumns.iterator();

                Column insertColumn;
                do {
                    if (!var5.hasNext()) {
                        insert.getColumns().add(new Column(this.dataTenantHandler.getDataTenantIdColumn()));
                        if (insert.getSelect() != null) {
                            this.processPlainSelect((PlainSelect)insert.getSelect().getSelectBody(), true);
                        } else {
                            if (insert.getItemsList() == null) {
                                throw ExceptionUtils.mpe("Failed to process multiple-table update, please exclude the tableName or statementId", new Object[0]);
                            }

                            ItemsList itemsList = insert.getItemsList();
                            if (itemsList instanceof MultiExpressionList) {
                                ((MultiExpressionList)itemsList).getExprList().forEach((el) -> {
                                    el.getExpressions().add(this.dataTenantHandler.getDataTenantId(false, "insert"));
                                });
                            } else {
                                ((ExpressionList)insert.getItemsList()).getExpressions().add(this.dataTenantHandler.getDataTenantId(false, "insert"));
                            }
                        }

                        return;
                    }

                    insertColumn = (Column)var5.next();
                } while(!Objects.equals(insertColumn.getColumnName(), this.dataTenantHandler.getDataTenantIdColumn()));

            }
        }
    }

    public void processUpdate(Update update) {
    }

    public void processDelete(Delete delete) {
        Table table = delete.getTable();
        if (!this.dataTenantHandler.doTableFilter(table.getSchemaName(), table.getName())) {
            Expression expression = this.dataTenantHandler.getDataTenantId(true, "where");
            if (!Objects.isNull(expression)) {
                delete.setWhere(this.andExpression(delete.getTable(), delete.getWhere()));
            }
        }
    }

    protected BinaryExpression andExpression(Table table, Expression where) {
        EqualsTo equalsTo = new EqualsTo();
        equalsTo.setLeftExpression(this.getAliasColumn(table));
        equalsTo.setRightExpression(this.dataTenantHandler.getDataTenantId(true, "where"));
        if (null != where) {
            return where instanceof OrExpression ? new AndExpression(equalsTo, new Parenthesis(where)) : new AndExpression(equalsTo, where);
        } else {
            return equalsTo;
        }
    }

    protected void processPlainSelect(PlainSelect plainSelect) {
        this.processPlainSelect(plainSelect, false);
    }

    protected void processPlainSelect(PlainSelect plainSelect, boolean addColumn) {
        FromItem fromItem = plainSelect.getFromItem();
        if (fromItem instanceof Table) {
            Table fromTable = (Table)fromItem;
            if (!this.getDataTenantHandler().doTableFilter(fromTable.getSchemaName(), fromTable.getName()) && !Objects.isNull(this.dataTenantHandler.getDataTenantId(false, "select"))) {
                plainSelect.setWhere(this.builderExpression(plainSelect.getWhere(), fromTable));
                if (addColumn) {
                    plainSelect.getSelectItems().add(new SelectExpressionItem(new Column(this.getDataTenantHandler().getDataTenantIdColumn())));
                }
            }
        } else {
            this.processFromItem(fromItem);
        }

        List<Join> joins = plainSelect.getJoins();
        if (joins != null && joins.size() > 0) {
            joins.forEach((j) -> {
                this.processJoin(j);
                this.processFromItem(j.getRightItem());
            });
        }

    }

    protected void processFromItem(FromItem fromItem) {
        if (fromItem instanceof SubJoin) {
            SubJoin subJoin = (SubJoin)fromItem;
            if (subJoin.getJoinList() != null) {
                subJoin.getJoinList().forEach(this::processJoin);
            }

            if (subJoin.getLeft() != null) {
                this.processFromItem(subJoin.getLeft());
            }
        } else if (fromItem instanceof SubSelect) {
            SubSelect subSelect = (SubSelect)fromItem;
            if (subSelect.getSelectBody() != null) {
                this.processSelectBody(subSelect.getSelectBody());
            }
        } else if (fromItem instanceof ValuesList) {
            this.logger.debug("Perform a subquery, if you do not give us feedback");
        } else if (fromItem instanceof LateralSubSelect) {
            LateralSubSelect lateralSubSelect = (LateralSubSelect)fromItem;
            if (lateralSubSelect.getSubSelect() != null) {
                SubSelect subSelect = lateralSubSelect.getSubSelect();
                if (subSelect.getSelectBody() != null) {
                    this.processSelectBody(subSelect.getSelectBody());
                }
            }
        }

    }

    protected void processJoin(Join join) {
        if (join.getRightItem() instanceof Table) {
            Table fromTable = (Table)join.getRightItem();
            if (this.dataTenantHandler.doTableFilter(fromTable.getSchemaName(), fromTable.getName()) || Objects.isNull(this.dataTenantHandler.getDataTenantId(false, "select"))) {
                return;
            }

            join.setOnExpression(this.builderExpression(join.getOnExpression(), fromTable));
        }

    }

    protected Expression builderExpression(Expression currentExpression, Table table) {
        ItemsList itemsList = this.getDataTenantHandler().getSelectDataTenantId(false, "select");
        Object appendExpression;
        if (!(itemsList instanceof SupportsOldOracleJoinSyntax)) {
            appendExpression = new InExpression();
            ((InExpression)appendExpression).setLeftExpression(this.getAliasColumn(table));
            ((InExpression)appendExpression).setRightItemsList(itemsList);
        } else {
            appendExpression = this.processTableAlias4CustomizedTenantIdExpression(new InExpression(this.getAliasColumn(table), itemsList), table);
        }

        if (currentExpression == null) {
            return (Expression)appendExpression;
        } else {
            if (currentExpression instanceof BinaryExpression) {
                BinaryExpression binaryExpression = (BinaryExpression)currentExpression;
                this.doExpression(binaryExpression.getLeftExpression());
                this.doExpression(binaryExpression.getRightExpression());
            } else if (currentExpression instanceof InExpression) {
                InExpression inExp = (InExpression)currentExpression;
                ItemsList rightItems = inExp.getRightItemsList();
                if (rightItems instanceof SubSelect) {
                    this.processSelectBody(((SubSelect)rightItems).getSelectBody());
                }
            }

            return currentExpression instanceof OrExpression ? new AndExpression(new Parenthesis(currentExpression), (Expression)appendExpression) : new AndExpression(currentExpression, (Expression)appendExpression);
        }
    }

    protected void doExpression(Expression expression) {
        if (expression instanceof FromItem) {
            this.processFromItem((FromItem)expression);
        } else if (expression instanceof InExpression) {
            InExpression inExp = (InExpression)expression;
            ItemsList rightItems = inExp.getRightItemsList();
            if (rightItems instanceof SubSelect) {
                this.processSelectBody(((SubSelect)rightItems).getSelectBody());
            }
        }

    }

    protected Expression processTableAlias4CustomizedTenantIdExpression(Expression expression, Table table) {
        return expression;
    }

    protected Column getAliasColumn(Table table) {
        StringBuilder column = new StringBuilder();
        if (null == table.getAlias()) {
            column.append(table.getName());
        } else {
            column.append(table.getAlias().getName());
        }

        column.append(".");
        column.append(this.dataTenantHandler.getDataTenantIdColumn());
        return new Column(column.toString());
    }

    public DataTenantSqlParser() {
    }

    public DataTenantHandler getDataTenantHandler() {
        return this.dataTenantHandler;
    }

    public DataTenantSqlParser setDataTenantHandler(DataTenantHandler dataTenantHandler) {
        this.dataTenantHandler = dataTenantHandler;
        return this;
    }

    public String toString() {
        return "DataTenantSqlParser(dataTenantHandler=" + this.getDataTenantHandler() + ")";
    }

    public boolean equals(Object o) {
        if (o == this) {
            return true;
        } else if (!(o instanceof DataTenantSqlParser)) {
            return false;
        } else {
            DataTenantSqlParser other = (DataTenantSqlParser)o;
            if (!other.canEqual(this)) {
                return false;
            } else if (!super.equals(o)) {
                return false;
            } else {
                Object this$dataTenantHandler = this.getDataTenantHandler();
                Object other$dataTenantHandler = other.getDataTenantHandler();
                if (this$dataTenantHandler == null) {
                    if (other$dataTenantHandler != null) {
                        return false;
                    }
                } else if (!this$dataTenantHandler.equals(other$dataTenantHandler)) {
                    return false;
                }

                return true;
            }
        }
    }

    protected boolean canEqual(Object other) {
        return other instanceof DataTenantSqlParser;
    }

    public int hashCode() {
        int PRIME = true;
        int result = super.hashCode();
        Object $dataTenantHandler = this.getDataTenantHandler();
        result = result * 59 + ($dataTenantHandler == null ? 43 : $dataTenantHandler.hashCode());
        return result;
    }
}

public class PreDataTenantHandler implements DataTenantHandler {
    private static final Logger log = LoggerFactory.getLogger(PreDataTenantHandler.class);
    @Autowired
    private DataTenantConfig dataTenantConfig;
    @Autowired
    private DataTenantHolder dataTenantHolder;

    public PreDataTenantHandler() {
    }

    public Expression getDataTenantId(boolean where, String type) {
        String dataTenantId = "";
        if ("insert".equals(type)) {
            dataTenantId = ContextUtil.getDataTenantId();
        } else {
            dataTenantId = ContextUtil.getQueryDataTenantId();
        }

        log.debug("当前租户dataTenantId为{}", dataTenantId);
        return StringUtils.isBlank(dataTenantId) ? null : new StringValue(String.format("'%s'", dataTenantId));
    }

    public ItemsList getSelectDataTenantId(boolean where, String type) {
        String dataTenantId = "";
        if ("insert".equals(type)) {
            dataTenantId = ContextUtil.getDataTenantId();
        } else {
            dataTenantId = ContextUtil.getQueryDataTenantId();
        }

        log.debug("当前租户dataTenantId为{}", dataTenantId);
        if (StringUtils.isBlank(dataTenantId)) {
            return null;
        } else {
            Set<String> deptIds = Sets.newLinkedHashSet();
            deptIds.add(dataTenantId);
            deptIds.add("global");
            ItemsList itemsList = new ExpressionList((List)deptIds.stream().map(StringValue::new).collect(Collectors.toList()));
            return itemsList;
        }
    }

    public String getDataTenantIdColumn() {
        return this.dataTenantConfig.getDataTenantIdColumn();
    }

    public boolean doTableFilter(String databaseName, String tableName) {
        if (this.dataTenantHolder.containEntityMap(databaseName, tableName) && !StringUtils.isBlank(this.dataTenantConfig.getDataTenantIdField())) {
            if (StringUtils.isNotBlank(this.dataTenantConfig.getIgnoreTable())) {
                if (StringUtils.isNotBlank(databaseName)) {
                    String fullName = databaseName + "." + tableName;
                    return Arrays.asList(this.dataTenantConfig.getIgnoreTable().split(",")).stream().anyMatch((e) -> {
                        return e.equalsIgnoreCase(fullName);
                    });
                } else {
                    return Arrays.asList(this.dataTenantConfig.getIgnoreTable().split(",")).stream().anyMatch((e) -> {
                        return e.equalsIgnoreCase(tableName);
                    });
                }
            } else {
                return false;
            }
        } else {
            return true;
        }
    }
}


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;

@RefreshScope
@Data
public class DataTenantConfig {
    private static final Logger log = LoggerFactory.getLogger(DataTenantConfig.class);
    @Value("${dataTenant.column.name:data_tenant_id}")
    private String dataTenantIdColumn;
    @Value("${dataTenant.column.field:dataTenantId}")
    private String dataTenantIdField;
    @Value("${dataTenant.column.tenantField:tenantId}")
    private String tenantIdField;
    @Value("${dataTenant.column.tenantName:tenant_id}")
    private String tenantIdColumn;
    @Value("${dataTenant.table.ignore:}")
    private String ignoreTable;
    @Value("${dataTenant.table.tenantIgnore:}")
    private String tenantIgnoreTable;
    @Value("${dataTenant.table.package:}")
    private String modelPackage;
    @Value("${dataTenant.mapper.use:}")
    private String scanMapper;
@Configuration
@ConditionalOnProperty(
    name = {"boot.tenant.enable"},
    havingValue = "true"
)
public class MybatisTenantAutoConfigure {
    private static final Logger log = LoggerFactory.getLogger(MybatisTenantAutoConfigure.class);
    @Value("${spring.profiles.active}")
    private String env;

    public MybatisTenantAutoConfigure() {
    }

    @Bean
    @ConditionalOnMissingBean({PaginationInterceptor.class})
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        return paginationInterceptor;
    }

    @Bean
    @ConditionalOnMissingBean({DataTenantSqlParser.class})
    public DataTenantSqlParser dataTenantSqlParser(PaginationInterceptor paginationInterceptor, PreDataTenantHandler preDataTenantHandler) {
        List<ISqlParser> sqlParserList = paginationInterceptor.getSqlParserList();
        if (sqlParserList == null) {
            sqlParserList = new ArrayList();
        }

        if (!Objects.isNull(this.env) && !this.env.contains("dev")) {
            ((List)sqlParserList).add(new BlockAttackSqlParser());
        }

        DataTenantSqlParser tenantSqlParser = new DataTenantSqlParser();
        tenantSqlParser.setDataTenantHandler(preDataTenantHandler);
        ((List)sqlParserList).add(tenantSqlParser);
        paginationInterceptor.setSqlParserList((List)sqlParserList);
        return tenantSqlParser;
    }

    @Bean
    @ConditionalOnMissingBean({DataTenantHolder.class})
    public DataTenantHolder dataTenantHolder(DataTenantConfig dataTenantConfig) {
        EntityDataTenantHolder entityDataTenantHolder = new EntityDataTenantHolder();
        return entityDataTenantHolder;
    }

    @Bean
    @ConditionalOnProperty(
        name = {"boot.tenant.useTenantId"},
        havingValue = "true"
    )
    @ConditionalOnMissingBean({FactorTenantSqlParser.class})
    public FactorTenantSqlParser factorTenantSqlParser(PaginationInterceptor paginationInterceptor, PreTenantHandler preTenantHandler) {
        List<ISqlParser> sqlParserList = paginationInterceptor.getSqlParserList();
        if (sqlParserList == null) {
            sqlParserList = new ArrayList();
        }

        if (!Objects.isNull(this.env) && !this.env.contains("dev")) {
            ((List)sqlParserList).add(new BlockAttackSqlParser());
        }

        FactorTenantSqlParser tenantSqlParser = new FactorTenantSqlParser();
        tenantSqlParser.setDataTenantHandler(preTenantHandler);
        ((List)sqlParserList).add(tenantSqlParser);
        paginationInterceptor.setSqlParserList((List)sqlParserList);
        return tenantSqlParser;
    }

    @Bean
    public PreDataTenantHandler preDataTenantHandler() {
        return new PreDataTenantHandler();
    }

    @Bean
    public PreTenantHandler preTenantHandler() {
        return new PreTenantHandler();
    }

    @Bean
    public DataTenantConfig dataTenantConfig() {
        return new DataTenantConfig();
    }

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容