IT-迁哥
发布于 2024-01-29 / 115 阅读
17
0

mybatis数据权限插件

mybatis数据权限自定义插件,在开发的过程中,我们常常会遇到在sql后面加上固定条件,尤其是租户的时候,这个时候我们又想动态的加上租户条件,这时候数据权限插件应运而生。

实现原理是注解加上mybatis插件,插件扫描xx方法是否包含xx注解,包含就进行sql拼接,拼接sql要注意语法问题,插件在xml的动态sql后执行。

1.DataScope注解

/**
 * 数据权限注解
 *
 * @author glq
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataScope {
    String tableAlis() default "";
}

2.DataScopeInterceptor数据权限插件

/**
 * @author glq
 **/
@Intercepts
        ({
                @Signature(type = Executor.class,
                        method = "query",
                        args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
                )
        })

public class DataScopeInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        System.out.println(invocation.getMethod().getName());
        Object[] queryArgs = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) queryArgs[0];
        BoundSql boundSql = mappedStatement.getBoundSql(queryArgs[1]);
        String queryId = mappedStatement.getId();
        int index = queryId.lastIndexOf(".");
        String className = queryId.substring(0, index);
        String methodName = queryId.substring(index + 1);
        System.out.println(queryId);
        Class clazz = Class.forName(className);
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                DataScope dataScope = AnnotationUtil.getAnnotation(method, DataScope.class);
                if (dataScope != null) {
                    System.err.println("拦截到指定方法");
                    //测试组装sql
                    StringBuilder builder = new StringBuilder(boundSql.getSql());
                    builder.append(" 1=1");
                    // 重新new一个查询语句对象
                    BoundSql newBoundSql = new BoundSql(mappedStatement.getConfiguration(),builder.toString(),
                            boundSql.getParameterMappings(), boundSql.getParameterObject());
                    // 把新的查询放到statement里
                    MappedStatement newMs = newMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql));
                    for (ParameterMapping mapping : boundSql.getParameterMappings()) {
                        String prop = mapping.getProperty();
                        if (boundSql.hasAdditionalParameter(prop)) {
                            newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop));
                        }
                    }
                    queryArgs[0] = newMs;
                    return invocation.proceed();

                }

            }
        }

        return invocation.proceed();

    }

    /**
     * 定义一个内部辅助类,作用是包装 SQL
     */
    class BoundSqlSqlSource implements SqlSource {
        private BoundSql boundSql;

        public BoundSqlSqlSource(BoundSql boundSql) {
            this.boundSql = boundSql;
        }

        @Override
        public BoundSql getBoundSql(Object parameterObject) {
            return boundSql;
        }

    }

    private MappedStatement newMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
        MappedStatement.Builder builder = new
                MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
        builder.resource(ms.getResource());
        builder.fetchSize(ms.getFetchSize());
        builder.statementType(ms.getStatementType());
        builder.keyGenerator(ms.getKeyGenerator());
        if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
            builder.keyProperty(ms.getKeyProperties()[0]);
        }
        builder.timeout(ms.getTimeout());
        builder.parameterMap(ms.getParameterMap());
        builder.resultMaps(ms.getResultMaps());
        builder.resultSetType(ms.getResultSetType());
        builder.cache(ms.getCache());
        builder.flushCacheRequired(ms.isFlushCacheRequired());
        builder.useCache(ms.isUseCache());
        return builder.build();
    }


}

最后别忘了把插件注入spring容器!


评论