使用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,一经查实,立即删除!

相关文章

Python—数据类型转换

一&#xff1a;基本数据类型 1.数值类型 整型&#xff08;int&#xff09; 浮点型 &#xff08;float&#xff09; 虚数 num2 0b0011#二进制的数字前面加0b num8 0o0011#八进制的数字前面加0o num16 0x0011#十六进制的数字前面加0x print(num2,num8,num16)3 9 17 2.布尔类…

【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 原装出厂系统自带所有驱动、出厂主题壁纸、系统…

如何让div中滚动条一直保持在最下方

设置div的scrollTop属性等于scrollHeight属性。 function onScrollChange() {const ele document.getElementById("test");ele.scrollTop ele.scrollHeight; }在React可以通过 ref 获取div元素 1.声明一个ref设置在div元素上 const testRef useRef(null)&#…

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

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

springmvc自定义http请求状态码

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

ubuntu 22.04 LTS 内核从 5.15.0 升级到 6.6.0

ubuntu 22.04LTS 内核从 5.15.0 升级到 6.6.0 ubuntu 22.04LTS 内核从 5.15.0 升级到 6.6.0升级内核时报错解决方法 内核升级过程回滚到先前版本 ubuntu 22.04LTS 内核从 5.15.0 升级到 6.6.0 升级内核时报错 ubuntu22.04LTS源码编译升级内核时报错&#xff0c; make[3]: **…

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…

高通平台ramdump-parser 工具

高通平台ramdump-parse工具生成 1. 获取GNU-TOOLSaosp-caf 源码目录下&#xff1a;自行下载GNU-Tools: 2. 获取ramdump-parseraosp-caf 源码目录下&#xff1a;自行下载ramdump-parser&#xff1a; 3. 修改linux-ramdump-parser-v2/local_settings.py4. 编写执行脚本5. 输出解析…

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

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

信息安全之网络安全防护

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

兼容性测试指南:技术和最佳实践

研究表明&#xff0c;如果应用程序表现不佳&#xff0c;88% 的用户就会放弃该应用程序。然而&#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;可变形参的方法n个字符串进行拼接&#xff0c;每一个字符串之间使用某字符进行分割&#xff0c;如果没有传入字符串&#xff0c;那么返回空字符串"" 代码 /*** ClassName: StringConCatTest* Description:* 练习&#xff1a;可变形参的方法** n…

vue 条件渲染

v-if​ v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。 <h1 v-if"awesome">Vue is awesome!</h1> v-else​ 你也可以使用 v-else 为 v-if 添加一个“else 区块”。 <button click"awesome !awesome&…

spring概念 及 SpringIoc 、DI

Spring框架&#xff0c;即&#xff1a;SpringFramework&#xff0c;主要优势 1、丰富的生态系统&#xff1a;Sping支持许多模块和库&#xff0c;如&#xff1a;SpringBoot、SpringSecurity、SpringCloud等&#xff0c; 2、模块化设计&#xff1a;框架组件之间的松散耦合和模块…