02-Mybatis实现分页查询-借助PageHelper插件

别人写的分页助手插件


如果没有使用springboot

导入依赖

image


在核心配置文件中加入拦截器

image

使用

  • 如果你使用了这个依赖,那么sql代码你就可以不用写limit
    image
  • 但是在查询之前,一定将分页功能开启,你只有开启了,你才会有机会使用人家的分页,
    注意注意,在执行分页之前一定一定开启分页功能 怎么开启?==》使用PageHelper这个类调用startPage(页号,显示的记录数),然后将页码和页数传进去
    image
  • 如何通过该插件获取分也相关的数据呢?比如总的数据记录数目等等
    ==》其实很简单,就是在你的查询语句执行结束之后自己new一个PageInfo,将你的查询结构和你的导航卡片数量传进去
    ===》什么是导航卡片?就是你前端根据你的总记录数计算出的要显示的总页数,如下图:导航的卡片是10个
    image
    代码如下:
    image
  • 那么PageInfo分页信息中存着多少信息呢??如下所示
    好的,你问的是 PageInfo 里到底存了多少分页信息,我来帮你详细拆解一下 👇

1. PageInfo 是什么

PageInfoPageHelper 提供的一个 分页结果封装类,它不仅包含了当前页的数据,还包含了与分页相关的所有元信息(比如总条数、总页数、上一页、下一页等),非常方便在前端或接口中直接使用。


2. PageInfo 中包含的信息

PageInfo 类的主要字段如下(以 PageHelper 5.x 版本为例):

字段名 类型 说明
pageNum int 当前页码
pageSize int 每页显示数量
size int 当前页实际条数(可能不足 pageSize)
startRow int 当前页第一条记录在数据库中的行号(从 1 开始)
endRow int 当前页最后一条记录在数据库中的行号
total long 总记录数
pages int 总页数
list List<T> 当前页的数据列表
prePage int 上一页页码(没有则为 0)
nextPage int 下一页页码(没有则为 0)
isFirstPage boolean 是否为第一页
isLastPage boolean 是否为最后一页
hasPreviousPage boolean 是否有上一页
hasNextPage boolean 是否有下一页
navigatePages int 导航页码数(默认 8)
navigatepageNums int[] 导航页码数组(比如 [1,2,3,4,5,6,7,8])
navigateFirstPage int 导航栏中的第一页页码
navigateLastPage int 导航栏中的最后一页页码

3. 示例代码

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public PageInfo<User> getUsers(int pageNum, int pageSize) {
        // 开启分页
        PageHelper.startPage(pageNum, pageSize);
        // 查询
        List<User> users = userMapper.selectAll();
        // 用 PageInfo 包装结果
        PageInfo<User> pageInfo = new PageInfo<>(users);

        System.out.println("当前页码: " + pageInfo.getPageNum());
        System.out.println("每页条数: " + pageInfo.getPageSize());
        System.out.println("总条数: " + pageInfo.getTotal());
        System.out.println("总页数: " + pageInfo.getPages());
        System.out.println("是否第一页: " + pageInfo.isIsFirstPage());
        System.out.println("导航页码: " + Arrays.toString(pageInfo.getNavigatepageNums()));

        return pageInfo;
    }
}

4. 返回 JSON 示例

假设查询第 2 页,每页 10 条,总共有 28 条数据:

{
  "pageNum": 2,
  "pageSize": 10,
  "size": 10,
  "startRow": 11,
  "endRow": 20,
  "total": 28,
  "pages": 3,
  "list": [...],
  "prePage": 1,
  "nextPage": 3,
  "isFirstPage": false,
  "isLastPage": false,
  "hasPreviousPage": true,
  "hasNextPage": true,
  "navigatePages": 8,
  "navigatepageNums": [1, 2, 3],
  "navigateFirstPage": 1,
  "navigateLastPage": 3
}

我们也可以使用Page类来获取分页信息

Page类是PageHelper的内部实现,继承自ArrayList,包含了基础的分页信息:
Page类核心字段和方法:

public class Page<E> extends ArrayList<E> {
    // 分页基本信息
    private int pageNum;          // 当前页码
    private int pageSize;         // 每页数量
    private long total;           // 总记录数
    private int pages;            // 总页数
    
    // 数据库相关
    private int startRow;         // 起始行号
    private int endRow;           // 结束行号
    
