本篇内容主要讲解“MyBatis拦截器怎么动态替换表名”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MyBatis拦截器怎么动态替换表名”吧!
简单的说就是mybatis在执行sql的时候,拦截目标方法并且在前后加上我们的业务逻辑。实际上就是加@Intercepts注解和实现org.apache.ibatis.plugin.Interceptor
接口
@Intercepts(
@Signature(method = "query",
type = Executor.class,
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
)
)
public interface Interceptor {
//主要重写这个方法、实现我们的业务逻辑
Object intercept(Invocation invocation) throws Throwable;
//生成代理对象,可以在这里判断是否生成代理对象
Object plugin(Object target);
//如果我们拦截器需要用到一些变量参数,可以在这里读取
void setProperties(Properties properties);
}
在intercept方法中有参数Invocation对象,里面有3个成员变量和@Signature对应
成员变量 | 变量类型 | 说明 |
---|---|---|
target | Object | 代理对象 |
method | Method | 被拦截方法 |
args | Object[] | 被拦截方法执行所需的参数 |
通过Invocation中的args变量。我们能拿到MappedStatement这个对象(args[0]),传入sql语句的参数Object(args[1])。而MappedStatement是一个记录了sql语句(sqlSource对象)、参数值结构、返回值结构、mapper配置等的一个对象。
sqlSource对象和传入sql语句的参数对象Object就能获得BoundSql。BoundSql的toString方法就能获取到有占位符的sql语句了,我们的业务逻辑就能在这里介入。
获取到sql语句,根据规则替换表名,塞回BoundSql对象中、再把BoundSql对象塞回MappedStatement对象中。最后再赋值给args[0](实际被拦截方法所需的参数)就搞定了
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.*;
/**
* @description: 动态替换表名拦截器
* @author: hinotoyk
* @created: 2022/04/19
*/
//method = "query"拦截select方法、而method = "update"则能拦截insert、update、delete的方法
@Intercepts({
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class ReplaceTableInterceptor implements Interceptor {
private final static Map<String,String> TABLE_MAP = new LinkedHashMap<>();
static {
//表名长的放前面,避免字符串匹配的时候先匹配替换子集
TABLE_MAP.put("t_game_partners","t_game_partners_test");//测试
TABLE_MAP.put("t_file_recycle","t_file_recycle_other");
TABLE_MAP.put("t_folder","t_folder_other");
TABLE_MAP.put("t_file","t_file_other");
}
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
//获取MappedStatement对象
MappedStatement ms = (MappedStatement) args[0];
//获取传入sql语句的参数对象
Object parameterObject = args[1];
BoundSql boundSql = ms.getBoundSql(parameterObject);
//获取到拥有占位符的sql语句
String sql = boundSql.getSql();
System.out.println("拦截前sql :" + sql);
//判断是否需要替换表名
if(isReplaceTableName(sql)){
for(Map.Entry<String, String> entry : TABLE_MAP.entrySet()){
sql = sql.replace(entry.getKey(),entry.getValue());
}
System.out.println("拦截后sql :" + sql);
//重新生成一个BoundSql对象
BoundSql bs = new BoundSql(ms.getConfiguration(),sql,boundSql.getParameterMappings(),parameterObject);
//重新生成一个MappedStatement对象
MappedStatement newMs = copyMappedStatement(ms, new BoundSqlSqlSource(bs));
//赋回给实际执行方法所需的参数中
args[0] = newMs;
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
/***
* 判断是否需要替换表名
* @param sql
* @return
*/
private boolean isReplaceTableName(String sql){
for(String tableName : TABLE_MAP.keySet()){
if(sql.contains(tableName)){
return true;
}
}
return false;
}
/***
* 复制一个新的MappedStatement
* @param ms
* @param newSqlSource
* @return
*/
private MappedStatement copyMappedStatement (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(String.join(",",ms.getKeyProperties()));
}
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();
}
/***
* MappedStatement构造器接受的是SqlSource
* 实现SqlSource接口,将BoundSql封装进去
*/
public static class BoundSqlSqlSource implements SqlSource {
private BoundSql boundSql;
public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}
@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}
}
到此,相信大家对“MyBatis拦截器怎么动态替换表名”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。