使用mybatis的@Interceptor实现拦截sql

一  mybatis的拦截器

1.1  拦截器介绍

拦截器是一种基于 AOP(面向切面编程)的技术,它可以在目标对象的方法执行前后插入自定义的逻辑。

1.2  语法介绍

1.注解@Intercepts

@Intercepts({@Signature(type = StatementHandler.class, method = “prepare”, args = {Connection.class, Integer.class})}),表示在 SQL 执行之前进行拦截处理。

@Intercepts 的作用:声明这是一个拦截器。

属性:Signature(注解)

@Signature:要拦截的具体方法

​ 属性: type-拦截接口(四种类型 ),

method-拦截的方法(update,insert,select),

args-重载时根据参数列表确定要拦截的方法。

2.介绍:

Executor:拦截执行器的方法,例如 update、query、commit、rollback 等。可以用来实现缓存、事务、分页等功能。
ParameterHandler:拦截参数处理器的方法,例如 setParameters 等。可以用来转换或加密参数等功能。
ResultSetHandler:拦截结果集处理器的方法,例如 handleResultSets、handleOutputParameters 等。可以用来转换或过滤结果集等功能。
StatementHandler:拦截语句处理器的方法,例如 prepare、parameterize、batch、update、query 等。可以用来修改 SQL 语句、添加参数、记录日志等功能。

1.3  API接口

1.intercept:主要是写我们具体业务逻辑,比如针对增删改sql语句添加更新日期。

2.plugin:生成代理对象

3.setProperties:设置拦截器属性

二  实现案例

2.1 结构

2.2 代码

package com.ljf.springboot.mybaits.demos.utils;import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.stereotype.Component;import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Properties;/*** 1. 打印mysql完整的执行语句* 2. 打印mysql语句执行时间* 这里我们拦截Executor里面的query和update方法*/
@Component
@Intercepts({@Signature(method = "query",type = Executor.class,args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),@Signature(type = Executor.class,method = "update",args = {MappedStatement.class, Object.class})
})
public class LogInterceptor implements Interceptor {/*** 是否显示语句的执行时间*/public static final String PROPERTIES_KEY_ENABLE_EXECUTOR_TIME = "enableExecutorTIme";public static final String ENABLE_EXECUTOR_TIME = "0"; // 显示private boolean enableExecutorTime = false;@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("dddddd======");// 获取执行方法的MappedStatement参数,不管是Executor的query方法还是update方法,第一个参数都是MappedStatementMappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];Object parameter = null;if (invocation.getArgs().length > 1) {parameter = invocation.getArgs()[1];}String sqlId = mappedStatement.getId();BoundSql boundSql = mappedStatement.getBoundSql(parameter);Configuration configuration = mappedStatement.getConfiguration();long sqlStartTime = System.currentTimeMillis();Object re = invocation.proceed();long sqlEndTime = System.currentTimeMillis();// 打印mysql执行语句String sql = getSql(configuration, boundSql, sqlId);System.out.println(sql);// 打印mysql执行时间if (enableExecutorTime) {String sqlTimeLog = sqlId + " 方法对应sql执行时间:" + (sqlEndTime - sqlStartTime) + " ms";System.out.println(sqlTimeLog);}return re;}/*** 通过该方法决定要返回的对象是目标对象还是对应的代理* 不要想的太复杂,一般就两种情况:* <p>* 1. return target;  直接返回目标对象,相当于当前Interceptor没起作用,不会调用上面的intercept()方法* 2. return Plugin.wrap(target, this);  返回代理对象,会调用上面的intercept()方法** @param target 目标对象* @return 目标对象或者代理对象*/@Overridepublic Object plugin(Object target) {System.out.println("==================dssssssssss");return Plugin.wrap(target, this);}/*** 用于获取在Configuration初始化当前的Interceptor时时候设置的一些参数** @param properties Properties参数*/@Overridepublic void setProperties(Properties properties) {if (properties != null) {String executorTImeValue = properties.getProperty(PROPERTIES_KEY_ENABLE_EXECUTOR_TIME);if (executorTImeValue != null) {enableExecutorTime = executorTImeValue.equals(ENABLE_EXECUTOR_TIME);}}}private static String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {return sqlId + " 方法对应sql执行语句:" + assembleSql(configuration, boundSql);}/*** 转义正则特殊字符 ($()*+.[]?\^{}* \\需要第一个替换,否则replace方法替换时会有逻辑bug*/private static String makeQueryStringAllRegExp(String str) {if (str != null && !str.equals("")) {return str.replace("\\", "\\\\").replace("*", "\\*").replace("+", "\\+").replace("|", "\\|").replace("{", "\\{").replace("}", "\\}").replace("(", "\\(").replace(")", "\\)").replace("^", "\\^").replace("$", "\\$").replace("[", "\\[").replace("]", "\\]").replace("?", "\\?").replace(",", "\\,").replace(".", "\\.").replace("&", "\\&");}return str;}/*** 获取参数对应的string值** @param obj 参数对应的值* @return string*/private static String getParameterValue(Object obj) {String value;if (obj instanceof String) {value = "'" + obj.toString() + "'";} else if (obj instanceof Date) {DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);value = "'" + formatter.format(new Date()) + "'";} else {if (obj != null) {value = obj.toString();} else {value = "";}}// 对特殊字符进行转义,方便之后处理替换return value != null ? makeQueryStringAllRegExp(value) : value;}/*** 组装完整的sql语句 -- 把对应的参数都代入到sql语句里面** @param configuration Configuration* @param boundSql      BoundSql* @return sql完整语句*/private static String assembleSql(Configuration configuration, BoundSql boundSql) {// 获取mapper里面方法上的参数Object sqlParameter = boundSql.getParameterObject();// sql语句里面需要的参数 -- 真实需要用到的参数 因为sqlParameter里面的每个参数不一定都会用到List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();// sql原始语句(?还没有替换成我们具体的参数)String sql = boundSql.getSql().replaceAll("[\\s]+", " ");if (parameterMappings.size() > 0 && sqlParameter != null) {// sql语句里面的?替换成真实的参数TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();if (typeHandlerRegistry.hasTypeHandler(sqlParameter.getClass())) {sql = sql.replaceFirst("\\?", getParameterValue(sqlParameter));} else {MetaObject metaObject = configuration.newMetaObject(sqlParameter);for (ParameterMapping parameterMapping : parameterMappings) {// 一个一个把对应的值替换进去 按顺序把?替换成对应的值String propertyName = parameterMapping.getProperty();if (metaObject.hasGetter(propertyName)) {Object obj = metaObject.getValue(propertyName);sql = sql.replaceFirst("\\?", getParameterValue(obj));} else if (boundSql.hasAdditionalParameter(propertyName)) {Object obj = boundSql.getAdditionalParameter(propertyName);sql = sql.replaceFirst("\\?", getParameterValue(obj));}}}}return sql;}
}

