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

news2024/9/28 5:34:41

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 {

    @Override
    public 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());
        else
            totalSql += 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.coloradmin.cn/o/1486061.html

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

相关文章

八. 实战:CUDA-BEVFusion部署分析-分析BEVFusion中各个ONNX

目录 前言0. 简述1. camera.backbone.onnx(fp16)2. camera.backbone.onnx(int8)3. camera.vtransform.onnx(fp16)4. fuser.onnx(fp16)5. fuser.onnx(int8)6. lidar.backbone.xyz.onnx7. head.bbox.onnx(fp16)总结下载链接参考 前言 自动驾驶之心推出的《CUDA与TensorRT部署实战…

【C++】vector的使用和模拟实现(超级详解!!!!)

文章目录 前言1.vector的介绍及使用1.1 vector的介绍1.2 vector的使用1.2.1 vector的定义1.2.2 vector iterator 的使用1.2.3 vector 空间增长问题1.2.3 vector 增删查改1.2.4 vector 迭代器失效问题。&#xff08;重点!!!!!!&#xff09;1.2.5 vector 在OJ中有关的练习题 2.ve…

蓝桥杯倒计时 41天 - KMP 算法

KMP算法 KMP算法是一种字符串匹配算法&#xff0c;用于匹配模式串P在文本串S中出现的所有位置。 例如S“ababac&#xff0c;P“aba”&#xff0c;那么出现的所有位置是13。 在初学KMP时&#xff0c;我们只需要记住和学会使用模板即可&#xff0c;对其原理只需简单理解&#xff…

WiFi模块引领智能家居革命:连接未来的生活

随着科技的快速发展&#xff0c;智能家居正成为现代生活的一部分&#xff0c;极大地改变了我们与家庭环境互动的方式。其中&#xff0c;WiFi模块作为关键的连接技术&#xff0c;在推动智能家居革命中发挥着不可忽视的作用。本文将深入探讨WiFi模块如何驱动智能家居革命。 设备互…

Maven实战(2)之搭建maven私服

一, 背景: 如果使用国外镜像,下载速度比较慢; 如果使用阿里云镜像,速度还算OK,但是假如网速不好的时候,其实也是比较慢的; 如果没有网的情况下更加下载不了. 二, 本地仓库、个人/公司私服、远程仓库关系如下: 三, 下载安装nexus私服 略

如何在Window系统部署VisualSVN服务并结合cpolar实现无公网ip远程访问

文章目录 前言1. VisualSVN安装与配置2. VisualSVN Server管理界面配置3. 安装cpolar内网穿透3.1 注册账号3.2 下载cpolar客户端3.3 登录cpolar web ui管理界面3.4 创建公网地址 4. 固定公网地址访问 前言 SVN 是 subversion 的缩写&#xff0c;是一个开放源代码的版本控制系统…

Mixtral模型解读

Mixtral 8x7B(Mistral MoE) 1.Mistral 7B模型 Mistral 7B模型与Llama2 7B模型结构整体上是相似的&#xff0c;其结构参数如下所示。 细节上来说&#xff0c;他有两点不同。 1.1SWA(Sliding Window Attention) ​ 一般的Attention来说&#xff0c;是Q与KV-Cache做内积&#…

23端口登录的Telnet命令+传输协议FTP命令

一、23端口登录的Telnet命令 Telnet是传输控制协议/互联网协议&#xff08;TCP/IP&#xff09;网络&#xff08;如Internet&#xff09;的登录和仿真程序&#xff0c;主要用于Internet会话。基本功能是允许用户登录进入远程主机程序。 常用的Telnet命令 Telnet命令的格式为&…

基础算法(四)(递归)

1.递归算法的介绍&#xff1a; 概念&#xff1a;递归是指函数直接或间接调用自身的过程。 解释递归的两个关键要素&#xff1a; 基本情况&#xff08;递归终止条件&#xff09;&#xff1a;递归函数中的一个条件&#xff0c;当满足该条件时&#xff0c;递归终止&#xff0c;避…