    // 排序相关
    private String orderBy;       // 排序字段
    
    // 计算字段
    private boolean count = true; // 是否进行count查询
    private Boolean reasonable;   // 分页合理化
    private Boolean pageSizeZero; // pageSize为0时返回所有结果
}

Page类的主要方法:

// 获取分页信息
page.getPageNum();     // 当前页码
page.getPageSize();    // 每页大小
page.getTotal();       // 总记录数
page.getPages();       // 总页数
page.getStartRow();    // 起始行
page.getEndRow();      // 结束行

// 列表操作(继承自ArrayList)
page.size();           // 当前页记录数
page.get(index);       // 获取指定位置记录

如何创建page对象?

📄 Page 对象的创建方式

  1. 通过PageHelper.startPage()自动创建(最常用)
// 方式1:基础分页
PageHelper.startPage(1, 10); // 页码,页大小
List<User> userList = userMapper.selectAllUsers();
Page<User> page = (Page<User>) userList;//这里可以强转是因为Page是ArrsyList的子类

// 方式2:带排序的分页
PageHelper.startPage(1, 10, "id desc");
List<User> userList = userMapper.selectAllUsers();
Page<User> page = (Page<User>) userList;

// 方式3:更详细的分页参数
PageHelper.startPage(1, 10, true); // 页码,页大小,是否进行count查询
List<User> userList = userMapper.selectAllUsers();
Page<User> page = (Page<User>) userList;
  1. 手动创建Page对象
// 方式1:空Page对象
Page<User> page = new Page<>();

// 方式2:指定页码和页大小
Page<User> page = new Page<>(1, 10);

// 方式3:指定页码、页大小和是否进行count查询
Page<User> page = new Page<>(1, 10, true);

// 方式4:指定页码、页大小、是否count查询和排序
Page<User> page = new Page<>(1, 10, "id desc", true);

// 方式5:从现有List创建

List<User> existingList = Arrays.asList(user1, user2, user3);
Page<User> page = new Page<>(1, 10);
page.addAll(existingList);
page.setTotal(100L); // 手动设置总数
  1. 使用PageMethod创建
// 使用PageMethod的静态方法
Page<User> page = PageMethod.startPage(1, 10)
    .doSelectPage(() -> userMapper.selectAllUsers());

那么如何创建PageInfo对象?

📋 PageInfo 对象的创建方式

  1. 从List/Page对象创建(最常用)
// 方式1:从普通List创建
List<User> userList = userMapper.selectAllUsers();
PageInfo<User> pageInfo = new PageInfo<>(userList);

// 方式2:从Page对象创建
PageHelper.startPage(1, 10);
List<User> userList = userMapper.selectAllUsers();
Page<User> page = (Page<User>) userList;
PageInfo<User> pageInfo = new PageInfo<>(page);

// 方式3:指定导航页码数量
PageInfo<User> pageInfo = new PageInfo<>(userList, 5); // 5个导航页码
  1. 使用Builder模式创建(灵活配置)
// 方式1:基础Builder
PageInfo<User> pageInfo = PageInfo.of(userList)
    .setPageNum(1)
    .setPageSize(10)
    .setTotal(100L)
    .setPages(10);

// 方式2:完整配置
PageInfo<User> pageInfo = new PageInfo.Builder<User>()
    .list(userList)
    .pageNum(1)
    .pageSize(10)
    .total(100L)
    .pages(10)
    .navigatePages(8)
    .build();
  1. 手动设置所有属性
// 创建空PageInfo并手动设置所有属性
PageInfo<User> pageInfo = new PageInfo<>();
pageInfo.setList(userList);           // 数据列表
pageInfo.setPageNum(1);               // 当前页码
pageInfo.setPageSize(10);             // 每页大小
pageInfo.setTotal(100L);              // 总记录数
pageInfo.setPages(10);                // 总页数
pageInfo.setSize(userList.size());    // 当前页记录数
pageInfo.setStartRow(1);              // 起始行
pageInfo.setEndRow(10);               // 结束行
pageInfo.setPrePage(0);               // 上一页
pageInfo.setNextPage(2);              // 下一页
pageInfo.setIsFirstPage(true);        // 是否第一页
pageInfo.setIsLastPage(false);        // 是否最后一页
pageInfo.setHasPreviousPage(false);   // 是否有上一页
pageInfo.setHasNextPage(true);        // 是否有下一页
pageInfo.setNavigatePages(8);         // 导航页码数
pageInfo.setNavigatepageNums(new int[]{1,2,3,4,5,6,7,8}); // 导航页码
pageInfo.setNavigateFirstPage(1);     // 导航第一页
pageInfo.setNavigateLastPage(8);      // 导航最后一页
  1. 使用工具方法创建
