mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器

mybatis开发一个分页插件、mybatis实现分页、mybatis拦截器

通过官网的mybatis插件说明可知,我们可以通过拦截器进行开发一个插件。

例如这样的:

        UserMapper mapper = sqlSession.getMapper(UserMapper.class);// 开始分页MagicPage.startPage(1, 3);// 查询List<UserEntity> list = mapper.selectAll();System.out.println(list);// 获取到分页的内容PageInfo page = MagicPage.getPage();System.out.println(page);

格式就是通过线程变量来实现

MagicPage.start(page,size);
// 执行查询
...
MagicPage.getPage();

先编写一个 MagicPage

import cn.hutool.core.lang.Assert;/*** @author lingkang* Created by 2024/3/3*/
public class MagicPage {private static final ThreadLocal<PageInfo> local = new ThreadLocal<>();/*** 开始分页** @param page 默认 1* @param size 默认 10*/public static void startPage(int page, int size) {Assert.isTrue(page > 0, "page 最小值为 1");Assert.isTrue(size > 0, "size 必须大于 0");PageInfo info = new PageInfo();info.setSize(size);info.setPage(page);local.set(info);}public static PageInfo getPage() {return local.get();}public static void removePage() {local.remove();}
}

PageInfo

@Data
public class PageInfo {private int size;private int page;private long total;
}

mybatis插件实现:

import cn.hutool.core.convert.BasicType;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
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 java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 查询分页拦截** @author lingkang* Created by 2024/3/3*/
@Intercepts({@Signature(type = StatementHandler.class,method = "prepare",args = {Connection.class, Integer.class})})
public class MagicPageInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {PageInfo page = MagicPage.getPage();if (page == null)return invocation.proceed();StatementHandler statementHandler = (StatementHandler) invocation.getTarget();BoundSql boundSql = statementHandler.getBoundSql();if (!boundSql.getSql().toLowerCase().contains("select")) {return invocation.proceed();}Connection conn = (Connection) invocation.getArgs()[0];String totalSql = "select count(*) ";TotalConvert convert = pageSql(boundSql.getSql());if (convert.getOrderIndex() != 0)totalSql += boundSql.getSql().substring(convert.getTotalIndex()) + boundSql.getSql().substring(convert.getOrderIndex());elsetotalSql += boundSql.getSql().substring(convert.getTotalIndex());PreparedStatement statement = conn.prepareStatement(totalSql);Object parameterObject = boundSql.getParameterObject();// 设置参数if (parameterObject != null) {if (parameterObject.getClass().isPrimitive() || BasicType.WRAPPER_PRIMITIVE_MAP.containsKey(parameterObject.getClass())) {statement.setObject(1, parameterObject);} else if (parameterObject.getClass().isArray()) {Object[] arr = (Object[]) parameterObject;for (int i = 1; i <= arr.length; i++)statement.setObject(i, arr[i]);} else if (parameterObject instanceof Collection) {int i = 1;for (Object o : (Collection) parameterObject)statement.setObject(i++, o);} else if (parameterObject instanceof Map) {Map map = (Map) parameterObject;int i = 1;for (ParameterMapping mapping : boundSql.getParameterMappings())statement.setObject(i++, map.get(mapping.getProperty()));} else {// 将它当成对象int i = 1;for (ParameterMapping mapping : boundSql.getParameterMappings()) {Field field = parameterObject.getClass().getDeclaredField(mapping.getProperty());field.setAccessible(true);statement.setObject(i++, field.get(parameterObject));}}}ResultSet resultSet = statement.executeQuery();if (resultSet.next()) {long total = resultSet.getLong(1);page.setTotal(total);resultSet.close();}if (page.getTotal() > 0) {// 存在分页String sql = boundSql.getSql() + " limit " + (page.getPage() - 1) * page.getSize() + "," + page.getSize();Field field = BoundSql.class.getDeclaredField("sql");field.setAccessible(true);field.set(boundSql, sql);}return invocation.proceed();}Pattern orderBy = Pattern.compile("order\\s+by");/*** select id,(select username from user where id=t_order.userid) as username from t_order order by id desc*/private TotalConvert pageSql(String sql) {TotalConvert convert = new TotalConvert();sql = sql.toLowerCase();int index = sql.indexOf("from");int start = sql.substring(0, index).indexOf("(");while (start != -1) {start = sql.indexOf("(", start + 1);if (start == -1)index = sql.indexOf("from", index + 1);}convert.setTotalIndex(index);// 匹配排序,可能存在排序,需要特殊处理Matcher matcher = orderBy.matcher(sql);if (matcher.find()) {convert.setOrderIndex(matcher.start());}return convert;}
}

