Springboot的Mybatis拦截器实现[通俗易懂]

Springboot的Mybatis拦截器实现[通俗易懂]MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,其实就是拦截器功能MyBatis允许拦截的接口MyBatis允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis允许使用插件来拦截的方法调用包括:Executor(update,query,fl…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,其实就是拦截器功能

MyBatis 允许拦截的接口

MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:

  1. Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  2. ParameterHandler (getParameterObject, setParameters)
  3. ResultSetHandler (handleResultSets, handleOutputParameters)
  4. StatementHandler (prepare, parameterize, batch, update, query)

Executor接口的部分方法,比如update,query,commit,rollback等方法,还有其他接口的一些方法等。

总体概括为:

  1. 拦截执行器的方法
  2. 拦截参数的处理
  3. 拦截结果集的处理,为sql执行之后的结果拦截过滤
  4. 拦截Sql语法构建的处理,为sql执行之前的拦截进行sql封装

MyBatis拦截器的接口定义

一共有三个方法interceptpluginsetProperties

setProperties()

方法主要是用来从配置中获取属性。

如果是使用xml式配置拦截器,可在Mybatis配置文件中添加如下节点,属性可以以如下方式传递

<plugins>
	<plugin interceptor="tk.mybatis.simple.plugin.XXXInterceptor">
		<property name="propl" value="valuel" />
		<property name="prop2" value="value2" />
	</plugin>
</plugins>

如果在Spring boot中使用,则需要单独写一个配置类,如下:

@Configuration
public class MybatisInterceptorConfig { 
   
    @Bean
    public String myInterceptor(SqlSessionFactory sqlSessionFactory) { 
   
        ExecutorInterceptor executorInterceptor = new ExecutorInterceptor();
        Properties properties = new Properties();
        properties.setProperty("prop1","value1");
        executorInterceptor.setProperties(properties);
        return "interceptor";
    }
}

如果说不需要配置属性,则在spring boot中,不需要去编写配置类,只需要像我一样在拦截器上加个@Component即可。

plugin()

方法用于指定哪些方法可以被此拦截器拦截。

intercept()

方法是用来对拦截的sql进行具体的操作。

注解实现

MyBatis拦截器用到了两个注解:@Intercepts@Signature

@Intercepts(
        { 
   
                @Signature(type = Executor.class, method = "query",
                        args = { 
   MappedStatement.class, Object.class,
                                RowBounds.class, ResultHandler.class}),
                @Signature(type = Executor.class, method = "query",
                        args = { 
   MappedStatement.class, Object.class, RowBounds.class,
                                ResultHandler.class, CacheKey.class, BoundSql.class}),
        }
)

type的值与类名相同,method方法名相同,为了避免方法重载,args中指定了各个参数的类型和个数,可通过invocation.getArgs()获取参数数组。

Executor 拦截器实现

@Intercepts({ 
   
        @Signature(
        type= Executor.class,
        method = "query",
        args = { 
   MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
        )
})
@Slf4j
@Component
public class ExecutorInterceptor implements Interceptor { 
   
    @Override
    public Object intercept(Invocation invocation) throws Throwable { 
   
        String sql = ExecutorPluginUtils.getSqlByInvocation(invocation);
        //可以对sql重写
        log.error("拦截器ExecutorInterceptor:"+sql);
        //sql = "SELECT id from BUS_RECEIVER where id = ? ";
        ExecutorPluginUtils.resetSql2Invocation( invocation,  sql);
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) { 
   
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) { 
   

    }


}

ParameterHandler 拦截器实现

/** * @Author: ynz * @Date: 2018/12/23/023 12:07 */
@Intercepts({ 

@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class),
})
@Component
@Slf4j
public class ParamInterceptor  implements Interceptor { 

@Override
public Object intercept(Invocation invocation) throws Throwable { 

log.error("拦截器ParamInterceptor");
//拦截 ParameterHandler 的 setParameters 方法 动态设置参数
if (invocation.getTarget() instanceof ParameterHandler) { 

ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];
// 反射获取 BoundSql 对象,此对象包含生成的sql和sql的参数map映射
Field boundSqlField = parameterHandler.getClass().getDeclaredField("boundSql");
boundSqlField.setAccessible(true);
BoundSql boundSql = (BoundSql) boundSqlField.get(parameterHandler);
// 反射获取 参数对像
Field parameterField = 
parameterHandler.getClass().getDeclaredField("parameterObject");
parameterField.setAccessible(true);
Object parameterObject = parameterField.get(parameterHandler);
if (parameterObject instanceof Map) { 

//将参数中的name值改为2
((Map) parameterObject).put("name","2");
}
// 改写的参数设置到原parameterHandler对象
parameterField.set(parameterHandler, parameterObject);
parameterHandler.setParameters(ps);
log.error(JSON.toJSONString(boundSql.getParameterMappings()));
log.error(JSON.toJSONString(parameterObject));
}
return invocation.proceed();
}
@Override
public Object plugin(Object o) { 

return Plugin.wrap(o, this);
}
@Override
public void setProperties(Properties properties) { 

}
}

ResultSetHandler 拦截器实现