// 从Map创建(适用于从参数Map转换)
Map<String, Object> params = new HashMap<>();
params.put("list", userList);
params.put("total", 100L);
params.put("pageNum", 1);
PageInfo<User> pageInfo = PageInfoUtils.buildFromMap(params);

// 从JSON创建(适用于反序列化)
String json = "{\"pageNum\":1,\"pageSize\":10,\"total\":100}";
PageInfo<User> pageInfo = JSON.parseObject(json, new TypeReference<PageInfo<User>>(){});

Page和PageInfo如何选择

Page vs PageInfo 分页信息对比

📋 Page类中的分页信息

Page类是PageHelper的内部实现,继承自ArrayList,包含了基础的分页信息:

Page类核心字段和方法:

public class Page<E> extends ArrayList<E> {
    // 分页基本信息
    private int pageNum;          // 当前页码
    private int pageSize;         // 每页数量
    private long total;           // 总记录数
    private int pages;            // 总页数
    
    // 数据库相关
    private int startRow;         // 起始行号
    private int endRow;           // 结束行号
    
    // 排序相关
    private String orderBy;       // 排序字段
    
    // 计算字段
    private boolean count = true; // 是否进行count查询
    private Boolean reasonable;   // 分页合理化
    private Boolean pageSizeZero; // pageSize为0时返回所有结果
}

Page类的主要方法:

// 获取分页信息
page.getPageNum();     // 当前页码
page.getPageSize();    // 每页大小
page.getTotal();       // 总记录数
page.getPages();       // 总页数
page.getStartRow();    // 起始行
page.getEndRow();      // 结束行

// 列表操作(继承自ArrayList)
page.size();           // 当前页记录数
page.get(index);       // 获取指定位置记录

📊 PageInfo类中的分页信息

PageInfo是一个独立的分页信息包装类,提供了更丰富的分页导航信息:

PageInfo类核心字段和方法:

public class PageInfo<T> implements Serializable {
    // 基础分页信息(与Page相同)
    private int pageNum;          // 当前页码
    private int pageSize;         // 每页数量
    private long total;           // 总记录数
    private int pages;            // 总页数
    private List<T> list;         // 数据列表
    
    // 扩展的分页信息
    private int size;             // 当前页记录数
    
    // 行号信息
    private int startRow;         // 起始行号
    private int endRow;           // 结束行号
    
    // 页面导航信息
    private int prePage;          // 上一页页码
    private int nextPage;         // 下一页页码
    
    // 布尔状态标识
    private boolean isFirstPage;  // 是否第一页
    private boolean isLastPage;   // 是否最后一页
    private boolean hasPreviousPage; // 是否有上一页
    private boolean hasNextPage;  // 是否有下一页
    
    // 导航页码相关
    private int navigatePages;    // 导航页码数
    private int[] navigatepageNums; // 所有导航页码
    private int navigateFirstPage; // 导航条上的第一页
    private int navigateLastPage; // 导航条上的最后一页
}

🔄 Page vs PageInfo 详细对比

特性 Page PageInfo
继承关系 继承ArrayList 独立的包装类
数据存储 直接存储数据列表 通过list属性存储数据
基础分页信息 ✅ 有 ✅ 有
导航页码 ❌ 无 ✅ 完整的导航页码数组
页面状态标识 ❌ 无 ✅ 丰富的布尔状态标识
前后页信息 ❌ 无 ✅ 明确的上一页/下一页页码
使用场景 内部实现,简单分页 对外返回,完整分页需求
序列化 可能包含过多信息 专门为API设计,字段清晰

💡 实际使用对比

使用Page:

PageHelper.startPage(pageNum, pageSize);
List<User> userList = userMapper.selectAllUsers();
Page<User> page = (Page<User>) userList;

// 获取基本信息
long total = page.getTotal();      // 总记录数
int totalPages = page.getPages();  // 总页数
int currentSize = page.size();     // 当前页记录数

使用PageInfo:

PageHelper.startPage(pageNum, pageSize);
List<User> userList = userMapper.selectAllUsers();
PageInfo<User> pageInfo = new PageInfo<>(userList);

// 获取基础信息
long total = pageInfo.getTotal();           // 总记录数
int totalPages = pageInfo.getPages();       // 总页数
int currentSize = pageInfo.getSize();       // 当前页记录数

// 获取扩展的导航信息
boolean isFirst = pageInfo.isFirstPage();           // 是否第一页
boolean isLast = pageInfo.isLastPage();             // 是否最后一页
int prePage = pageInfo.getPrePage();                // 上一页页码
int nextPage = pageInfo.getNextPage();              // 下一页页码
int[] navigatePages = pageInfo.getNavigatepageNums(); // 导航页码数组

🎯 核心差异总结

Page的特点:

  • 轻量级:只包含最基本的分页信息
  • 直接数据容器:本身就是数据列表,可以直接使用
  • 内部实现:更适合在Service层内部处理
  • 信息有限:缺少导航相关的丰富信息

PageInfo的特点:

  • 功能完整:包含完整的分页导航信息
  • API友好:专门为前后端交互设计
  • 导航丰富:提供页面导航所需的所有信息
  • 推荐使用:PageHelper官方推荐对外返回的方式

✅ 选择建议

  1. 如果需要简单分页:可以使用Page,通过强制转换获得基础分页信息
  2. 如果需要完整分页(推荐):使用PageInfo,特别是需要给前端提供分页导航时
  3. API返回:总是使用PageInfo,字段清晰且完整
  4. 内部处理:可以使用Page进行简单处理,然后转换为PageInfo返回

最终建议:在大多数场景下,直接使用PageInfo是更好的选择,因为它提供了完整且标准化的分页信息,特别适合前后端分离的项目架构。


2.如果使用了springboot

好的,你想在 Spring Boot 中使用 MyBatis 的分页插件 PageHelper,我给你详细说一下 依赖导入分页拦截器配置 的步骤。


1. 导入 Maven 依赖

PageHelper 官方提供了 Spring Boot Starter,可以直接引入,不用手动配置拦截器(推荐)。

<!-- MyBatis 分页插件 PageHelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>1.4.7</version> <!-- 版本号可以去 Maven Central 查最新 -->
</dependency>

如果你不想用 starter,也可以单独引入 pagehelper 核心包:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.3</version>
</dependency>

但是这样需要自己手动配置拦截器。


2. 添加分页拦截器(两种方式)

方式一:使用 pagehelper-spring-boot-starter(自动配置)

如果你用了 starter,一般不需要手动配置拦截器,它会自动注入 PageInterceptor

你只需要在 application.ymlapplication.properties 里配置数据库方言等参数:

pagehelper:
  helper-dialect: mysql
  reasonable: true
  support-methods-arguments: true
  params: count=countSql

方式二:手动配置拦截器(不用 starter)

如果没用 starter,需要自己定义一个 @Configuration 类来注册分页插件:

import com.github.pagehelper.PageInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Properties;

@Configuration
public class MyBatisConfig {

    @Bean
    public PageInterceptor pageInterceptor() {
        PageInterceptor interceptor = new PageInterceptor();
        Properties properties = new Properties();
        // 指定数据库方言
        properties.setProperty("helperDialect", "mysql");
        // 合理化分页参数
        properties.setProperty("reasonable", "true");
        interceptor.setProperties(properties);
        return interceptor;
    }
}

3. 使用示例

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    public Page<User> getUsers(int pageNum, int pageSize) {
        // 开始分页
        PageHelper.startPage(pageNum, pageSize);
        // 后续的第一个 MyBatis 查询会自动分页
        List<User> users = userMapper.selectAll();
        // 用 Page 接收结果,可以获取分页信息
        return (Page<User>) users;
    }
}

4. 注意事项

  • PageHelper.startPage 方法必须紧挨着需要分页的查询方法,中间不能有其他 MyBatis 方法调用,否则分页会失效。
  • 如果是多数据源,需要确保拦截器配置在对应 SqlSessionFactory 里。
  • 数据库方言(helperDialect)要配置正确,比如 mysqlpostgresqloracle 等。

✅ 如果你用 Spring Boot + MyBatis,我建议直接用 pagehelper-spring-boot-starter,几乎零配置就能用。