需要注意,上面的插件只是做了mysql语法下的分页,如果是sqlserver以及其他数据库需要做调整

配置我们的插件

// 将拦截器添加到配置
configuration.addInterceptor(new MagicPageInterceptor());

执行效果:
在这里插入图片描述

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

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

相关文章

Javascript:类型转换

一、前言 prompt与表达单取过来的值默认为string类型 二、正文 1.隐式转换 某些运算符被执行的时候&#xff0c;系统内部自动将数据类型进行转换。 规则&#xff1a; 好两边只要有一个是字符串&#xff0c;都会把另外一个转成字符串。 除了以外的算术运算符&#xff0c;比如…

Linux:线程的概念

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 前言一、线程的概念线程代码的简单示例 总结 前言 本文是对于线程概念的知识总结 一、线程的概念 在课本上&#xff0c;线程是比进程更轻量级的一种指向流 或 线程是在…

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行

VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行功能&#xff0c;即滚动 UI 显示当前源代码范围。便于在代码行数比较多的时候更好的知道自己所在的位置。粘性滚动UI 显示用户在滚动期间所处的范围&#xff0c;将显示编辑器顶部所在的类/接口/命名空间/函数/方法/构造函数&a…

4、Linux-常用命令(二)

目录 一、搜索命令 1、命令搜索命令 2、文件搜索命令find。格式&#xff1a;find [搜索范围] [搜索条件]。 3、字符串搜索命令grep 二、帮助命令 1、man【详细的帮助】 2、--help【简要的帮助】 三、压缩与解压命令 1、.zip格式 2、.gz格式 3、打包 四、关机和重启命…

【大厂AI课学习笔记NO.57】(10)分类任务的评价指标

我们实际做的是一个分类任务。 在人工智能深度学习项目中&#xff0c;分类任务是指一种特定的任务类型&#xff0c;即预测结果是离散值的任务。具体来说&#xff0c;分类任务的目标是将输入数据划分到不同的类别中。这些类别可以是二分类&#xff08;如垃圾邮件分类&#xff0c…

理解这几个安全漏洞,你也能做安全测试

01 短信炸弹 1、漏洞描述 短信轰炸攻击是常见的一种攻击&#xff0c;攻击者通过网站页面中所提供的发送短信验证码的功能处&#xff0c;通过对其发送数据包的获取后&#xff0c;进行重放&#xff0c;如果服务器短信平台未做校验的情况时&#xff0c;系统会一直去发送短信&…

函数式响应式编程(FRP):构筑灵活动态的应用程序

FRP&#xff08;Functional Reactive Programming&#xff0c;函数式响应式编程&#xff09;是一个编程范式&#xff0c;它结合了函数式编程和响应式编程的原则&#xff0c;用于处理时间变化的数据和响应性系统。FRP 让开发者能够以声明式地方式来构建响应用户输入、网络请求或…

【vue3 路由使用与讲解】vue-router : 简洁直观的全面介绍

# 核心内容介绍 路由跳转有两种方式&#xff1a; 声明式导航&#xff1a;<router-link :to"...">编程式导航&#xff1a;router.push(...) 或 router.replace(...) &#xff1b;两者的规则完全一致。 push(to: RouteLocationRaw): Promise<NavigationFailur…

