Commit 921d75cc by hy

集成mybatis模块

parent ae1f8630
......@@ -18,6 +18,10 @@
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis-plus.version}</version>
......
package cn.datax.common.mybatis.annotation;
import java.lang.annotation.*;
/**
* 数据权限过滤注解
* 参考 https://gitee.com/cancerGit/Crown
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataScopeAop {
/**
* 表的别名
*/
String alias() default "sys_user";
/**
* 表的部门字段
*/
String deptScopeName() default "create_dept";
/**
* 表的用户字段
*/
String userScopeName() default "create_by";
}
package cn.datax.common.mybatis.aspectj;
import java.lang.reflect.Method;
import java.util.List;
import cn.datax.common.base.BaseQueryParams;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.DataRole;
import cn.datax.common.core.DataUser;
import cn.datax.common.mybatis.annotation.DataScopeAop;
import cn.datax.common.utils.SecurityUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
/**
* 数据过滤处理(基于注解式,用于自定义sql)
*/
@Slf4j
@Aspect
public class DataScopeAspect {
// 配置织入点
@Pointcut("@annotation(cn.datax.common.mybatis.annotation.DataScopeAop)")
public void dataScopePointCut() {
}
@Before("dataScopePointCut()")
public void doBefore(JoinPoint point) {
handleDataScope(point);
}
protected void handleDataScope(final JoinPoint joinPoint) {
// 获得注解
DataScopeAop dataScope = getAnnotationLog(joinPoint);
if (dataScope == null) {
return;
}
DataUser currentUser = SecurityUtil.getDataUser();
if (null != currentUser) {
// 如果是超级管理员,则不过滤数据
if (!currentUser.isAdmin()) {
dataScopeFilter(joinPoint, currentUser, dataScope);
}
}
}
/**
* 数据范围过滤
*
* @param user
* @param dataScope
*/
private void dataScopeFilter(JoinPoint joinPoint, DataUser user, DataScopeAop dataScope) {
StringBuilder sqlString = new StringBuilder();
List<DataRole> roles = user.getRoles();
if (CollUtil.isNotEmpty(roles)){
for (DataRole role : roles){
String roleDataScope = role.getDataScope();
if (DataConstant.DataScope.ALL.getKey().equals(roleDataScope)) {
sqlString = new StringBuilder();
break;
} else if (DataConstant.DataScope.CUSTOM.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {}.{} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) "
,dataScope.alias()
,dataScope.deptScopeName()
,"'" + role.getId() + "'"
));
} else if (DataConstant.DataScope.DEPT.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {}.{} = {} "
,dataScope.alias()
,dataScope.deptScopeName()
,"'" + user.getDept() + "'"
));
} else if (DataConstant.DataScope.DEPTANDCHILD.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {}.{} IN ( SELECT descendant FROM sys_dept_relation WHERE ancestor = {} )"
,dataScope.alias()
,dataScope.deptScopeName()
,"'" + user.getDept() + "'"
));
} else if (DataConstant.DataScope.SELF.getKey().equals(roleDataScope)) {
if (StrUtil.isNotBlank(dataScope.alias())) {
sqlString.append(StrUtil.format(" OR {}.{} = {} "
,dataScope.alias()
,dataScope.userScopeName()
,user.getId()));
} else {
// 数据权限为仅本人且没有alias别名不查询任何数据
sqlString.append(" OR 1=0 ");
}
}
}
}
if (StrUtil.isNotBlank(sqlString.toString())) {
BaseQueryParams baseQueryParams = (BaseQueryParams) joinPoint.getArgs()[0];
baseQueryParams.setDataScope(" AND (" + sqlString.substring(4) + ")");
}
log.info("数据范围过滤:{}", sqlString);
}
/**
* 是否存在注解,如果存在就获取
*/
private DataScopeAop getAnnotationLog(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
if (method != null) {
return method.getAnnotation(DataScopeAop.class);
}
return null;
}
}
package cn.datax.common.mybatis.config;
import cn.datax.common.mybatis.aspectj.DataScopeAspect;
import cn.datax.common.mybatis.injector.DataLogicSqlInjector;
import cn.datax.common.mybatis.interceptor.DataScopeInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@MapperScan("cn.datax.service.**.dao")
@EnableTransactionManagement
public class DataBatisPlusConfig {
/**
* 分页插件
*
* @return PaginationInterceptor
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
/**
* 数据权限插件
*
* @return DataScopeInterceptor
*/
@Bean
public DataScopeInterceptor dataScopeInterceptor() {
return new DataScopeInterceptor();
}
/**
* 数据过滤处理(基于注解式)
*
* @return dataScopeAspect
*/
@Bean
public DataScopeAspect dataScopeAspect() {
return new DataScopeAspect();
}
/**
* 自定义 SqlInjector
* 里面包含自定义的全局方法
*/
@Bean
public DataLogicSqlInjector myLogicSqlInjector() {
return new DataLogicSqlInjector();
}
@Bean
public DataMetaObjectHandler dataMetaObjectHandler() {
return new DataMetaObjectHandler();
}
}
package cn.datax.common.mybatis.config;
import cn.datax.common.core.DataConstant;
import cn.datax.common.utils.SecurityUtil;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import java.time.LocalDateTime;
public class DataMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "status", String.class, DataConstant.EnableState.ENABLE.getKey());
this.strictInsertFill(metaObject, "createBy", String.class, SecurityUtil.getUserId());
this.strictInsertFill(metaObject, "updateBy", String.class, SecurityUtil.getUserId());
boolean bolCreateDept = metaObject.hasSetter("createDept");
if (bolCreateDept) {
this.strictInsertFill(metaObject, "createDept", String.class, SecurityUtil.getUserDeptId());
}
boolean bolFlowStatus = metaObject.hasSetter("flowStatus");
if (bolFlowStatus) {
this.strictInsertFill(metaObject, "flowStatus", String.class, DataConstant.AuditState.WAIT.getKey());
}
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
this.strictUpdateFill(metaObject, "updateBy", String.class, SecurityUtil.getUserId());
}
}
package cn.datax.common.mybatis.injector;
import cn.datax.common.mybatis.injector.methods.SelectListDataScope;
import cn.datax.common.mybatis.injector.methods.SelectPageDataScope;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import java.util.List;
/**
* 自定义 SqlInjector
*/
public class DataLogicSqlInjector extends DefaultSqlInjector {
/**
* 如果只需增加方法,保留MP自带方法
* 可以super.getMethodList() 再add
* @return
*/
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass);
methodList.add(new SelectListDataScope());
methodList.add(new SelectPageDataScope());
return methodList;
}
}
package cn.datax.common.mybatis.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectListDataScope extends AbstractMethod {
public SelectListDataScope() {
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.SELECT_LIST;
String sql = String.format(sqlMethod.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlComment());
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, "selectListDataScope", sqlSource, tableInfo);
}
}
package cn.datax.common.mybatis.injector.methods;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectPageDataScope extends AbstractMethod {
public SelectPageDataScope() {
}
@Override
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
SqlMethod sqlMethod = SqlMethod.SELECT_PAGE;
String sql = String.format(sqlMethod.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlComment());
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, "selectPageDataScope", sqlSource, tableInfo);
}
}
package cn.datax.common.mybatis.interceptor;
import cn.datax.common.base.DataScope;
import cn.datax.common.core.DataConstant;
import cn.datax.common.core.DataRole;
import cn.datax.common.core.DataUser;
import cn.datax.common.utils.SecurityUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.handlers.AbstractSqlParserHandler;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import java.sql.Connection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* mybatis 数据权限拦截器
*/
@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})})
public class DataScopeInterceptor extends AbstractSqlParserHandler implements Interceptor {
@Override
@SneakyThrows
public Object intercept(Invocation invocation) {
StatementHandler statementHandler = (StatementHandler) PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
this.sqlParser(metaObject);
// 先判断是不是SELECT操作
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) {
return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
String originalSql = boundSql.getSql();
Object parameterObject = boundSql.getParameterObject();
//查找参数中包含DataScope类型的参数
DataScope dataScope = findDataScopeObject(parameterObject);
if (dataScope != null) {
// 获取当前的用户
DataUser currentUser = SecurityUtil.getDataUser();
if (null != currentUser) {
// 如果是超级管理员,则不过滤数据
if (!currentUser.isAdmin()) {
String sqlString = dataScopeFilter(currentUser, dataScope);
if (StrUtil.isNotBlank(sqlString)) {
originalSql = "SELECT * FROM (" + originalSql + ") TEMP_DATA_SCOPE WHERE 1=1 AND (" + sqlString.substring(4) + ")";
metaObject.setValue("delegate.boundSql.sql", originalSql);
}
}
}
}
return invocation.proceed();
}
/**
* 数据范围过滤
*
* @param user
* @param dataScope
*/
private String dataScopeFilter(DataUser user, DataScope dataScope) {
StringBuilder sqlString = new StringBuilder();
List<DataRole> roles = user.getRoles();
if (CollUtil.isNotEmpty(roles)){
for (DataRole role : roles){
String roleDataScope = role.getDataScope();
if (DataConstant.DataScope.ALL.getKey().equals(roleDataScope)) {
sqlString = new StringBuilder();
break;
} else if (DataConstant.DataScope.CUSTOM.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {} IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) "
,dataScope.getDeptScopeName()
,"'" + role.getId() + "'"
));
} else if (DataConstant.DataScope.DEPT.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {} = {} "
,dataScope.getDeptScopeName()
,"'" + user.getDept() + "'"
));
} else if (DataConstant.DataScope.DEPTANDCHILD.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(
" OR {} IN ( SELECT descendant FROM sys_dept_relation WHERE ancestor = {} )"
,dataScope.getDeptScopeName()
,"'" + user.getDept() + "'"
));
} else if (DataConstant.DataScope.SELF.getKey().equals(roleDataScope)) {
sqlString.append(StrUtil.format(" OR {} = {} "
,dataScope.getUserScopeName()
,"'" + user.getId() + "'"
));
}
}
}
log.info("数据范围过滤:{}", sqlString);
return sqlString.toString();
}
/**
* 生成拦截对象的代理
*
* @param target 目标对象
* @return 代理对象
*/
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
/**
* mybatis配置的属性
*
* @param properties mybatis配置的属性
*/
@Override
public void setProperties(Properties properties) {
}
/**
* 查找参数是否包括DataScope对象
*
* @param parameterObj 参数列表
* @return DataScope
*/
private DataScope findDataScopeObject(Object parameterObj) {
if (parameterObj instanceof DataScope) {
return (DataScope) parameterObj;
} else if (parameterObj instanceof Map) {
for (Object val : ((Map<?, ?>) parameterObj).values()) {
if (val instanceof DataScope) {
return (DataScope) val;
}
}
}
return null;
}
}
......@@ -4,4 +4,5 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.datax.common.exception.GlobalExceptionHandler,\
cn.datax.common.utils.SpringContextHolder,\
cn.datax.common.database.datasource.CacheDataSourceFactoryBean,\
cn.datax.common.redis.config.RedisConfig
cn.datax.common.redis.config.RedisConfig,\
cn.datax.common.mybatis.config.DataBatisPlusConfig
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment