1.引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
2.使用注解
@Slf4j
@Component
@Intercepts(
{@Signature(
type = StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)})
public class DataScopePlusInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler target = (StatementHandler) invocation.getTarget();
//未经过包装的sql
String sql = target.getBoundSql().getSql();
log.info("DataScopePlusInterceptor");
return invocation.proceed();
}
}
3.@Signature注解
-
@Intercepts注解有一个参数就是@Signature,可以填写多个Signature
-
这个注解有三个参数
public @interface Signature { /** * Returns the java type. * * @return the java type */ Class<?> type(); /** * Returns the method name. * * @return the method name */ String method(); /** * Returns java types for method argument. * @return java types for method argument */ Class<?>[] args(); }
-
type:就是指定拦截器类型
-
method:是拦截器类型中的方法
-
args:是拦截器类型中的方法的参数(不是自己写的)
3.1.type
3.2.method
-
这个方法就看你选用那个type拦截器,比如你选了StatementHandler ,点进去这个类,这个类的方法名就是你要拦截的,假如你选了prepare,就在method填写
type="prepare"
-
每一个方法都能见名知意,比如query就是执行查询时会触发拦截调用的方法
public interface StatementHandler { Statement prepare(Connection connection, Integer transactionTimeout) throws SQLException; void parameterize(Statement statement) throws SQLException; void batch(Statement statement) throws SQLException; int update(Statement statement) throws SQLException; <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException; <E> Cursor<E> queryCursor(Statement statement) throws SQLException; BoundSql getBoundSql(); ParameterHandler getParameterHandler(); }
3.3.args
- 这个就是选用的方法,所需的参数,例如上面我选了
type="prepare"
,那么看接口所需的方法参数,填写args = {Connection.class, Integer.class}
4.自定义SQL,拼接到拦截的SQL中并执行
/**
* sql拦截器
* @author xxl
* @since 2023/8/31
*/
@Component
@Intercepts(@Signature(
type = StatementHandler.class,
method = "query",
args = {Statement.class, ResultHandler.class}
))
@Slf4j
public class DataScopePlusInterceptor implements Interceptor {
@Resource
Wrapper wrapper;
@Override
public Object intercept(Invocation invocation) throws Throwable {
//获取执行sql的类信息
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
MetaObject metaObject = MetaObject.forObject(statementHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY,
new DefaultReflectorFactory());
MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
BoundSql boundSql = statementHandler.getBoundSql();
//自定义b
String sql = wrapper.createSql(boundSql.getSql(), mappedStatement);
//如果原SQL没变就不用反射
if (!boundSql.getSql().equals(sql)) {
//通过反射设置新值
Field declaredField = boundSql.getClass().getDeclaredField("sql");
declaredField.setAccessible(true);
declaredField.set(boundSql, sql);
}
return invocation.proceed();
}
}
接口
/**
* @author: xxl
* @since: 2023/9/4
* @description: 包装器修改权限的基础接口,自定义数据源皆要基于此接口
*/
public interface Wrapper {
/**
*
* @param sql 原sql
* @param mappedStatement 原sql执行类信息
* @return 新sql
*/
String createSql(String sql, MappedStatement mappedStatement);
}
实现接口类
/**
* @author: xxl
* @since: 2023/9/4
* @description: 可以在如下写逻辑
*/
@Component
@Slf4j
public class JinZhiWrapper implements Wrapper {
@Override
public String createSql(String sql, MappedStatement mappedStatement) {
log.info("JinZhiWrapper");
return sql;
}
}