JVM内部世界(内存划分,类加载,垃圾回收)

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;JVM内部世界(内存划分,类加载,垃圾回收) 关于JVM的学习主要掌握三方面: JVM内存区的划分类加载垃圾回收 一.JVM内存区的划分 当一个Java进程开始执行时,JVM会首先向操作系统申…

实例驱动计算机网络

文章目录 计算机网络的层次结构应用层DNSHTTP协议HTTP请求响应过程 运输层TCP协议TCP协议面向连接实现TCP的三次握手连接TCP的四次挥手断开连接 TCP协议可靠性实现TCP的流量控制TCP的拥塞控制TCP的重传机制 UDP协议 网际层IP协议&#xff08;主机与主机&#xff09;IP地址的分类…

php 读取文件并以文件方式下载

if (!file_exists($filename)){//判断能否获取这个文件header("Content-type: text/html; charset=utf-8");echo "File not found!";exit

【创作回顾】17个月峥嵘创作史

#里程碑专区#、#创作者纪念日# 还记得 2022 年 10 月 05 日&#xff0c;我在CSDN撰写了第 1 篇博客——《关于测试工程师瓶颈和突围的一个思考》&#xff0c;也是我在全网发布的第一篇技术文章。 回想当时&#xff0c;这一篇的诞生过程并不轻松&#xff0c;不像是一篇网络文章…

【计算机网络】深度学习HTTPS协议

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【计算机网络】深度学习HTTPS协议 &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 一:HTTPS是什么二:HTTPS的工作过程三:对称加密四:非对称加密五:中间人攻击1…

【web | CTF】BUUCTF [HCTF 2018]WarmUp

天命&#xff1a;这题本地php代码是无法复现的 首先打开网站&#xff0c;啥也没有&#xff0c;查看源码 发现文件&#xff0c;打开访问一下看看&#xff0c;发现是代码审计 <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whit…

【学习总结】什么是DoS和DDoS

[Q&A] 什么是DoS DoS 是 “Denial of Service”&#xff08;拒绝服务&#xff09;的缩写&#xff0c;它是一种网络攻击方式&#xff0c;其目的是使目标计算机或网络资源无法为合法用户提供正常的服务。通过向目标系统发送大量请求、消耗其带宽、处理器或内存等资源&#…

13 双口 RAM IP 核

双口 RAM IP 核简介 双口 RAM IP 核有两个端口&#xff0c;它又分为伪双端口 RAM 和真双端口 RAM&#xff0c;伪双端口 RAM 一个端口只能读&#xff0c;另一个端口只能 写&#xff0c;真双端口 RAM 两个端口都可以进行读写操作。同时对存储器进行读写操作时就会用到双端口 RAM…

unity-1

创建游戏对象&#xff08;游戏物体&#xff09; 可通过unity中的菜单栏中的Gameobject创建&#xff1b;也可在Hierarchy&#xff08;层级&#xff09;中创建&#xff0c; 双击即可居中看到。 在Hierarchy空白处右键即可看到&#xff0c;能创建游戏对象。 在Scene框中&#x…

BioTech - ADMET的性质预测 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136438192 ADMET&#xff0c;即 Absorption、Distribution、Metabolism、Excretion、Toxicity&#xff0c;吸收、分布、代谢、排泄、毒性…

题目 1629: 蓝桥杯算法训练VIP-接水问题

题目描述: 学校里有一个水房&#xff0c;水房里一共装有m个龙头可供同学们打开水&#xff0c;每个龙头每秒钟的供水量相等&#xff0c;均为1。现在有n名同学准备接水&#xff0c;他们的初始接水顺序已经确定。将这些同学按接水顺序从1到n编号&#xff0c;i号同学的接水量为wi。…

Linux shell:补充命令的使用

目录 一.导读 二.正文 三.结语 一.导读 上一篇介绍了脚本的简单概念以及使用&#xff0c;现在补充一些命令。 二.正文 目前处于全局目录&#xff0c;通过mkdir创建名我为day01的文件。 通过cd命令day01 切换至day01文件当中。 使用vim文本编辑器文件名&#xff08;firstdir&…