当前位置: 首页 > news >正文

解决SpringMVC使用MyBatis-Plus自定义MyBaits拦截器不生效的问题

自定义MyBatis拦截器

如果是SpringBoot项目引入@Component注解就生效了,但是SpringMVC不行

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.util.StringUtils;import java.lang.reflect.Field;
import java.sql.Statement;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;@Slf4j
@Intercepts({@Signature(type = StatementHandler.class, method = "update", args = {Statement.class,}),@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class})
})
//@Component 在SpringBoot生效,在SpringMVC不生效
public final class MyBatisSqlParsingPlugin implements Interceptor {private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");@Overridepublic Object intercept(Invocation invocation) throws Throwable {StatementHandler statementHandler = (StatementHandler) invocation.getTarget();ParameterHandler parameterHandler = statementHandler.getParameterHandler();BoundSql boundSql = statementHandler.getBoundSql();try {String sql = formatSql(parameterHandler, boundSql);if (!boundSql.getSql().equals(sql)) {log.info("Execute SQL:{}", sql);}} catch (Exception e) {String sql = boundSql.getSql();log.error("Execute SQL:{}\nException:", sql, e);}return invocation.proceed();}@Overridepublic Object plugin(Object target) {return Interceptor.super.plugin(target);}@Overridepublic void setProperties(Properties properties) {Interceptor.super.setProperties(properties);}/*** 格式化SQL及其参数*/private String formatSql(ParameterHandler parameterHandler, BoundSql boundSql) throws NoSuchFieldException, IllegalAccessException {Class<? extends ParameterHandler> parameterHandlerClass = parameterHandler.getClass();Field mappedStatementField = parameterHandlerClass.getDeclaredField("mappedStatement");mappedStatementField.setAccessible(true);MappedStatement mappedStatement = (MappedStatement) mappedStatementField.get(parameterHandler);String sql = boundSql.getSql().replaceAll("\\s+", " ");// sql字符串是空或存储过程,直接跳过if (!StringUtils.hasText(sql) || sql.trim().charAt(0) == '{') {return "";}// 不传参数的场景,直接把Sql美化一下返回出去Object parameterObject = parameterHandler.getParameterObject();List<ParameterMapping> parameterMappingList = boundSql.getParameterMappings();if (Objects.isNull(parameterObject) || parameterMappingList.isEmpty()) {return sql;}return handleCommonParameter(sql, boundSql, mappedStatement);}//替换预编译SQLprivate String handleCommonParameter(String sql, BoundSql boundSql, MappedStatement mappedStatement) {Object parameterObject = boundSql.getParameterObject();List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();Configuration configuration = mappedStatement.getConfiguration();TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();List<String> params = new ArrayList<>();for (ParameterMapping parameterMapping : parameterMappings) {if (parameterMapping.getMode() == ParameterMode.OUT) {continue;}Object propertyValue;String propertyName = parameterMapping.getProperty();if (boundSql.hasAdditionalParameter(propertyName)) {propertyValue = boundSql.getAdditionalParameter(propertyName);} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {propertyValue = parameterObject;} else {MetaObject metaObject = configuration.newMetaObject(parameterObject);propertyValue = metaObject.getValue(propertyName);}params.add(this.formatParam(propertyValue));}//转译百分号if (sql.contains("%")) {//如果参数不一致直接返回SQLPattern pattern = Pattern.compile("\\?");Matcher matcher = pattern.matcher(sql);int count = 0;while (matcher.find()) {count++;}if (count == 0 || params.isEmpty()) {return sql;}if (params.size() != count) {log.error("SQL:{}", sql);log.error("SQL parameters:{}", params);return sql;}sql = sql.replaceAll("%", "%%");}sql = sql.replaceAll("\\?", "%s");return String.format(sql, params.toArray());}private String formatParam(Object object) {if (object == null) {return "null";}if (object instanceof String) {return formatString((String) object);}if (object instanceof Date) {return formatDate((Date) object);}if (object instanceof LocalDate) {return formatLocalDate((LocalDate) object);}if (object instanceof LocalDateTime) {return formatLocalDateTime((LocalDateTime) object);}return object.toString();}private static String formatString(String str) {return "'" + str + "'";}private String formatDate(Date date) {return "'" + DATE_TIME_FORMATTER.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()) + "'";}private String formatLocalDate(LocalDate date) {return "'" + DATE_FORMATTER.format(date) + "'";}private String formatLocalDateTime(LocalDateTime dateTime) {return "'" + DATE_TIME_FORMATTER.format(dateTime) + "'";}
}

mybatis-plus使用mybatis插件

