粗解PageHelper分页逻辑——分页参数的获取与传递(线程局部变量)
【摘要】 PageHelper对线程局部变量的妙用
起因
在学习若依管理系统的过程中,发现其系统的几乎没有分页的代码,很是疑惑。发现其使用了一个名为PageHelper的中间件,通过实现mybatis拦截器,拦截执行分页SQL,从而来实现后台分页功能,那么这个PageHelper的实现原理是什么样的?我们来粗略的探究一下。
参数获取与传递与保存
在学习的过程中,发现若依系统中出现分页时,在Controller层并没有编写如下获取分页参数的方法,例如:
@PreAuthorize("@ss.hasPermi('monitor:oper:list')")
@GetMapping("/list")
public TableDataInfo list(SysOper oper) {
startPage();
// ....
}
那么分页参数是如何获取的呢?又是如何传递给后续SQL的呢?
我们发现每次分页都与startPage()
方法有关,猜测分页参数大概是在startPage()函数中获取的。看一下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);
}
}
可以清楚地看到其中有两行:
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
查看其基础逻辑为通过TableSupport.buildPageRequest()
构造一个PageDomain
对象,其中通过:
getRequest().getParameter(name);
达到获取请求中的分页参数的目的。
那么后续分页参数是如何传递的呢?
作者使用了一个非常巧妙的对象:ThreadLocal
。通过使用ThreadLocal保存分页的参数,以便后续使用。这个对象通常被称为线程局部变量。
我们来看一下逐层的逻辑,上述的startPage
在最后一句调用:
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
其方法内部为:
/**
* 基础分页方法
*
* @author liuzh
*/
public abstract class PageMethod {
/**
* 开始分页
*
* @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;
}
}
其中的关键是getLocalPage
以及setLocalPage
,我们来看一下这两个方法:
/**
* 基础分页方法
*
* @author liuzh
*/
public abstract class PageMethod {
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
/**
* 设置 Page 参数
*
* @param page
*/
protected static void setLocalPage(Page page) {
LOCAL_PAGE.set(page);
}
/**
* 获取 Page 参数
*
* @return
*/
public static <T> Page<T> getLocalPage() {
return LOCAL_PAGE.get();
}
}
在使用时,即可通过getLocalPage()
方法获取到分页相关的参数。
总结
线程局部变量之前我只在阿里巴巴的日期格式化编码规范中见过,没想到线程局部变量的功能会如此强大与巧妙。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)