mybatis 拦截器

article/2025/10/1 8:27:02

🚀 优质资源分享 🚀

学习路线指引(点击解锁)知识定位人群定位
🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

1.mybatis拦截器介绍

拦截器可在mybatis进行sql底层处理的时候执行额外的逻辑,最常见的就是分页逻辑、对结果集进行处理过滤敏感信息等。

  public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql);parameterHandler = (ParameterHandler) interceptorChain.pluginAll(parameterHandler);return parameterHandler;}public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,ResultHandler resultHandler, BoundSql boundSql) {ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);return resultSetHandler;}public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);return statementHandler;}public Executor newExecutor(Transaction transaction) {return newExecutor(transaction, defaultExecutorType);}public Executor newExecutor(Transaction transaction, ExecutorType executorType) {executorType = executorType == null ? defaultExecutorType : executorType;executorType = executorType == null ? ExecutorType.SIMPLE : executorType;Executor executor;if (ExecutorType.BATCH == executorType) {executor = new BatchExecutor(this, transaction);} else if (ExecutorType.REUSE == executorType) {executor = new ReuseExecutor(this, transaction);} else {executor = new SimpleExecutor(this, transaction);}if (cacheEnabled) {executor = new CachingExecutor(executor);}executor = (Executor) interceptorChain.pluginAll(executor);return executor;}

从上面的代码可以看到mybatis支持的拦截类型只有四种(按拦截顺序)

1.Executor 执行器接口

2.StatementHandler sql构建处理器

3.ParameterHandler 参数处理器

4.ResultSetHandler 结果集处理器

2.拦截器原理

public class InterceptorChain {private final List interceptors = new ArrayList<>();// 遍历定义的拦截器,对拦截的对象进行包装public Object pluginAll(Object target) {for (Interceptor interceptor : interceptors) {target = interceptor.plugin(target);}return target;}public void addInterceptor(Interceptor interceptor) {interceptors.add(interceptor);}public List getInterceptors() {return Collections.unmodifiableList(interceptors);}}#Interceptor
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}}

mybatis拦截器本质上使用了jdk动态代理,interceptorChain拦截器链中存储了用户定义的拦截器,会遍历进行对目标对象代理包装。

用户自定义拦截器类需要实现Interceptor接口,以及实现intercept方法,plugin和setProperties方法可重写,plugin方法一般不会改动,该方法调用了Plugin的静态方法wrap实现了对目标对象的代理

public class Plugin implements InvocationHandler {// 拦截目标对象private final Object target;// 拦截器对象-执行逻辑private final Interceptor interceptor;// 拦截接口和拦截方法的映射private final Map, Set> signatureMap;private Plugin(Object target, Interceptor interceptor, Map, Set> signatureMap) {this.target = target;this.interceptor = interceptor;this.signatureMap = signatureMap;}// 获取jdk代理对象public static Object wrap(Object target, Interceptor interceptor) {// 存储拦截接口和拦截方法的映射Map, Set> signatureMap = getSignatureMap(interceptor);Class type = target.getClass();// 获取拦截目标对象实现的接口,若为空则不代理Class[] interfaces = getAllInterfaces(type, signatureMap);if (interfaces.length > 0) {return Proxy.newProxyInstance(type.getClassLoader(),interfaces,new Plugin(target, interceptor, signatureMap));}return target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {try {// 获取需要拦截的方法集合,若不存在则使用目标对象执行Set methods = signatureMap.get(method.getDeclaringClass());if (methods != null && methods.contains(method)) {// Invocation存储了目标对象、拦截方法以及方法参数return interceptor.intercept(new Invocation(target, method, args));}return method.invoke(target, args);} catch (Exception e) {throw ExceptionUtil.unwrapThrowable(e);}}private static Map, Set> getSignatureMap(Interceptor interceptor) {// 获取Intercepts注解值不能为空Intercepts interceptsAnnotation = interceptor.getClass().getAnnotation(Intercepts.class);// issue #251if (interceptsAnnotation == null) {throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName());}Signature[] sigs = interceptsAnnotation.value();// key 拦截的类型Map, Set> signatureMap = new HashMap<>();for (Signature sig : sigs) {Set methods = signatureMap.computeIfAbsent(sig.type(), k -> new HashSet<>());try {// 获取拦截的方法Method method = sig.type().getMethod(sig.method(), sig.args());methods.add(method);} catch (NoSuchMethodException e) {throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + e, e);}}return signatureMap;}private static Class[] getAllInterfaces(Class type, Map, Set> signatureMap) {Set> interfaces = new HashSet<>();while (type != null) {for (Class c : type.getInterfaces()) {if (signatureMap.containsKey(c)) {interfaces.add(c);}}type = type.getSuperclass();}return interfaces.toArray(new Class[interfaces.size()]);}}折叠 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {/*** Returns method signatures to intercept.** @return method signatures*/Signature[] value();
}@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {/*** Returns the java type.** @return the java type*/Class type();/*** Returns the method name.** @return the method name*/String method();/*** Returns java types for method argument.* @return java types for method argument*/Class[] args();
}

