mybatis实战之拦截器

在服务的开发过程中,往往存在这样的需求,针对业务,实现对数据库操作语句做统一的处理。比如对某些敏感数据如用户姓名、手机号等坐脱敏处理保存和查询、对未实现权限的查询通过添加关联查询实现权限控制查询结果等等。
这时,mybatis框架提供了拦截器的方式,允许在映射语句执行过程中的某一点进行拦截调用,进行自己的业务处理。

1、使用方法

这里参考了官网的使用说明,只需实现 Interceptor 接口,并在类中指定想要拦截的方法签名即可。比如:

@Intercepts({@Signature(type= Executor.class,method = "update",args = {MappedStatement.class,Object.class})})
public class ExamplePlugin implements Interceptor {private Properties properties = new Properties();public Object intercept(Invocation invocation) throws Throwable {// implement pre processing if needObject returnObject = invocation.proceed();// implement post processing if needreturn returnObject;}public void setProperties(Properties properties) {this.properties = properties;}
}

然后在mybatis的配置文件中,添加插件的对应配置即可。

<!-- mybatis-config.xml -->
<plugins><plugin interceptor="org.mybatis.example.ExamplePlugin"><property name="someProperty" value="100"/></plugin>
</plugins>

我们也可以在代码中添加,下面给出在spring中

//通过spring查找SqlSessionFactory对象的逻辑在此省略
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) var3;
org.apache.ibatis.session.Configuration c = sqlSessionFactory.getConfiguration();
c.addInterceptor(interceptor);

分别加上处理的业务逻辑,这个拦截器就可以使用了。

2、需要注意的地方

第一节简单介绍了,拦截器的使用方法,但在实际项目中这样还远远不够。笔者在本节列举了一些需要注意的地方,供大家思考讨论。

1、拦截器的执行顺序

拦截器的调用顺序分为两大种,第一种是拦截的不同对象,第二种是指拦截同一种对象的同一个方法。

  • 第一种情况,例如拦截 Executor 和 拦截 StatementHandler 就属于不同的拦截对象, 这两类的拦截器在整体执行的逻辑上是不同的。

StatementHandler 属于 Executor 执行过程中的一个子过程。 所以这两种不同类别的插件在配置时,一定是先执行 Executor 的拦截器,然后才会轮到 StatementHandler。所以这种情况下配置拦截器的顺序就不重要了,在 MyBatis 逻辑上就已经控制了先后顺序。

  • 第二种情况,例如都拦截 Executor 的 query 方法,这时你配置拦截器的顺序就会对这里有影响了。比如配置如下。
<plugins><plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor1"/><plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor2"/><plugin interceptor="com.github.pagehelper.ExecutorQueryInterceptor3"/>
</plugins>

前面我们配置拦截器的顺序是1,2,3。在这里也会按照 1,2,3 的顺序被层层代理,代理后的结构如下:

Interceptor3:{Interceptor2: {Interceptor1: {target: Executor}}
}

然后到执行的逻辑:

Interceptor3 前置处理
Interceptor2 前置处理
Interceptor1 前置处理
Object result = executor.query(4个参数方法);
Interceptor1 后续处理
Interceptor2 后续处理
Interceptor3 后续处理
return result;

顺序就是 3>2>1>Executor>1>2>3。MyBatis的拦截器采用责任链设计模式,多个拦截器之间的责任链是通过动态代理组织的。我们一般都会在拦截器中的intercept方法中往往会有invocation.proceed()语句,其作用是将拦截器责任链向后传递,本质上便是动态代理的invoke。

2、与常用插件的整合遇到的问题
  • pageHelper造成分页失效的问题
    通过查看pagehelper源码,可以看到其inercept方法直接获取了excutor然后开始分页查询,当查询到结果时,便返回了。就是pagehelper的intercept方法中没有invocation.proceed(),这意味着什么?
//com.github.pagehelper.PageInterceptor#intercept
.....resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);}return dialect.afterPage(resultList, parameter, rowBounds);} finally {dialect.afterAll();}

这意味着pagehelper没有继续向后传递责任链,而是自行处理直接返回。由此,我们可以猜出该问题大概率与拦截器的执行顺序有关。通过断点调试,验证了该猜想,当遇到分页查询时,执行到pagehelper就结束了,没有进入我们的自定义拦截器。这就可能造成我们自定义拦截器失效。
解决方案
因为PageHelper是Excetor类型的拦截器,所以我们如果想要在PageHelper拦截器前面执行,就必须要将我们自己的拦截器添加到他的拦截器后面。
这里只介绍最简单最优雅的一种方式:
注册一个ApplicationListener监听器,监听 ContextRefreshedEvent 事件,当所有的bean都初始化完成后(即PageHelper也已经注册好了),再把我们的自定义 MyBatis 拦截器注册到 SqlSessionFactory 中。

3、可以提升的点

Interceptor接口提供了三个方法分别是拦截器处理逻辑的主要方法、判断是否要进行拦截,然后做出决定是否生成一个代理的方法及设置参数的方法。

