MyBatis拦截器怎么动态替换表名
发表于:2024-11-17 作者:千家信息网编辑
千家信息网最后更新 2024年11月17日,本篇内容主要讲解"MyBatis拦截器怎么动态替换表名",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"MyBatis拦截器怎么动态替换表名"吧!一、Myba
千家信息网最后更新 2024年11月17日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.*;/** * @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 MapTABLE_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 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拦截器怎么动态替换表名"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
对象
方法
参数
语句
拦截器
变量
动态
实际
生成
业务
接口
逻辑
代理
内容
就是
成员
时候
注解
结构
学习
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
数据库中记录之间的相互关系
办公网络技术与维护运行
外派软件开发员怎么样
网络技术的英文单词
阿里云邮箱服务器SMTP
全球6大网络安全事件
光遇自动跑图服务器
海康软件开发工程师
wp系统软件开发
网络安全监测不包括
服务器硬件内存有多大
游戏服务器备份时会断网吗
后台密码跟数据库无法匹配
mysql数据库面试代码题
为啥会发生数据库锁表
常用数据库访问中间件
数据库使用count的例题
数据库表头怎么加
js点击清除数据库
游戏服务器什么时候才会开服
数据库题 答案
青少年该怎样做到网络安全
免费的网络技术学习
数据库主要数据源
苗木数据库
香港启荣电子软件开发有限公司
渭南市国家网络安全宣传周启动
投诉赛茂雅网络技术有限公司
车载网络技术有哪些作用
数据库未来教育题库