2.3 验证效果

1.请求

2.日志结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/779474.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Java - 框架 - Lombok】(2) SpringBoot整合Lombok完成日志的创建使用 - 快速上手;

"SpringBoot"整合"Lombok"完成日志的创建使用 - 快速上手&#xff1b; 环境 “Java"版本"1.8.0_202”&#xff1b;“Lombok"版本"1.18.20”&#xff1b;“Spring Boot"版本"2.5.9”&#xff1b;“Windows 11 专业版_22621…

华硕ROG幻X笔记本GZ301VV原厂OEM预装Win11系统安装包下载

ASUS华硕幻X电脑原装出厂Windows11系统&#xff0c;恢复出厂开箱状态系统 链接&#xff1a;https://pan.baidu.com/s/1RkPr5IscTUolYJVUrxTyhQ?pwdhob2 提取码&#xff1a;hob2 适用型号&#xff1a;GZ301VV、GZ301VU、GZ301VF 原装出厂系统自带所有驱动、出厂主题壁纸、系统…

翔云身份证实名认证接口-PHP调用方法

网络平台集成实名认证接口&#xff0c;是顺应当下网络实名制规定&#xff0c;有效规避法律风险。互联网平台若没有实名认证功能&#xff0c;那么便无法保证网民用户身份的真实性&#xff0c;很有可能被虚假用户攻击&#xff0c;特别是在当网络平台产生垃圾信息乃至是违法信息时…

springmvc自定义http请求状态码

1.背景 在做微信支付后回调时,微信要求: 接收成功&#xff1a; HTTP应答状态码需返回200或204&#xff0c;无需返回应答报文。 接收失败&#xff1a; HTTP应答状态码需返回5XX或4XX&#xff0c;同时需返回应答报文 微信通知文档:支付通知 - H5支付 | 微信支付商户文档中心 …

Flink CDC 同步数据到Doris

Flink CDC 同步数据到Doris Flink CDC 是基于数据库日志 CDC(Change Data Capture)技术的实时数据集成框架,支持了全增量一体化、无锁读取、并行读取、表结构变更自动同步、分布式架构等高级特性。配合 Flink 优秀的管道能力和丰富的上下游生态,Flink CDC 可以高效实现海量…

《VideoMamba》论文笔记

原文链接&#xff1a; [2403.06977] VideoMamba: State Space Model for Efficient Video Understanding (arxiv.org) 原文笔记 What&#xff1a; VideoMamba: State Space Model for Efficient Video Understanding 作者探究Mamba模型能否用于VideoUnderStanding作者引入…

穿透业务报表和回报方案,看见广汽集团的长期价值

在大多数内卷的领域&#xff0c;企业总是有各种各样的理由延缓或者停止回馈资本市场。所以&#xff0c;当我们在竞争激烈的汽车市场&#xff0c;发现这样一家始终将投资者回报放在重要位置的老牌车企时&#xff0c;会觉得有些惊讶。因为伴随着经营和分红上的高确定性&#xff0…

Ubuntu20.04下PCL安装,查看,卸载等操作