MybatisPlusInterceptor实现的是MyBaits Interceptor接口,而MybatisPlusInterceptor自己又创建了一个InnerInterceptor接口去实现自己的插件,比如:PaginationInnerInterceptor 分页插件。我们使用的是MyBatis Interceptor的插件,所以不能注入到MybatisPlusInterceptor类里面,而是要和MybatisPlusInterceptor平级,因为前面也说了MybatisPlusInterceptor 实现的是MyBaits Interceptor,而我们自定义的MyBatisSqlParsingPlugin实现的也是MyBaits Interceptor,因此要和MybatisPlusInterceptor平级放到plugins下面,建议自定义的MyBaits Interceptor要放到MybatisPlusInterceptor前面,防止MybatisPlusInterceptor干扰我们自定义的插件。

	<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath*:mapper/**/*.xml"/><property name="typeAliasesPackage" value="com.bsoft.extend.mybatis.entity"/><property name="plugins"><array><!-- 引入的是 MyBatis 插件 --><ref bean="myBatisSqlParsingPlugin"/><!-- 引入的是 MyBatis-Plus 自己封装的插件 --><ref bean="mybatisPlusInterceptor"/></array></property></bean><!-- 实现 MyBatis Interceptor 接口的插件 --><bean id="myBatisSqlParsingPlugin" class="com.bsoft.extend.mybatis.plugins.MyBatisSqlParsingPlugin"/><!-- 实现 MyBatis-Plus InnerInterceptor 接口的插件【就是MyBatis-Plus自己封装的插件】 --><bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor"><property name="interceptors"><list><!-- 引入 MyBatis-Plus 分页插件 --><ref bean="paginationInnerInterceptor"/></list></property></bean><!-- MyBatis-Plus 分页插件配置 --><bean id="paginationInnerInterceptor" class="com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor"><constructor-arg name="dbType" value="ORACLE"/><property name="optimizeJoin" value="true"/></bean>

相关文章:

解决SpringMVC使用MyBatis-Plus自定义MyBaits拦截器不生效的问题

自定义MyBatis拦截器 如果是SpringBoot项目引入Component注解就生效了&#xff0c;但是SpringMVC不行 import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.executor.parameter.ParameterHandler; import org.apache.ibatis.executor.statement.StatementHandler; i…...

Swagger与RESTful API

1. Swagger简介 在现代软件开发中&#xff0c;RESTful API已成为应用程序间通信的一个标准。这种架构风格通过使用标准的HTTP方法来执行网络上的操作&#xff0c;简化了不同系统之间的交互。API&#xff08;应用程序编程接口&#xff09;允许不同的软件系统以一种预定义的方式…...

MySQL84 -- ERROR 1524 (HY000): Plugin ‘msql_native_password‘ is not loaded.

【问题描述】 MySQL 8.4版本&#xff0c;配置用户使用mysql_native_password认证插件验证用户身份&#xff0c;报错&#xff1a; 【解决方法】&#xff08;Windows, MySQL 8.4) 1、修改MySQL配置文件my.ini&#xff0c;在[mysqld]段添加mysql_native_passwordON。 2、管理员…...

将Excel中的错误值#N/A替换成心仪的字符串,瞬间爱了……

常用表格的人都晓得&#xff0c;看到满屏悦动的#N/A&#xff0c;心情都会不好。把它替换成自己心仪的字符&#xff0c;瞬间就爱了。 (笔记模板由python脚本于2024年06月13日 19:32:37创建&#xff0c;本篇笔记适合常用Excel&#xff0c;喜欢数据的coder翻阅) 【学习的细节是欢悦…...

AI大模型日报#0628:谷歌开源9B 27B版Gemma2、AI首次实时生成视频、讯飞星火4.0发布

导读&#xff1a;AI大模型日报&#xff0c;爬虫LLM自动生成&#xff0c;一文览尽每日AI大模型要点资讯&#xff01;目前采用“文心一言”&#xff08;ERNIE-4.0-8K-latest&#xff09;生成了今日要点以及每条资讯的摘要。欢迎阅读&#xff01;《AI大模型日报》今日要点&#xf…...

【随笔】提高代码学习水平(以更高的视角看事物)

最近&#xff0c;我感觉到自己的代码水平似乎卡在了一个瓶颈。似乎只想着数仓&#xff0c;Hive&#xff0c;Spark技术优化&#xff0c;但只要稍微离开这几个点&#xff0c;我就感到无所适从。我开始反思&#xff0c;或许&#xff0c;我应该总结一下自己的学习方法。 1.站的高&…...

游戏AI的创造思路-技术基础-深度学习(5)

继续深度学习技术的探讨&#xff0c;填坑不断&#xff0c;头秃不断~~~~~ 目录 3.5. 自编码器&#xff08;AE&#xff09; 3.5.1. 定义 3.5.2. 形成过程 3.5.3. 运行原理 3.5.3.1.运行原理及基本框架 3.5.3.2. 示例代码 3.5.4. 优缺点 3.5.5. 存在的问题和解决方法 3.5…...

基于SpringBoot养老院管理系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…...

餐饮点餐的简单MySQL集合

ER图 模型图&#xff08;没有进行排序&#xff0c;混乱&#xff09; DDL和DML /* Navicat MySQL Data TransferSource Server : Mylink Source Server Version : 50726 Source Host : localhost:3306 Source Database : schooldbTarget Server Type …...

