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

mybatisplus做SQL拦截添加自定义排序

前言

工作中写的一段代码,备个份,以后兴许能直接用

功能描述:如果前端传入了排序规则,则优先按传入的字段进行排序,SQL原有的排序规则追加到末尾

注:我们项目里的分页查询,是基于XML的SQL执行的,没有直接使用mybatis-plus的 IPage

正文

定义拦截器


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.jetbrains.annotations.Nullable;import java.sql.Connection;
import java.util.List;/*** 添加自定义排序规则* 如果前端传入了排序规则,则优先按传入的字段进行排序,SQL原有的排序规则追加到末尾* 这个SQL的处理方式【不是基于】字符串拼接,底层的SQL执行是基于 com.mysql.cj.jdbc.ClientPreparedStatement.execute,*  PreparedStatement 是防SQL注入的,强行做SQL注入会抛语法错误的异常 - syntax exception* @author weiheng* @date 2024-01-23**/
@Slf4j
public class MybatisPageOrderSqlInterceptor extends JsqlParserSupport implements InnerInterceptor {/** 排序方式 - 升序 */private static final String SORT_ASC = "asc";@Overridepublic void beforePrepare(StatementHandler sh, Connection connection, Integer transactionTimeout) {if (log.isDebugEnabled()) {log.info(">>>>> 自定义排序拦截 StatementHandler[{}]", sh);log.info(">>>>> 自定义排序拦截 connection[{}]", connection);log.info(">>>>> 自定义排序拦截 transactionTimeout[{}]", transactionTimeout);}PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);MappedStatement ms = mpSh.mappedStatement();SqlCommandType sct = ms.getSqlCommandType();if (sct != SqlCommandType.SELECT) {// 不是查询操作则直接跳过,不做任何操作return;}   PluginUtils.MPStatementHandler mpSh = PluginUtils.mpStatementHandler(sh);PluginUtils.MPBoundSql mpBs = mpSh.mPBoundSql();// 取分页查询的入参 PageDTOPageDTO pageDto = getPageDTO(mpSh);if (pageDto == null || CollUtil.isEmpty(pageDto.getOrderColumns())) {// 不是自定义分页查询,不做处理return;}mpBs.sql(parserMulti(mpBs.sql(), pageDto));}@Overrideprotected void processSelect(Select select, int index, String sql, Object obj) {PageDTO dto;if (obj instanceof PageDTO) {dto = (PageDTO) obj;} else {// 如果不是分页查询,则不做处理return;}// 1. 解析SQLPlainSelect plainSelect = (PlainSelect) select.getSelectBody();List<OrderByElement> originOrderList = plainSelect.getOrderByElements();List<OrderByElement> clonedOriginOrder = null;if (CollUtil.isNotEmpty(originOrderList)) {// 创建副本,然后删除原有排序规则clonedOriginOrder = BeanUtil.copyToList(originOrderList, OrderByElement.class);originOrderList.clear();}// 2. 向 plainSelect 中添加自定义排序规则addCustomizeSortColumns(dto, plainSelect);// 3. 添加SQL的原始排序规则 - 追加到末尾if (CollUtil.isNotEmpty(clonedOriginOrder)) {plainSelect.addOrderByElements(clonedOriginOrder);}if (log.isDebugEnabled()) {log.info("<<<<< 自定义排序拦截 plainSelect[{}]", plainSelect);}}/*** 添加自定义排序规则** @param dto SQL查询入参* @param plainSelect 明文* @author weiheng**/private void addCustomizeSortColumns(PageDTO dto, PlainSelect plainSelect) {List<OrderColumnDTO> orderColumns = dto.getOrderColumns();for (OrderColumnDTO c : orderColumns) {// 构建新的排序规则OrderByElement orderByElement = new OrderByElement();// 设置排序 - 不传值则默认asc升序orderByElement.setAsc(SORT_ASC.equalsIgnoreCase(c.getSort()));// 设置排序字段orderByElement.setExpression(new Column(c.getOrderColumn()));// 重新封装条件 - 优先按自定义进行排序plainSelect.addOrderByElements(orderByElement);}}/*** 分页查询入参获取* 大概搜了下,没有到3个入参的,如果有,请将 PageDTO 放到第1或第2的位置* @param mpSh 处理对象* @return 分页查询入参* @author weiheng**/@Nullableprivate PageDTO getPageDTO(PluginUtils.MPStatementHandler mpSh) {PageDTO pageDto = null;Object obj = mpSh.parameterHandler().getParameterObject();try {Object param = ((MapperMethod.ParamMap<?>) obj).get("param1");if (param instanceof PageDTO) {pageDto = (PageDTO) param;} else {param = ((MapperMethod.ParamMap<?>) obj).get("param2");if (param instanceof PageDTO) {pageDto = (PageDTO) param;}}} catch (Exception e) {// 没有从SQL中获取到对应的参数(没有param1或param2),不走自定义分页逻辑}return pageDto;}}

添加插件 - 添加自定义的拦截器


import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** mybatis配置* @author Heng.Wei* @date 2022-05-11**/
@Configuration
public class MybatisPlusConfig {@Beanpublic MybatisPlusInterceptor paginationInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());// 分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));// 添加防止全表更新与删除插件interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());// 深度分页插件interceptor.addInnerInterceptor(new MybatisHighPageInterceptor());// 添加自定义排序interceptor.addInnerInterceptor(new MybatisPageOrderSqlInterceptor());return interceptor;}
}

代码很简单,不多做废话了,自测OK

补充

在这里插入图片描述
从上图可以看到,这里会 for 循环调用所有拦截器的 beforePrepare 方法
然后再通过 invocation.proceed 反射调用 StatementHandler 接口的 prepare 方法
    可以从图中看到接口实现是 PreparedStatementHandler 类的 instantiateStatement 方法

在这里插入图片描述
通过 PreparedStatementHandler 执行SQL操作

PS: 很意外昨晚发的帖子,基本纯代码,也没什么描述和备注,第二天早上看,展现量9、阅读199、新增粉丝2、收藏6、点赞3
感觉这个东西,喜欢看的同学还比较多,所以又稍微【补充】了一下内容

相关文章:

mybatisplus做SQL拦截添加自定义排序

前言 工作中写的一段代码&#xff0c;备个份&#xff0c;以后兴许能直接用 功能描述&#xff1a;如果前端传入了排序规则&#xff0c;则优先按传入的字段进行排序&#xff0c;SQL原有的排序规则追加到末尾 注&#xff1a;我们项目里的分页查询&#xff0c;是基于XML的SQL执行的…...

代码随想录算法训练营第29天(回溯算法05 | * 491.递增子序列 * 46.全排列 * 47.全排列 II

回溯算法part05 491.递增子序列解题思路与 90.子集II 不同的点回溯三部曲 46.全排列解题思路遇到的难点思考 47.全排列 II解题思路注意点拓展需要加深理解的点&#xff08;需复习 小总结 491.递增子序列 本题和大家刚做过的90.子集II非常像&#xff0c;但又很不一样&#xff0c…...

mac docker desktop被禁用了,如何使用虚拟机lima运行docker

安装lima brew install lima创建配置 echo "\\ndynamic:\n big-sur:\n image: docker://docker:git\n linux:\n image: docker.io/limasoftware/ubuntu:20.04 \\n" > ~/.lima/default.yaml启动名叫default的虚拟机 limactl start default测试 limactl …...

sublime text 开启vim模式

sublime text 开启vim模式 打开配置文件 mac下点击菜单栏 Sublime Text -> Settings... -> Settings 修改配置文件并保存 添加配置 // 开启vim模式 "ignored_packages": [// "Vintage", ], // 以命令模式打开文件 "vintage_start_in_comman…...

JS词法结构

编程语言的词法结构是一套基础性规则&#xff0c;用来描述如何使用这门语言来编写程序。作为语法的基础&#xff0c;它规定了诸如变量名是什么样的、怎么写注释&#xff0c;以及程序语句之间如何分隔等规则。 2.1程序的文本 JS区分大小写 JS忽略程序记号&#xff08;token&am…...

程序媛的mac修炼手册-- 如何用Python节省WPS会员费

上篇分享了如何用微博爬虫&#xff0c;咱举例爬了女明星江疏影的微博数据。今天就用这些数据&#xff0c;给大家安利一下怎么用Python实现WPS中部分Excel付费功能。 MacOS系统自带的工具&#xff0c;绝大多数都非常顶&#xff0c;除Numbers外。当然&#xff0c;page比起word来&…...

ASP.NET Core NE8实现HTTP Upgrade和HTTP CONNECT代理服务器

看到一个文章[Go] 不到 100 行代码实现一个支持 CONNECT 动词的 HTTP 服务器 在NET8中如何实现 创建项目为MiniApi 编辑Program.cs文件。 var builder WebApplication.CreateSlimBuilder(args);var app builder.Build();// 将HTTP请求通过协议升级机制转为远程TCP请求&…...

apipost和curl收不到服务器响应的HTTP/1.1 404 Not Found

windows的apipost发送请求后&#xff0c;服务器响应了HTTP/1.1 404 Not Found&#xff0c;但是apipost一直显示发送中。 linux上的curl也一样。 使用wireshark抓包发现收到了响应&#xff0c;但是wireshark识别不了&#xff08;图中是回应404后关闭了连接&#xff09;&#xff…...

javascript:计算一个坐标数组的最小值点、最大值点、中心点

作者&#xff1a;CSDN _乐多_ 本文将介绍使用 javascript 语言计算一个坐标数组的最小值点、最大值点、中心点的代码。 文章目录 一、代码 一、代码 function calculateCenterPoint(points) {if (points.length 0) {return null;}let sumX 0;let sumY 0;let sumZ 0;for …...

使用远程工具连接Linux系统——使用Root用户登录

1、启动虚拟机&#xff0c;输入以下命令 进入root用户 sudo su或 su root修改ssh配置文件 vim /etc/ssh/sshd_config找到PermitRootLogin 并用#注释掉当前行 # PermitRootLogin prohibit-password添加&#xff1a; PermitRootLogin yes键入esc输入:wq保存退出 2、重启服…...

JuiceSSH结合内网穿透实现移动端设备公网远程访问Linux虚拟机

文章目录 1. Linux安装cpolar2. 创建公网SSH连接地址3. JuiceSSH公网远程连接4. 固定连接SSH公网地址5. SSH固定地址连接测试 处于内网的虚拟机如何被外网访问呢?如何手机就能访问虚拟机呢? cpolarJuiceSSH 实现手机端远程连接Linux虚拟机(内网穿透,手机端连接Linux虚拟机) …...

06-枚举和模式匹配

上一篇&#xff1a;05-使用结构体构建相关数据 在本章中&#xff0c;我们将介绍枚举。枚举允许你通过枚举其可能的变体来定义一种类型。首先&#xff0c;我们将定义并使用一个枚举&#xff0c;以展示枚举如何与数据一起编码意义。接下来&#xff0c;我们将探索一个特别有用的枚…...

【C/C++】C/C++编程——C++ 开发环境搭建

C的开发环境种类繁多&#xff0c;以下是一些常见的C 集成开发环境&#xff1a; AppCode &#xff1a;构建与JetBrains’ IntelliJ IDEA 平台上的用于Objective-C&#xff0c;C,C&#xff0c;Java和Java开发的集成开发环境CLion&#xff1a;来自JetBrains的跨平台的C/C的集成开…...

Go 接口

接口概览 接口大概理解 接口类型是队其他类型行为的概括与抽象 接口类型中&#xff0c;包含函数声明&#xff0c;但没有数据变量接口的作用通过使用接口&#xff0c;可以写出更加灵活和通用的函数&#xff0c;这些函数不用绑定在一个特定的类型实现上Go 接口特征 很多面向对象…...

用 AI 将自拍照 P 进不同艺术作品,谷歌发布「艺术自拍 2」

1 月 24 日消息&#xff0c;谷歌旗下「艺术与文化」应用今日宣布&#xff0c;2018 年推出的「艺术自拍」功能在时隔近六年后&#xff0c;借助生成式 AI 的力量回归。官方表示&#xff0c;「艺术自拍 2」将再次使用户与艺术面对面&#xff0c;重新探访世界各地的艺术、历史和文化…...

SpringSecurity+OAuth2.0 搭建认证中心和资源服务中心

目录 1. OAuth2.0 简介 2. 代码搭建 2.1 认证中心&#xff08;8080端口&#xff09; 2.2 资源服务中心&#xff08;8081端口&#xff09; 3. 测试结果 1. OAuth2.0 简介 OAuth 2.0&#xff08;开放授权 2.0&#xff09;是一个开放标准&#xff0c;用于授权第三方应用程序…...

c# 策略模式

在 C# 中&#xff0c;策略模式是一种行为型设计模式&#xff0c;它定义了一系列算法&#xff0c;并将每个算法封装到具有公共接口的独立类中&#xff0c;使得它们可以互相替换。这样可以使得算法的选择独立于算法的使用者&#xff0c;从而提高了灵活性和可维护性。 以下是策略…...

消息队列RabbitMQ.03.死信交换机的讲解与使用

目录 一、死信队列(延迟队列) 概念讲解 二、确认消息&#xff08;局部方法处理消息&#xff09; 三、代码实战 1.编写生产者代码&#xff0c;配置消息、直连交换机、路由键 1.1代码解析&#xff1a; 2.配置消费者接受类接受直连交换机的路由键 2.1. String msg&#xff…...

人工智能原理实验4(2)——贝叶斯、决策求解汽车评估数据集

&#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1; 汽车数据集 车子具有 buying,maint,doors,persons,lug_boot and safety六种属性&#xff0c;而车子的好坏分为uncc,ucc,good and vgood四种。 &#x1f9e1;&#x1f9e1;贝叶斯求解&#x1f9e1;&#x1f9e1;…...

算力网络:未来计算资源的驱动力

文章目录 前言一、算力网络的基本概况(一)算力网络的基本概念(二)算力网络研究进展二、运营商的算力网络架构(一)算力网络基础设施构成(二)算力网络编排管理(三)能力开放三、算力网络的优势(一)弹性计算(二)降低成本(三)去中心化四、算力网络的应用场景(一)人…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别

OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

Fabric V2.5 通用溯源系统——增加图片上传与下载功能

fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

R 语言科研绘图第 55 期 --- 网络图-聚类

在发表科研论文的过程中&#xff0c;科研绘图是必不可少的&#xff0c;一张好看的图形会是文章很大的加分项。 为了便于使用&#xff0c;本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中&#xff0c;获取方式&#xff1a; R 语言科研绘图模板 --- sciRplothttps://mp.…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...