Page和PageInfo的构造方法创建方式的对比

Page 和 PageInfo 构造方法参数详解

📄 Page 构造方法参数详解

1. 无参构造方法

Page<E> page = new Page<>();

作用:创建空的Page对象
包含属性

  • pageNum = 1(默认页码)
  • pageSize = 0(默认页大小)
  • total = 0(总记录数)
  • pages = 0(总页数)
  • 空的ArrayList数据容器

2. 页码 + 页大小构造方法

Page<E> page = new Page<>(int pageNum, int pageSize);

参数作用

  • pageNum:当前页码(从1开始)
  • pageSize:每页显示的记录数

包含属性

  • 设置指定的页码和页大小
  • 其他属性保持默认值

3. 页码 + 页大小 + 是否count构造方法

Page<E> page = new Page<>(int pageNum, int pageSize, boolean count);

参数作用

  • pageNum:当前页码
  • pageSize:每页记录数
  • count:是否进行count查询(true=查询总数,false=不查询)

包含属性

  • 设置分页基本参数
  • 控制是否进行总数统计

4. 完整参数构造方法

Page<E> page = new Page<>(int pageNum, int pageSize, String orderBy, boolean count);

参数作用

  • pageNum:当前页码
  • pageSize:每页记录数
  • orderBy:排序字段(如:"id DESC, name ASC")
  • count:是否进行count查询

包含属性

  • 完整的分页和排序参数
  • 包含排序信息

📋 PageInfo 构造方法参数详解

1. 无参构造方法

PageInfo<E> pageInfo = new PageInfo<>();

作用:创建空的PageInfo对象
包含属性:所有属性均为默认值(null、0、false等)

2. List数据构造方法(最常用)

PageInfo<E> pageInfo = new PageInfo<>(List<E> list);

参数作用

  • list:当前页的数据列表

包含属性

  • list = 传入的数据列表
  • 自动计算:sizestartRowendRow
  • 其他分页信息需要后续设置

3. List数据 + 导航页码数构造方法

PageInfo<E> pageInfo = new PageInfo<>(List<E> list, int navigatePages);

参数作用

  • list:当前页的数据列表
  • navigatePages:导航页码显示数量(如:5显示5个页码)

包含属性

  • 包含所有基础分页信息
  • 设置导航页码数量,影响navigatepageNums数组

🔄 构造方法对比总结

Page 构造方法特点:

构造方法 核心参数 创建的对象特点
Page() 空Page对象,需要手动设置所有属性
Page(pageNum, pageSize) 页码、页大小 基础分页参数设置
Page(pageNum, pageSize, count) 页码、页大小、是否统计 控制是否查询总数
Page(pageNum, pageSize, orderBy, count) 完整参数 包含排序的完整分页对象

PageInfo 构造方法特点:

构造方法 核心参数 创建的对象特点
PageInfo() 空PageInfo,需要手动设置所有属性
PageInfo(list) 数据列表 包含数据,自动计算基础分页信息
PageInfo(list, navigatePages) 数据列表、导航页数 完整的分页导航对象

💡 实际应用建议

创建Page的推荐场景:

// 场景1:手动创建分页对象
Page<User> page = new Page<>(1, 10, "create_time DESC", true);

// 场景2:通过PageHelper自动创建(最常用)
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll();
Page<User> page = (Page<User>) list; // 实际使用时转换

创建PageInfo的推荐场景:

// 场景1:从查询结果直接创建(最常用)
PageHelper.startPage(1, 10);
List<User> list = userMapper.selectAll();
PageInfo<User> pageInfo = new PageInfo<>(list, 5); // 5个导航页码

// 场景2:手动创建完整分页信息
PageInfo<User> pageInfo = new PageInfo<>();
pageInfo.setList(userList);
pageInfo.setPageNum(1);
pageInfo.setPageSize(10);
pageInfo.setTotal(100L);
pageInfo.setPages(10);

🎯 核心区别总结

  • Page:主要是数据容器 + 基础分页参数
  • PageInfo:主要是分页信息包装器 + 完整导航信息

选择建议

  • 内部处理数据时可以使用Page
  • 返回给前端的API统一使用PageInfo
  • 大多数情况下推荐直接使用new PageInfo<>(list, navigatePages)
posted on 2025-10-10 15:17  笨忠  阅读(126)  评论(0)    收藏  举报