SpringBoot优雅的实现分页功能及原理简析(转载)

前言
分页功能是我们开发过程中常见的一个小功能,如何快速高效的实现一个分页功能呢。本文将带领大家快速搭建一个分页功能。

引入依赖

com.github.pagehelper
pagehelper
5.1.2

实体封装
接收分页参数实体封装
需要分页的实体继承该实体,用以接收分页的参数

public class BasePageReqListMsg {

protected final static int SIZE = 20;
protected final static int NO = 1;

protected int pageNum=NO;
protected int pageSize = SIZE;

public static int getInitSize() {
    return SIZE;
}


public int getPageNum() {
    return pageNum;
}


public int getPageSize() {
    return pageSize;
}


public int getStartIndex() {
    return (getPageNum() - 1) * this.pageSize;
}

public int getEndIndex() {
    return getPageNum() * this.pageSize;
}

}
封装返回分页实体
该实体将分页数据封装,返给前端

@Data
public class PageResult {

private Integer pageNum;

private Integer pageSize;

private Long total;

private List<T> list;

public PageResult() {

}

public PageResult(Integer pageNum, Integer pageSize, Long total, List<T> list) {
    this.pageNum = pageNum;
    this.pageSize = pageSize;
    this.total = total;
    this.list = list;
}

public static PageResult getResult(int pageNum, int pageSize, long total, List result) {
    return new PageResult(pageNum, pageSize, total, result);
}

public static PageResult getResult(int pageNum, int pageSize) {
    return new PageResult(pageNum, pageSize, 0L, new ArrayList());
}

}
分页查询
public PageResult queryByParamPageList(QueryDTO queryDTO) {
PageHelper.startPage(queryDTO.getPageNum(), queryDTO.getPageSize());
List users= userMapper.selectByParam(queryDTO);
PageInfo pageInfo = new PageInfo<>(users);
return new PageResult<>(pageInfo.getPageNum(), pageInfo.getPageSize(), pageInfo.getTotal(), users);
}
源码讲解
分页是从这个方法开始的

/**

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

https://blog.csdn.net/zhangzijiejiayou/article/details/103425789

protected static final ThreadLocal LOCAL_PAGE = new ThreadLocal();
protected static boolean DEFAULT_COUNT = true;

/**

  • 设置 Page 参数
  • @param page
    */
    protected static void setLocalPage(Page page) {
    LOCAL_PAGE.set(page);
    }

/**

  • 获取 Page 参数
  • @return
    */
    public static Page getLocalPage() {
    return LOCAL_PAGE.get();
    }
    PageInterceptor是分页的核心实现了mybatis的拦截器Interceptor,进行分页拦截和频接核心方法如下

public class PageInterceptor implements Interceptor {
//缓存count查询的ms
protected Cache<String, MappedStatement> msCountMap = null;
private Dialect dialect;
private String default_dialect_class = “com.github.pagehelper.PageHelper”;
private Field additionalParametersField;
private String countSuffix = “_COUNT”;

@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];
}
List resultList;
//调用方法判断是否需要进行分页,如果不需要,直接返回结果
if (!dialect.skip(ms, parameter, rowBounds)) {
//反射获取动态参数
String msId = ms.getId();
Configuration configuration = ms.getConfiguration();
Map<String, Object> additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
//判断是否需要进行 count 查询
if (dialect.beforeCount(ms, parameter, rowBounds)) {
String countMsId = msId + countSuffix;
Long count;
//先判断是否存在手写的 count 查询
MappedStatement countMs = getExistedMappedStatement(configuration, countMsId);
if(countMs != null){
count = executeManualCount(executor, countMs, parameter, boundSql, resultHandler);
} else {
countMs = msCountMap.get(countMsId);
//自动创建
if (countMs == null) {
//根据当前的 ms 创建一个返回值为 Long 类型的 ms
countMs = MSUtils.newCountMappedStatement(ms, countMsId);
msCountMap.put(countMsId, countMs);
}
count = executeAutoCount(executor, countMs, parameter, boundSql, rowBounds, resultHandler);
}
//处理查询总数
//返回 true 时继续分页查询,false 时直接返回
if (!dialect.afterCount(count, parameter, rowBounds)) {
//当查询总数为 0 时,直接返回空的结果
return dialect.afterPage(new ArrayList(), parameter, rowBounds);
}
}
//判断是否需要进行分页查询
if (dialect.beforePage(ms, parameter, rowBounds)) {
//生成分页的缓存 key
CacheKey pageKey = cacheKey;
//处理参数对象
parameter = dialect.processParameterObject(ms, parameter, boundSql, pageKey);
//调用方言获取分页 sql
String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, pageKey);
BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);
//设置动态参数
for (String key : additionalParameters.keySet()) {
pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key));
}
//执行分页查询
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, pageKey, pageBoundSql);
} else {
//不执行分页的情况下,也不执行内存分页
resultList = executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql);
}
} else {
//rowBounds用参数值,不使用分页插件处理时,仍然支持默认的内存分页
resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
return dialect.afterPage(resultList, parameter, rowBounds);
} finally {
dialect.afterAll();
}
}
参考
http://www.dengb.com/Javabc/1381088.html

原文链接:https://blog.csdn.net/zhangzijiejiayou/article/details/107706207?utm_medium=distribute.pc_feed.none-task-blog-personrec_tag-4.nonecase&depth_1-utm_source=distribute.pc_feed.none-task-blog-personrec_tag-4.nonecase&request_id=5f2489ee2405af26f814c7f7

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值