package org.apache.ibatis.plugin;import java.util.Properties;public interface Interceptor {Object intercept(Invocation invocation) throws Throwable;default Object plugin(Object target) {return Plugin.wrap(target, this);}default void setProperties(Properties properties) {// NOP}
}

这里说的提升点,就是在实现接口的实现类中,我们可以在plugin方法里加上一个判断,因为默认情况下,拦截器根据顺序拦截后,就可以去处理对应逻辑了,这里加上一个判断拦截的条件,可以减少代理类的创建。

    @Overridepublic Object plugin(Object target) {if (target instanceof StatementHandler && checkIfNeeded((StatementHandler) target)) {return Plugin.wrap(target, this);} else {return target;}}

参考文档:

官网plugin
pagehelper
解决PageHelper使Mybatis自定义拦截器失效

mybatis实战之拦截器相关推荐

  1. 使用mybatis plus自定义拦截器,实现数据权限

    需求 为了增强程序的安全性,需要在用户访问数据库的时候进行权限判断后选择性进行判断是否需要增强sql,来达到限制低级别权限用户访问数据的目的. 根据业务需要,这里将角色按照数据范围做权限限定.比如,角 ...

  2. Mybatis Plugin(拦截器)的开发

    1.Plugin MyBatis 允许使用插件来拦截的方法调用包括: • Executor (update, query, flushStatements, commit, rollback, get ...

  3. Mybatis自定义SQL拦截器

    本博客介绍的是继承Mybatis提供的Interface接口,自定义拦截器,然后将项目中的sql拦截一下,打印到控制台. 先自定义一个拦截器 package com.muses.taoshop.com ...

  4. MyBatis 插件之拦截器(Interceptor),拦截查询语句

    一.背景 在很多业务场景下我们需要去拦截sql,达到不入侵原有代码业务处理一些东西,比如:分页操作,数据权限过滤操作,SQL执行时间性能监控等等,这里我们就可以用到Mybatis的拦截器Interce ...

  5. Mybatis之Interceptor拦截器

    MyBatis提供了一种插件(plugin)的功能,虽然叫做插件,但其实这是拦截器功能.那么拦截器拦截MyBatis中的哪些内容呢? 我们进入官网看一看: MyBatis 允许你在已映射语句执行过程中 ...

  6. Spring Boot实战:拦截器与过滤器

    一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...

  7. struts实战--登陆拦截器

    登陆校验拦截器 一.概述 功能:用户只有登录成功后,才可以进行操作. 二.实现 1).创建一个类,实现Interceptor接口 1.判断用户user是否为空 2.如果为空,则设置哪些方法可以不用登陆 ...

  8. Mybatis拦截器安全加解密MySQL数据实战

    需求背景 公司为了通过一些金融安全指标(政策问题)和防止数据泄漏,需要对用户敏感数据进行加密,所以在公司项目中所有存储了用户信息的数据库都需要进行数据加密改造.包括Mysql.redis.mongod ...

  9. 【mybatis系列】自定义实现拦截器插件Interceptor

    目录 类型 规则 介绍 intercept(Invocation invocation) plugin(Object target) setProperties(Properties properti ...

  10. MySQL拦截器获取xml id_关于mybatis拦截器,有谁知道怎么对结果集进行拦截,将指定字段查询结果进行格式化...

    用MyBatis结果集拦截器做过这样一个需求: 由于项目需求经常变动,项目MySQL数据库都是存放JSON字符串,例如:用户的基本信息随着版本升级可能会有变动 数据表 CREATE TABLE `ac ...

最新文章

  1. 设置文件权限位时我们一般忽略了suid/guid的存在,现在看看它们到底是怎么回事
  2. makefile中命令的显示
  3. 昨天还在for循环里写加号拼接字符串的那个同事,今天已经不在了
  4. MyEclipse配置DataBase Explorer
  5. 由浅入深学“工厂模式”(3)
  6. lass翻译_【专题讲座】政务翻译人才培训系列讲座(1)
  7. 【LeetCode-SQL每日一题】——183. 从不订购的客户
  8. python判断阿姆斯特朗数_Python 程序检查阿姆斯特朗数
  9. MySQL数据库开发 (视频)
  10. windows下使用cmake+mingw配置makefile(2)
  11. cmake命令的python库的位置参数-DTORCH_PATH
  12. stm32呼吸灯程序_STM32裸机开发基础篇02点亮LED
  13. 关闭计算机端口的命令行,关闭端口命令,小编教你如何关闭电脑80端口
  14. 鸿鹄系统和鸿蒙系统电脑,荣耀智慧屏发布:首发鸿鹄818处理器及鸿蒙系统,定价3799元起...
  15. Atitit.wrmi web rmi框架新特性
  16. cc2530设计性实验代码八
  17. mathtype 7.4.10.53中文版安装教程,以及如何将MathType嵌入到word中
  18. C11标准和C++11标准
  19. 《Rework》语句摘录
  20. sakila-dwh-schema文件

热门文章

  1. 联想服务器怎么备份系统软件,联想电脑管家备份电脑驱动程序教程
  2. Leetcode NO.63 Unique Paths II
  3. 使用PdgCntEditor软件对PDF目录进行快速编辑
  4. 西门子PLC常用通信协议以及常用协议的区别(二)
  5. linux操作系统短进程优先调度算法,操作系统的常用的进程调度算法
  6. 前端工程师如何快速的Mac装机?学会这些技巧让你的装机速度提升至少1倍!!!
  7. 程序员【超实用】面试问题
  8. 【系统辨识】初识系统辨识,学习这个的目的
  9. JLink驱动设备管理器中显示黄色感叹号
  10. python代码混淆