MyBatis拦截器怎么动态替换表名
本篇内容主要讲解“MyBatis拦截器怎么动态替换表名”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“MyBatis拦截器怎么动态替换表名”吧!
一、Mybatis Interceptor 拦截器接口和注解
简单的说就是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.*;//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) { } private boolean isReplaceTableName(String sql){ for(String tableName : TABLE_MAP.keySet()){ if(sql.contains(tableName)){ return true; } } return false; } 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(); } 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拦截器怎么动态替换表名”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341