跳至主要內容

若依源码解析:pagehelper和mybaties进行分页

程序员诚哥大约 5 分钟若依若依后端源码解析

若依分页使用示例

@PreAuthorize("@ss.hasPermi('system:dict:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysDictData dictData)
    {
        startPage();
        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
        return getDataTable(list);
    }

startPage()方法介绍

在BaseController中有一个startPage()方法用于设置请求分页数据

/**
     * 设置请求分页数据
     */
    protected void startPage()
    {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
        {
            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
            Boolean reasonable = pageDomain.getReasonable();
            PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
        }
    }

PageHelper.startPage方法介绍

setLocalPage是将page保存到本地线程变量里面。

/**
  * 开始分页
  *
  * @param pageNum  页码
  * @param pageSize 每页显示数量
  * @param orderBy  排序
  */
public static <E> Page<E> startPage(int pageNum, int pageSize, String orderBy) {
    Page<E> page = startPage(pageNum, pageSize);
    page.setOrderBy(orderBy);
    return page;
}
···
/**
  * 开始分页
  *
  * @param pageNum      页码
  * @param pageSize     每页显示数量
  * @param count        是否进行count查询
  * @param reasonable   分页合理化,null时用默认配置
  * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置
  */
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
    Page<E> page = new Page<E>(pageNum, pageSize, count);
    page.setReasonable(reasonable);
    page.setPageSizeZero(pageSizeZero);
    //当已经执行过orderBy的时候
    Page<E> oldPage = getLocalPage();
    if (oldPage != null && oldPage.isOrderByOnly()) {
        page.setOrderBy(oldPage.getOrderBy());
    }
    setLocalPage(page);
    return page;
}

封装分页对象

TableSupport.buildPageRequest()来将前台传递过来的分页信息记录下来封装分页对象

/**
 * 表格数据处理
 * 
 * @author ruoyi
 */
public class TableSupport
{
    /**
     * 当前记录起始索引
     */
    public static final String PAGE_NUM = "pageNum";

    /**
     * 每页显示记录数
     */
    public static final String PAGE_SIZE = "pageSize";

    /**
     * 排序列
     */
    public static final String ORDER_BY_COLUMN = "orderByColumn";

    /**
     * 排序的方向 "desc" 或者 "asc".
     */
    public static final String IS_ASC = "isAsc";

    /**
     * 分页参数合理化
     */
    public static final String REASONABLE = "reasonable";

    /**
     * 封装分页对象
     */
    public static PageDomain getPageDomain()
    {
        PageDomain pageDomain = new PageDomain();
        pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
        pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
        pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
        return pageDomain;
    }

    public static PageDomain buildPageRequest()
    {
        return getPageDomain();
    }
}

com.github.pagehelper介绍

com.github.pagehelper 是一个基于 MyBatis 的分页插件,它能够简化在数据库查询中使用分页功能的操作。

  • 在查询方法中使用分页:在需要进行分页查询的方法中,使用 PageHelper.startPage 方法来开启分页功能。示例代码如下:
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

public List<MyEntity> queryEntities(int pageNum, int pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    List<MyEntity> entities = yourMapper.queryEntities();
    PageInfo<MyEntity> pageInfo = new PageInfo<>(entities);
    return pageInfo.getList();
}

在上述示例中,pageNum 表示页码,pageSize 表示每页的数据条数。通过调用 PageHelper.startPage(pageNum, pageSize) 方法,会将当前线程绑定一个分页参数对象,这样在查询方法执行时,PageHelper 会自动对查询语句进行拦截并进行分页处理。

  • 获取分页结果:使用 PageInfo 类可以获取到分页查询的详细信息,如总记录数、总页数等。在上述示例中,通过创建 PageInfo 对象并传入查询结果集,然后通过 pageInfo.getList() 方法获取分页后的数据列表。

这样,你就可以在使用 com.github.pagehelper 进行分页查询时,简化代码的编写,并且自动处理分页的逻辑。

请注意,以上只是一个基本的使用示例,你可以根据自己的具体需求进行更多的配置和使用方式。另外,确保你选择的 com.github.pagehelper 版本与你项目中使用的 MyBatis 版本兼容。你可以在 com.github.pagehelper 的 GitHub 页面上查找更多的文档和示例代码。