STM32驱动-ads1112

汇总一系列AD/DA的驱动程序 ads1112.c #include "ads1112.h" #include "common.h"void AD5726_Init(void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE );//PORTA、D时钟使能 G…...

数据结构与算法高频面试题

初级面试题及详细解答 当涉及到数据结构与算法的初级面试题时&#xff0c;通常涉及基本的数据结构操作、算法复杂度分析和基本算法的应用。 1. 什么是数组&#xff1f;数组和链表有什么区别&#xff1f; 解答&#xff1a; 数组&#xff1a;是一种线性数据结构&#xff0c;用…...

uni-app的showModal提示框,进行删除的二次确认,可自定义确定或取消操作

实现效果&#xff1a; 此处为删除的二次确认示例&#xff0c;点击删除按钮时出现该提示&#xff0c;该提示写在js script中。 实现方式&#xff1a; 通过uni.showModal进行提示&#xff0c;success为确认状态下的操作自定义&#xff0c;此处调用后端接口进行了删除操作&#…...

5款提高工作效率的免费工具推荐

SimpleTex SimpleTex是一款用于创建和编辑LaTeX公式的简单工具。它能够识别图片中的复杂公式并将其转换为可编辑的数据格式。该软件提供了一个直观的界面&#xff0c;用户可以在编辑LaTeX代码的同时实时预览公式的效果&#xff0c;无需额外的编译步骤。此外&#xff0c;SimpleT…...

区块链的技术架构:节点、网络和数据结构

区块链技术听起来很高大上&#xff0c;但其实它的核心架构并不难理解。今天我们就用一些简单的例子和有趣的比喻&#xff0c;来聊聊区块链的技术架构&#xff1a;节点、网络和数据结构。 节点&#xff1a;区块链的“细胞” 想象一下&#xff0c;区块链就像是一个大型的组织&a…...

pdfmake不能设置表格边框颜色?

找到pdfmake>build>pdfmake.js中&#xff1a; 找到定义的“TableProcessor.prototype.drawVerticalLine”和“TableProcessor.prototype.drawHorizontalLine”两个方法&#xff1a; 重新定义borderColor: var borderColor this.tableNode.table.borderColor||"#…...

laravel 使用RabbitMQ作为消息中间件

先搞定环境&#xff0c;安装amqp扩展 确保已安装rabbitmq-c-dev。 比如 可以使用apk add rabbmit-c-dev安装 cd ~ wget http://pecl.php.net/get/amqp-1.10.2.tgz tar -zxf amqp-1.10.2.tgz cd amqp-1.10.2 phpize ./configure make && make install cd ~ rm -rf am…...

web项目打包成可以离线跑的exe软件

目录 引言打开PyCharm安装依赖创建 Web 应用运行应用程序打包成可执行文件结语注意事项 引言 在开发桌面应用程序时&#xff0c;我们经常需要将网页集成到应用程序中。Python 提供了多种方法来实现这一目标&#xff0c;其中 pywebview 是一个轻量级的库&#xff0c;它允许我们…...

BFS:队列+树的宽搜

一、二叉树的层序遍历 . - 力扣&#xff08;LeetCode&#xff09; 该题的层序遍历和以往不同的是需要一层一层去遍历&#xff0c;每一次while循环都要知道在队列中节点的个数&#xff0c;然后用一个for循环将该层节点走完了再走下一层 class Solution { public:vector<vec…...

MySQL高级-SQL优化- count 优化 - 尽量使用count(*)

文章目录 1、count 优化2、count的几种用法3、count(*)4、count(id)5、count(profession)6、count(null)7、 count(1) 1、count 优化 MyISAM引擎把一个表的总行数存在了磁盘上&#xff0c;因此执行count&#xff08;*&#xff09;的时候会直接返回这个数&#xff0c;效率很高&a…...

python Flask methods

在 Flask 中&#xff0c;app.route() 装饰器用于定义 URL 路由和与之关联的视图函数。当你想指定某个 URL 可以接受哪些 HTTP 方法时&#xff0c;你可以使用 methods 参数。methods 是一个列表&#xff0c;它可以包含任何有效的 HTTP 方法。 Falsk文章中的描述&#xff1a; 链…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

【大模型RAG】Docker 一键部署 Milvus 完整攻略

本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装&#xff1b;只需暴露 19530&#xff08;gRPC&#xff09;与 9091&#xff08;HTTP/WebUI&#xff09;两个端口&#xff0c;即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...

Linux-进程间的通信

1、IPC&#xff1a; Inter Process Communication&#xff08;进程间通信&#xff09;&#xff1a; 由于每个进程在操作系统中有独立的地址空间&#xff0c;它们不能像线程那样直接访问彼此的内存&#xff0c;所以必须通过某种方式进行通信。 常见的 IPC 方式包括&#…...