All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.jeesuite.mybatis.plugin.dataprofile.DataProfileHandler Maven / Gradle / Ivy
package com.jeesuite.mybatis.plugin.dataprofile;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jeesuite.common.model.Page;
import com.jeesuite.common.util.ResourceUtils;
import com.jeesuite.mybatis.MybatisRuntimeContext;
import com.jeesuite.mybatis.core.InterceptorHandler;
import com.jeesuite.mybatis.parser.EntityInfo;
import com.jeesuite.mybatis.parser.EntityInfo.MapperMethod;
import com.jeesuite.mybatis.parser.MybatisMapperParser;
import com.jeesuite.mybatis.plugin.InvocationVals;
import com.jeesuite.mybatis.plugin.JeesuiteMybatisInterceptor;
import com.jeesuite.mybatis.plugin.dataprofile.annotation.DataProfileIgnore;
import com.jeesuite.mybatis.plugin.pagination.PaginationHandler;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
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.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.Join;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
/**
* 数据权限mybatis层拦截处理器
* Class Name : DataProfileHandler
*
* @author jiangwei
* @version 1.0.0
* @date 2019年10月28日
*/
public class DataProfileHandler implements InterceptorHandler {
private final static Logger logger = LoggerFactory.getLogger("com.jeesuite.mybatis.plugin.dataprofile");
public static final String NAME = "dataProfile";
private Set includeMapperIds = new HashSet<>();
private List excludeMapperIds = new ArrayList<>();
private Map> dataProfileMappings = new HashMap<>();
private boolean pageScope;
@Override
public void start(JeesuiteMybatisInterceptor context) {
Properties properties = ResourceUtils.getAllProperties("jeesuite.mybatis.dataProfile.mappings");
properties.forEach( (k,v) -> {
String tableName = k.toString().substring(k.toString().indexOf("[") + 1).replace("]", "").trim();
buildTableDataProfileMapping(tableName, v.toString());
} );
if(dataProfileMappings.isEmpty()) {
logger.warn("[jeesuite.mybatis.dataProfile.mappings] NOT FOUND");
return;
}
pageScope = ResourceUtils.getBoolean("jeesuite.mybatis.dataProfile.pageScope");
Set tableNames = dataProfileMappings.keySet();
List entityInfos = MybatisMapperParser.getEntityInfos(context.getGroupName());
includeMapperIds = new HashSet<>(ResourceUtils.getList("jeesuite.mybatis.dataProfile.includeMapperIds"));
//未指定就解析sql
if(includeMapperIds.isEmpty()) {
for (EntityInfo entityInfo : entityInfos) {
entityInfo.getMapperSqls().forEach( (k,v) -> {
for (String tableName : tableNames) {
if(v.contains(tableName)) {
includeMapperIds.add(k);
}
}
} );
}
}
//
Collection mapperMethods;
for (EntityInfo entityInfo : entityInfos) {
mapperMethods = entityInfo.getMapperMethods().values();
for (MapperMethod mapperMethod : mapperMethods) {
if(mapperMethod.getMethod().isAnnotationPresent(DataProfileIgnore.class)){
excludeMapperIds.add(mapperMethod.getFullName());
}
}
}
List list = ResourceUtils.getList("jeesuite.mybatis.dataProfile.excludeMapperIds");
if(!list.isEmpty()) {
excludeMapperIds.addAll(list);
}
logger.info("dataProfileMappings >> {}",dataProfileMappings);
}
@Override
public Object onInterceptor(InvocationVals invocation) throws Throwable {
if(!invocation.isSelect())return null;
//
final MappedStatement mappedStatement = invocation.getMappedStatement();
if(MybatisRuntimeContext.isTransactionalOn())return null;
if(MybatisRuntimeContext.isDataProfileIgnore())return null;
boolean isPageQuery = invocation.getPageParam() != null || PaginationHandler.pageMappedStatements.containsKey(mappedStatement.getId());
if(pageScope && !isPageQuery) return null;
if(!includeMapperIds.contains(mappedStatement.getId()))return null;
if(excludeMapperIds.contains(mappedStatement.getId()))return null;
Map dataMappings = MybatisRuntimeContext.getDataProfileMappings();
if(dataMappings == null)return null;
final Executor executor = invocation.getExecutor();
final Object[] args = invocation.getArgs();
BoundSql boundSql = invocation.getBoundSql();
String newSql = buildDataProfileSql(mappedStatement.getId(),invocation.getSql(),dataMappings);
//直接返回
if(newSql == null) {
List list = new ArrayList<>(1);
//
EntityInfo entityInfo = MybatisMapperParser.getEntityInfoByMapper(invocation.getMapperNameSpace());
String methodName = mappedStatement.getId().replace(invocation.getMapperNameSpace(), StringUtils.EMPTY).substring(1);
Class> returnType = entityInfo.getMapperMethod(methodName).getMethod().getReturnType();
if(returnType == int.class || returnType == Integer.class|| returnType == long.class|| returnType == Long.class) {
list.add(0);
}else if(invocation.getPageParam() != null) {
list.add(new Page(invocation.getPageParam(),0,null));
}
return list;
}
//
// if(invocation.getParameter() instanceof UserContextQueryParam) {
// ((UserContextQueryParam)invocation.getParameter()).setDataProfileValues(dataMappings);
// }
//如果是分页查询,直接返回重写后的sql,有分页查询处理查询逻辑
if(isPageQuery) {
invocation.setSql(newSql);
return null;
}
final ResultHandler> resultHandler = (ResultHandler>) args[3];
BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(), newSql,boundSql.getParameterMappings(), invocation.getParameter());
//newBoundSql.setAdditionalParameter("dataProfileValues", dataMappings);
CacheKey cacheKey = executor.createCacheKey(mappedStatement, invocation.getParameter(), RowBounds.DEFAULT, newBoundSql);
List> resultList = executor.query(mappedStatement, invocation.getParameter(), RowBounds.DEFAULT, resultHandler, cacheKey,newBoundSql);
return resultList;
}
/**
* @param mappedStatementId
* @param orignSql
* @param dataMappings
* @return
*/
private String buildDataProfileSql(String mappedStatementId,String orignSql, Map dataMapping) {
Select select = null;
try {
select = (Select) CCJSqlParserUtil.parse(orignSql);
} catch (JSQLParserException e) {
logger.error("rebuildDataProfileSql_ERROR",e);
throw new RuntimeException("sql解析错误");
}
PlainSelect selectBody = (PlainSelect) select.getSelectBody();
Table table = (Table) selectBody.getFromItem();
Map columnMapping;
Set fieldNames;
Expression newExpression = null;
String[] values;
if(dataProfileMappings.containsKey(table.getName())) {
columnMapping = dataProfileMappings.get(table.getName());
fieldNames = columnMapping.keySet();
for (String fieldName : fieldNames) {
if(!dataMapping.containsKey(fieldName))continue;
values = dataMapping.get(fieldName);
//如果某个匹配字段为空直接返回null,不在查询数据库
if(values == null || values.length == 0) {
return null;
}
newExpression = appendDataProfileCondition(table, selectBody.getWhere(), columnMapping.get(fieldName),values);
selectBody.setWhere(newExpression);
//TODO 主表已经处理的条件,join表不在处理
}
}
//JOIN
List joins = selectBody.getJoins();
if(joins != null){
for (Join join : joins) {
table = (Table) join.getRightItem();
if(dataProfileMappings.containsKey(table.getName())) {
columnMapping = dataProfileMappings.get(table.getName());
fieldNames = columnMapping.keySet();
for (String fieldName : fieldNames) {
if(!dataMapping.containsKey(fieldName))continue;
values = dataMapping.get(fieldName);
//如果某个匹配字段为空直接返回null,不在查询数据库
if(values == null || values.length == 0) {
return null;
}
//左右连接加在ON 无法过滤
newExpression = appendDataProfileCondition(table, selectBody.getWhere(), columnMapping.get(fieldName),values);
selectBody.setWhere(newExpression);
}
}
}
}
//
String newSql = selectBody.toString();
return newSql;
}
private static Expression appendDataProfileCondition(Table table,Expression orginExpression,String columnName,String[] values){
Expression newExpression = null;
Column column = new Column(table, columnName);
if (values.length == 1) {
EqualsTo equalsTo = new EqualsTo();
equalsTo.setLeftExpression(column);
equalsTo.setRightExpression(new StringValue(values[0]));
newExpression = orginExpression == null ? equalsTo : new AndExpression(orginExpression, equalsTo);
} else {
ExpressionList expressionList = new ExpressionList(new ArrayList<>(values.length));
for (String value : values) {
expressionList.getExpressions().add(new StringValue(value));
}
InExpression inExpression = new InExpression(column, expressionList);
newExpression = orginExpression == null ? inExpression : new AndExpression(orginExpression,inExpression);
}
return newExpression;
}
private void buildTableDataProfileMapping(String tableName,String ruleString) {
dataProfileMappings.put(tableName, new HashMap<>());
String[] rules = ruleString.split(",|;");
String[] tmpArr;
for (String rule : rules) {
tmpArr = rule.split(":");
String columnName = tmpArr.length == 2 ? tmpArr[1] : rule;
dataProfileMappings.get(tableName).put(tmpArr[0], columnName);
}
}
@Override
public void onFinished(InvocationVals invocation, Object result) {
}
@Override
public int interceptorOrder() {
//需要在分页前执行
return 2;
}
@Override
public void close() {
}
}