集成和使用 com.github.pagehelper

如果你使用 Spring Boot 和 MyBatis-Plus(一种基于 MyBatis 的数据库操作框架),你可以按照以下步骤来集成和使用 com.github.pagehelper:

  1. 添加依赖:在你的 Spring Boot 项目中,打开 pom.xml 文件,并添加以下依赖:
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <version>最新版本号</version>
</dependency>
  1. 配置文件:在 application.properties(或 application.yml)中添加 PageHelper 的相关配置。示例配置如下:
# PageHelper 配置
pagehelper.helper-dialect=your-database-dialect
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true

其中,your-database-dialect 是你所使用的数据库方言,例如 "mysql"、"oracle" 等。

  1. 分页查询:在你的 Mapper 接口中,可以直接使用 MyBatis-Plus 提供的查询方法来实现分页查询。示例代码如下:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yourpackage.entity.MyEntity;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MyEntityMapper extends BaseMapper<MyEntity> {

    Page<MyEntity> queryEntities(Page<MyEntity> page);
}

在上述示例中,Page 类型是 com.baomidou.mybatisplus.extension.plugins.pagination 包下的分页对象,通过传入分页参数来进行分页查询。

  1. 服务层调用:在你的服务层(Service)中,调用 Mapper 接口中的分页查询方法,并传入分页参数。示例代码如下:
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yourpackage.entity.MyEntity;
import com.yourpackage.mapper.MyEntityMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyEntityService {

    private final MyEntityMapper myEntityMapper;

    @Autowired
    public MyEntityService(MyEntityMapper myEntityMapper) {
        this.myEntityMapper = myEntityMapper;
    }

    public Page<MyEntity> queryEntities(int pageNum, int pageSize) {
        Page<MyEntity> page = new Page<>(pageNum, pageSize);
        return myEntityMapper.queryEntities(page);
    }
}

在上述示例中,通过创建一个 Page 对象,并传入页码和每页数据条数,然后调用 Mapper 接口的分页查询方法。

这样,你就可以在使用 Spring Boot 和 MyBatis-Plus 的项目中,集成和使用 com.github.pagehelper 来实现分页查询功能。请注意,确保你选择的 com.github.pagehelper 版本与 MyBatis-Plus 版本兼容。

PageInterceptor进行拦截并执行分页sql

com.github.pagehelper.PageInterceptor这个类就实现了mybaties的interceptor接口,调用其中的intercept方法。

@Override
public Object intercept(Invocation invocation) throws Throwable {
    try {
        Object[] args = invocation.getArgs();
        MappedStatement ms = (MappedStatement) args[0];
        Object parameter = args[1];
        RowBounds rowBounds = (RowBounds) args[2];
        ResultHandler resultHandler = (ResultHandler) args[3];
        Executor executor = (Executor) invocation.getTarget();
        CacheKey cacheKey;
        BoundSql boundSql;
        //由于逻辑关系,只会进入一次
        if (args.length == 4) {
            //4 个参数时
            boundSql = ms.getBoundSql(parameter);
            cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
        } else {
            //6 个参数时
            cacheKey = (CacheKey) args[4];
            boundSql = (BoundSql) args[5];
        }
        checkDialectExists();

        List resultList;
        //调用方法判断是否需要进行分页,如果不需要,直接返回结果
        if (!dialect.skip(ms, parameter, rowBounds)) {
            //判断是否需要进行 count 查询
            if (dialect.beforeCount(ms, parameter, rowBounds)) {
                //查询总数
                Long count = count(executor, ms, parameter, rowBounds, resultHandler, boundSql);
                //处理查询总数,返回 true 时继续分页查询,false 时直接返回
                if (!dialect.afterCount(count, parameter, rowBounds)) {
                    //当查询总数为 0 时,直接返回空的结果
                    return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                }
            }
            resultList = ExecutorUtil.pageQuery(dialect, executor,
                    ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
        } else {
            //rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
            resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
        }
        return dialect.afterPage(resultList, parameter, rowBounds);
    } finally {
        if(dialect != null){
            dialect.afterAll();//这里将销毁threadlocal
        }
    }
}

上次编辑于:
贡献者: zccbbg