@Intercepts({ 

@Signature(type = ResultSetHandler.class, method = "handleResultSets", args={ 
Statement.class})
})
@Component
@Slf4j
public class ResultInterceptor implements Interceptor { 

@Override
public Object intercept(Invocation invocation) throws Throwable { 

log.error("拦截器ResultInterceptor");
// ResultSetHandler resultSetHandler1 = (ResultSetHandler) invocation.getTarget();
//通过java反射获得mappedStatement属性值
//可以获得mybatis里的resultype
Object result = invocation.proceed();
if (result instanceof ArrayList) { 

ArrayList resultList = (ArrayList) result;
for (int i = 0; i < resultList.size(); i++) { 

Object oi = resultList.get(i);
Class c = oi.getClass();
Class[] types = { 
String.class};
Method method = c.getMethod("setAddress", types);
// 调用obj对象的 method 方法
method.invoke(oi, "china");
}
}
return result;
}
@Override
public Object plugin(Object target) { 

return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) { 

}
}

StatementHandler 拦截器实现

/** * @Author: ynz * @Date: 2018/12/23/023 14:22 */
@Intercepts(
{ 
@Signature(
type = StatementHandler.class,
method = "prepare",
args = { 
Connection.class, Integer.class}
)
})
@Component
@Slf4j
public class StatementInterceptor implements Interceptor { 

@Override
public Object intercept(Invocation invocation) throws Throwable { 

StatementHandler statementHandler = 
(StatementHandler) PluginUtils.realTarget(invocation.getTarget());
MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
MappedStatement mappedStatement = 
(MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
//只拦截select方法
if (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) { 

return invocation.proceed();
}
BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
//获取到sql
String originalSql = boundSql.getSql();
//可以对originalSql进行改写
log.error("拦截器StatementInterceptor:"+originalSql);
metaStatementHandler.setValue("delegate.boundSql.sql", originalSql);
Object parameterObject = boundSql.getParameterObject();
return invocation.proceed();
}
@Override
public Object plugin(Object target) { 

return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) { 

}
}

Spring Boot整合

方法1:手写一个配置类

@Configuration
public class MybatisInterceptorConfig { 

@Bean
public String myInterceptor(SqlSessionFactory sqlSessionFactory) { 

ExecutorInterceptor executorInterceptor = new ExecutorInterceptor();
Properties properties = new Properties();
properties.setProperty("prop1","value1");
executorInterceptor.setProperties(properties);
sqlSessionFactory.getConfiguration().addInterceptor(executorInterceptor);
sqlSessionFactory.getConfiguration().addInterceptor(new ParamInterceptor());
sqlSessionFactory.getConfiguration().addInterceptor(new ResultInterceptor());
return "interceptor";
}
}

方法2:在拦截器上加@Component注解

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/195748.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • VMware Tools安装步骤(windows10)[通俗易懂]

    VMware Tools安装步骤(windows10)[通俗易懂]VMwareTools是VMware虚拟机中的一个工具,其主要作用是能够使鼠标在虚拟机和主机之前流畅地切换,并且能够共享剪贴板。我们可以通过VMwareTools将主机的文件复制粘贴到虚拟机。同时使得Ubuntu界面完全填充VMware界面在Windows10环境下,在电脑上安装VMware和Ubuntu的具体步骤可以看此篇博客:Windows环境下,在VMware中安装Ubuntu的详细步骤本文讲述了在VMware16.0.0,Ubuntu21.10环境下,VMwareTools的安装步骤。1

  • mybatisplus关联表查询_hibernate多表查询

    mybatisplus关联表查询_hibernate多表查询我们在设计表的时候往往一个表的外键作为另一张表的主键,那么我们在查询的时候就要查询两个表的数据。下面来说下实现的方法。数据库表的结构wc_user实体类publicclassWcUserimplementsSerializable{ //用户idprivateStringuserId;//用户密码privateStringus…

  • 支持向量机与支持向量回归(support vector machine and support vector regression)

    支持向量机与支持向量回归(support vector machine and support vector regression)支持向量机和支持向量回归是目前机器学习领域用得较多的方法,不管是人脸识别,字符识别,行为识别,姿态识别等,都可以看到它们的影子。在我的工作中,经常用到支持向量机和支持向量回归,然而,作为基本的理论,却没有认真地去梳理和总结,导致有些知识点没有彻底的弄明白。这篇博客主要就是想梳理一遍支持向量机和支持向量回归的基础理论知识,一个是笔记,另一个是交流学习,便于大家共勉。凸集、凸函数、凸优化凸集:如果集合…

  • IOS MapView 用法

    IOS MapView 用法

  • spark面试题目_面试提问的问题及答案

    spark面试题目_面试提问的问题及答案一、简答题1.Sparkmaster使用zookeeper进行HA的,有哪些元数据保存在Zookeeper?答:spark通过这个参数spark.deploy.zookeeper.dir指定master元数据在zookeeper中保存的位置,包括Worker,Driver和Application以及Executors。standby节点要从zk中,获得元数据信息,恢复集群运行状态,才能对外…

    2022年10月30日
  • spring中使用form标签「建议收藏」

    在jsp头部包含:按如下方式编写表单:              111                    222                    333                    444

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号