Ubuntu20.04下PCL安装&#xff0c;查看&#xff0c;卸载等操作 项目来源 https://github.com/PointCloudLibrary/pclhttps://pointclouds.org/documentation/modules.htmlhttps://pcl.readthedocs.io/projects/tutorials/en/master/ 点云学习&#xff1a; https://github.c…

性能测试的几个重要指标的说明!

在做性能测试过程中有一件很重要的事情需要去完成&#xff0c;那就是分析性能指标数据&#xff0c;可以这样说做性能测试的整个过程都跟指标数据息息相关&#xff0c;下面来说一下常见的一些性能指标数据&#xff1a; 1.吞吐量 2.并发数 3.思考时间 4.响应时间 5.点击数 …

信息安全之网络安全防护

先来看看计算机网络通信面临的威胁&#xff1a; 截获——从网络上窃听他人的通信内容中断——有意中断他人在网络上的通信篡改——故意篡改网络上传送的报文伪造——伪造信息在网络上传送 截获信息的攻击称为被动攻击&#xff0c;而更改信息和拒绝用户使用资源的攻击称为主动…

开始时间大于结束时间

1.dom中代码&#xff0c;监听所选日期值的变化&#xff0c;并把需要比较的时间字段作为参数传到监听方法中&#xff0c; <el-form-item label"起始日期" prop"startTime"><el-date-picker clearable size"small":disabled"isDisa…

智能未来:一站式AI技术探索平台(一键收藏)

KKAI&#xff0c;&#xff08;kk.zlrxjh.top&#xff09; 一个融合了星火大模型和文心大模型技术的先进知识增强型大语言模型&#xff0c;致力于自然语言处理&#xff08;NLP&#xff09;技术的深入研究与开发。此模型展现了卓越的语义理解与内容生成技能&#xff0c;轻松应对…

千川素材投放效果追踪与精准识别

一、投放效果深度追踪&#xff1a;从数据表面到策略内核在数字广告时代&#xff0c;单纯的曝光量已不再是评估广告效果的唯一标准。投放效果的深度追踪要求我们深入挖掘每一个数据背后的意义&#xff0c;洞察广告策略的实际效果。这不仅涉及到广告的点击率、转化率等显性指标&a…

Java毕业设计 基于SSM新闻管理系统

Java毕业设计 基于SSM新闻管理系统 SSM jsp 新闻管理系统 功能介绍 用户&#xff1a;首页 图片轮播 查询 登录 注册 新闻正文 评论 广告 社会新闻 天下新闻 娱乐新闻 个人中心 个人收藏 管理员&#xff1a;登录 用户管理 新闻管理 新闻类型管理 角色&#xff1a;用户 管理员…

FMEA与智能机器人:提升机器人可靠性与安全性的关键

随着科技的飞速发展&#xff0c;智能机器人已经深入到我们生活的方方面面&#xff0c;从工业生产到家庭服务&#xff0c;从深海探险到太空探索&#xff0c;处处都有它们的身影。然而&#xff0c;随着应用的日益广泛&#xff0c;机器人系统的复杂性和不确定性也在增加&#xff0…

Paper Digest|基于在线聚类的自监督自蒸馏序列推荐模型

论文标题&#xff1a; Leave No One Behind: Online Self-Supervised Self-Distillation for Sequential Recommendation 作者姓名&#xff1a; 韦绍玮、吴郑伟、李欣、吴沁桐、张志强、周俊、顾立宏、顾进杰 组织单位&#xff1a; 蚂蚁集团 录用会议&#xff1a; WWW 2024 …

书生浦语训练营2期-第一节课笔记

笔记总结: 了解大模型的发展方向、本质、以及新一代数据清洗过滤技术、从模型到应用的典型流程、获取数据集的网站、不同微调方式的使用场景和训练数据是什么&#xff0c;以及预训练和微调在训练优势、通信/计算调度、显存管理上的区别。 收获&#xff1a; 理清了预训练和微调…

第十三届蓝桥杯省赛真题 Java 研究生 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 排列字母试题 B: 灭鼠先锋试题 C: 质因数个数试题 D: 数位排序试题 E: 蜂巢试题 F : \mathrm{F}: F: 爬树的甲壳虫试题 G: 重新排序试题 H \mathrm{H} H : 技能升级试题 I: 最优清零方案试题 J : \mathrm{J}: J: 推导部分和 发现宝藏 …

Java基础之算数运算符的初级用法

运算符 运算符: 对字面量或者变量进行操作的符号 表达式: 用运算符把字面量或者变量连接起来,符合java语法的式子就可以称为表达式 不同运算符连接的表达式体现的是不同类型的表达式 一 .算数运算符 实践一下 加 减 乘 运行结果: 除 取模 运行结果 练习: 数值拆分 需求…

Nginx_简介 + Linux系统下详细安装教程指路

安装教程指路 可参看该视频【尚硅谷Nginx教程&#xff08;亿级流量nginx架构设计&#xff09;】 https://www.bilibili.com/video/BV1yS4y1N76R/?p2&share_sourcecopy_web&vd_source4c2f33f3ba1a0dd45bfdf574befd0069 的p2-p7。从安装centos虚拟机到在虚拟机上安装ng…