MyBatis拦截器怎么动态替换表名
发表于:2025-01-19 作者:千家信息网编辑
千家信息网最后更新 2025年01月19日,本篇内容主要讲解"MyBatis拦截器怎么动态替换表名",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"MyBatis拦截器怎么动态替换表名"吧!一、Myba
千家信息网最后更新 2025年01月19日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安全错误
数据库的锁怎样保障安全
安徽软件开发解决方案定制
网络安全论文模板素材
河北pdu服务器电源厂家报价
软件开发与软件管理的关系
隔离网络安全风险
凤凰网络安全技术论坛
该软件开发适于采用什么过程
用ensp配置dhcp服务器
广讯通网络技术
电信卡5g服务器设置
sci数据库不能导出
数据库中标量函数又返回值的
服务器时间攻击
软件开发实习生好找工作吗
数据库技术与应用复习重点
电力网络安全数据挖掘
服务器cpu与内存的搭配
电力行业网络安全十四五行动计划
我的世界服务器怎么看礼包名称
服务器装家里
腾讯云服务器更改账号密码错误
凤凰网络安全技术论坛
asp中cs用访问数据库
服务器口令管理
软件开发后端是什么
手机提示服务器出错怎么回事
软件开发属于cs还是bs
建议不要改变服务器的
白泽网络安全员
建设网络安全环境