可以看到,当被拦截的方法被执行时主要调用自定义拦截器的intercept方法,把拦截对象、方法以及方法参数封装成Invocation对象传递过去。

在getSignatureMap方法中可以看到,自定义的拦截器类上需要添加Intercepts注解并且Signature需要有值,Signature注解中的type为需要拦截对象的接口(Executor.class/StatementHandler/ParameterHandler/ResultSetHandler),method为需要拦截的方法的方法名,args为拦截方法的方法参数类型。

3.参考例子

接下来举一个拦截器实现对结果集下划线转驼峰的例子来简要说明

/*** @author dxu2* @date 2022/7/14* map结果转驼峰*/
@Intercepts(value = {@Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})})
public class MyInterceptor implements Interceptor {@SuppressWarnings("unchecked")@Overridepublic Object intercept(Invocation invocation) throws Throwable {// 调用目标方法List result = (List) invocation.proceed();for (Object o : result) {if (o instanceof Map) {processMap((Map) o);} else {break;}}return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {}private void processMap(Map map) {Set keySet = new HashSet<>(map.keySet());for (String key : keySet) {if ((key.charAt(0) >= 'A' && key.charAt(0) <= 'Z') || key.indexOf("\_") > 0) {Object value = map.get(key);map.remove(key);map.put(camel(key), value);}}}// 下划线转驼峰private String camel(String fieldName) {StringBuffer stringBuffer = new StringBuffer();boolean flag = false;for (int i = 0; i < fieldName.length(); i++) {if (fieldName.charAt(i) == '\_') {if (stringBuffer.length() > 0) {flag = true;}} else {if (flag) {stringBuffer.append(Character.toUpperCase(fieldName.charAt(i)));flag = false;} else {stringBuffer.append(Character.toLowerCase(fieldName.charAt(i)));}}}return stringBuffer.toString();}
}折叠 

这个例子拦截的是ResultSetHandler的handleResultSets方法,这个方法是用来对结果集处理的,看intercept方法首先调用了目标对象的方法接着强转为List类型,这里为什么可以强转呢,因为我们可以看到handleResultSets方法定义 List handleResultSets(Statement stmt) throws SQLException; 返回的是List类型,然后遍历列表,若元素是map类型的再进行处理把key值转化为驼峰形式重新put到map中。

最后不要忘了把自定义的拦截器添加到配置中,这边是使用xml配置的,添加完后接着运行测试代码,可以看到列user_id已经转换成驼峰形式了。

<plugins><plugin interceptor="org.apache.ibatis.study.interceptor.MyInterceptor">plugin>
plugins>
#mapper接口
List selectAllUsers();#mapper.xml
"selectAllUsers" resultType="map">select user\_id, username, password, nicknamefrom user#java测试类
public class Test {public static void main(String[] args) throws IOException {try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {// 构建session工厂 DefaultSqlSessionFactorySqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);SqlSession sqlSession = sqlSessionFactory.openSession();UserMapper userMapper = sqlSession.getMapper(UserMapper.class);System.out.println(userMapper.selectAllUsers());}}}


http://chatgpt.dhexx.cn/article/7vw83jqY.shtml

相关文章

Mybatis——拦截器Interceptor

本篇介绍Mybatis拦截器/插件相关知识&#xff0c;包括相关的类及作用、拦截器有哪几种、拦截器可以在Mybatis的执行过程中的哪些节点起作用、拦截器如何使用、相关的API&#xff0c;最后附上代码示例。 1. Mybatis拦截器是什么&#xff1f;一般用途&#xff1f; MyBatis允许使…

vue后台管理框架(iview + vue)

iview官网&#xff1a;https://www.iviewui.com/docs/introduce vueiview后台管理文档&#xff1a;https://lison16.github.io/iview-admin-doc/#/ vueiview后台管理线上示例&#xff1a;https://admin.iviewui.com/login vueiview后台管理github&#xff1a;https://github.co…

基于ThinkPHP6+Layui的后台管理框架

项目介绍 一款 PHP 语言基于 ThinkPhp6.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架&#xff0c;可用于快速搭建前后端分离后台管理系统&#xff0c;本着简化开发、提升开发效率的初衷&#xff0c;框架自研了一套个性化的组件&am…

Quickadmin:基于ThinkPhp6+Vue+ElementUI后台管理框架

Quickadmin&#xff1a;基于ThinkPhp6VueElementUI后台管理框架 简介 QuickAdmin 是一款基于ThinkPHP 6.x&#xff0c;ElementUI&&Vue 2.x前后端分离后台管理框架&#xff0c;通过框架自带的在线代码生成器&#xff0c;可以轻松的实现后台管理的curd&#xff08;增删…

后台管理怎样用html实现,后台管理实现

京淘后台管理实现 1.1 商品列表展现 1.1.1 商品POJO对象 1.1.2 表格数据页面结构 1.1.3 请求URL地址 说明&#xff1a;如果采用UI框架并且添加了分页插件&#xff0c;则会自动的形成如下的URL请求地址 1.1.4 编辑ItemController 1.1.5 编辑ItemService 1.1.6 编辑ItemMapper 手…

【React项目架构 】+后台管理系统cms实操

React项目架构 一、 react脚手架 (一) 、yarn 安装 (二) 、react安装 npx create-react-app [-g] npm i react17.0.0 react-dom17.0.0 babel-standalone6.26.0 npm i react-router-dom npm i redux4.1.1 --save npm i redux-thunk2.4.1 npm i redux-persist npm install an…

Python实现的一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台,不用配置各种运行环境

Mini Admin 完整代码下载地址&#xff1a;Python实现的一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台 Mini Admin,一个简洁轻快的后台管理框架.支持拥有多用户组的RBAC管理后台 &#x1f680; 应用场景&#xff1a;2-5人的管理团队&#xff0c;需要管理的资源数…

vue——后台管理系统框架

效果图 代码: <template><el-container class="box-el-container"><el-aside class="box-el-aside" :style="{width:isCollapse?60px:200px}"><el-col :span="12" class="el-menu-aside"><!…

基于ThinkPHP6+Layui通用后台管理框架

项目介绍 一款 PHP 语言基于 ThinkPhp6.x、Layui、MySQL等框架精心打造的一款模块化、插件化、高性能的前后端分离架构敏捷开发框架&#xff0c;可用于快速搭建前后端分离后台管理系统&#xff0c;本着简化开发、提升开发效率的初衷&#xff0c;框架自研了一套个性化的组件&am…

Rust学习指南(一)安装RUST后台管理框架

Windows安装 Rust安装非常简单&#xff0c;只要将Visual Studio的 Visual Studio的构建工具或者Visual Stuido 2022的构件工具安装即可。当被问及要安装哪些内容时&#xff0c;请确保已选择 “C build tools”&#xff0c;并包括 Windows 10 SDK 和英文语言包。具体可以参考这个…

php是一种通用开源,caozha-admin(PHP网站后台管理框架)

caozha-admin 后台管理框架 1.7.2 caozha-admin是一个通用的PHP网站后台管理框架&#xff0c;基于开源的ThinkPHP开发&#xff0c;特点&#xff1a;易上手&#xff0c;零门槛&#xff0c;界面清爽极简&#xff0c;极便于二次开发。 基础功能 1、系统设置 2、管理员管理 3、权限…

移动端后台管理系统框架

创建此项目的初衷 目前移动端越来越重要&#xff0c;好多项目都从PC端转移到了移动端。 前一段给客户做了一个PC和M自适应的项目&#xff0c;用vue-element-admin框架&#xff0c;手机端也能用&#xff0c;但体验有点差&#xff0c;客户改了好多。本来是好意&#xff0c;客户只…

(若依)RuoYi后台管理框架前端

若依后台管理 官方网址 后台管理二开推荐 官网的源码地址可供下载前后端代码 最近进到公司后跟着团队接了两家公司的App一套的开发&#xff0c;到公司的第一天就是先配置开发环境 安装软件之类的 第二天 带着熟悉RuoYi框架 很巧带我的大哥和我是一个学校毕业的 是大师兄 若依…

后台管理系统框架bootstrap中文版

简介&#xff1a; 后台管理系统框架bootstrap中文版 网盘下载地址&#xff1a; http://kekewl.cc/8TLdhidu7gi0 图片&#xff1a;

SpringBoot后台管理系统框架

SpringBoot后台管理系统框架 SpringBoot后台管理系统功能介绍 登录 注册 用户列表和添加功能 只是个框架 实现了shiro权限控制, 详细的shiro使用 一个模板项目系统 只有少量功能 使用技术 SpringBoot框架 Mysql数据库 redis shiro权限 thymeleaf(前端) 功能展示 shi…

thinkphp 后台管理框架swiftadmin的使用

SwiftAdmin 极速开发框架 这款框架是基于ThinkPHP Layui 完美契合&#xff0c;在开发上采用最精简最高效的做法去完成业务系统的需求&#xff0c;是一款优秀的中后台极速开发解决方案。 可以很卡快的上手开发&#xff0c;而且他的文档也很完善&#xff0c;代码量不是很多&…

layui搭建后台管理框架

简介&#xff1a;layui&#xff08;谐音&#xff1a;类UI) 是一款采用自身模块规范编写的前端 UI 框架&#xff0c;遵循原生 HTML/CSS/JS 的书写与组织形式&#xff0c;门槛极低&#xff0c;拿来即用。其外在极简&#xff0c;却又不失饱满的内在&#xff0c;体积轻盈&#xff0…

后台管理框架搭建

搭建一套通用的后台管理框架对于以后的快速开发时是非常重要的。通常框架需要包含权限验证、日志、及一些基础数据的增删改查功能。 本框架采用Spring MVCMybatisFreemarkerAdminlte前端 组合在一起搭建一个管理系统。 大概的样子如下&#xff1a; 1.权限 角色->应用-&…

flutter 后台管理框架

一直希望有一个简单实用&#xff0c;强大的后台管理框架&#xff0c;能快速定义各个管理页面 只注重业务上面的处理&#xff0c;经过良久的寻找 终于找了一款符合大众的开源flutter 框架 运行 example 中lib目录下的 main 编译环境 flutter3 vscode config文件夹下面配置 业务…

一定要收藏的5个后台管理系统的前端框架

当你开发新项目的时候&#xff0c;如何快速的完成一个项目的搭建&#xff0c;这个时候就需要借助到一些模板了&#xff0c;现在网上各类UI模板都是相当的齐全的&#xff0c;本文就介绍几个靓仔觉得非常不错的前端框架&#xff0c;感兴趣的可以了解一下。 1、vue-element-admin …