C++11中的auto、基于范围的for循环、指针空值nullptr

目录 auto关键字 使用原因 历史背景 C11中的auto auto的使用案例 auto 指针/引用 同一行定义多个变量 typeid关键字 基于范围的for循环 范围for的语法 范围for的使用条件 指针空值nullptr C98中的指针空值 C11中的指针空值 auto关键字 使用原因 随着程序越…

Decoupled Knowledge Distillation解耦知识蒸馏

Decoupled Knowledge Distillation解耦知识蒸馏 现有的蒸馏方法主要是基于从中间层提取深层特征&#xff0c;而忽略了Logit蒸馏的重要性。为了给logit蒸馏研究提供一个新的视角&#xff0c;我们将经典的KD损失重新表述为两部分&#xff0c;即目标类知识蒸馏&#xff08;TCKD&a…

JavaSec 基础之五大不安全组件

文章目录 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4jLog4jShiroJacksonFastJsonXStream 不安全组件(框架)-Shiro&FastJson&Jackson&XStream&Log4j Log4j Apache的一个开源项目&#xff0c;是一个基于Java的日志记录框架。 历史…

python学习笔记------元组

元组的定义 定义元组使用小括号&#xff0c;且使用逗号隔开各个数据&#xff0c;数据是不同的数据类型 定义元组字面量&#xff1a;(元素,元素,元素,......,元素) 例如&#xff1a;(1,"hello") 定义元组变量&#xff1a;变量名称(元素,元素,元素,......,元素)…

哈希表是什么?

一、哈希表是什么&#xff1f; 哈希表&#xff0c;也称为散列表&#xff0c;是一种根据关键码值&#xff08;Key value&#xff09;直接进行访问的数据结构。它通过把关键码值映射到表中一个位置来访问记录&#xff0c;从而加快查找速度。这个映射函数叫做散列函数&#xff08…

C#与VisionPro联合开发——单例模式

单例模式 单例模式是一种设计模式&#xff0c;用于确保类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。单例模式通常用于需要全局访问一个共享资源或状态的情况&#xff0c;以避免多个实例引入不必要的复杂性或资源浪费。 Form1 的代码展示 using System; usi…

初阶数据结构之---栈和队列(C语言)

引言 在顺序表和链表那篇博客中提到过&#xff0c;栈和队列也属于线性表 线性表&#xff1a; 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构。线性表在逻辑上是线性结构&#xff0c;也就是说是连…

c++之拷贝构造和赋值

如果一个构造函数中的第一个参数是类本身的引用&#xff0c;或者是其他的参数都有默认值&#xff0c;则该构造函数为拷贝构造函数。 那么什么是拷贝构造呢&#xff1f;利用同类对象构造一个新对象。 1&#xff0c;函数名和类必须同名。 2&#xff0c;没有返回值。 3&#x…

差分题练习(区间更新)

一、差分的特点和原理 对于一个数组a[]&#xff0c;差分数组diff[]的定义是: 对差分数组做前缀和可以还原为原数组: 利用差分数组可以实现快速的区间修改&#xff0c;下面是将区间[l, r]都加上x的方法: diff[l] x; diff[r 1] - x;在修改完成后&#xff0c;需要做前缀和恢复…

4.关联式容器

关联式container STL中一些常见的容器&#xff1a; 序列式容器&#xff08;Sequence Containers&#xff09;&#xff1a; vector&#xff08;动态数组&#xff09;&#xff1a; 动态数组&#xff0c;支持随机访问和在尾部快速插入/删除。list&#xff08;链表&#xff09;&am…

奇舞周刊第521期:“一切非 Rust 项目均为非法”

奇舞推荐 ■ ■ ■ 拜登&#xff1a;“一切非 Rust 项目均为非法” 科技巨头要为Coding安全负责。这并不是拜登政府对内存安全语言的首次提倡。“程序员编写代码并非没有后果&#xff0c;他们的⼯作⽅式于国家利益而言至关重要。”白宫国家网络总监办公室&#xff08;ONCD&…