
先说结论,满足以下两点即可触发PageHelper隐式分页:
1、application.properties/application.yml中配置了pagehelper.support-methods-arguments=true
2、自定义查询对象中同时包含pageNum和pageSize属性,且可以转换成数字类型
下面从源码进行分析,为什么在进行MyBatis查询的时候,我明明没有调用PageHelper.startPage方法,但是却自动进行了分页。
1、PageHelperAutoConfiguration 自动配置类
@PostConstruct
public void addPageInterceptor() {
PageInterceptor interceptor = new PageInterceptor();
Properties properties = new Properties();
properties.putAll(this.pageHelperProperties());
properties.putAll(this.properties.getProperties());
interceptor.setProperties(properties);
Iterator var3 = this.sqlSessionFactoryList.iterator();
while(var3.hasNext()) {
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var3.next();
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
我们从PageHelper的自动配置类入手,在PageHelper的配置类中,会创建一个PageInterceptor拦截器。
2、PageInterceptor 分页拦截器
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) {
boundSql = ms.getBoundSql(parameter);
cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql);
} else {
cacheKey = (CacheKey)args[4];
boundSql = (BoundSql)args[5];
}
this.checkDialectExists();
if (this.dialect instanceof Chain) {
boundSql = ((Chain)this.dialect).doBoundSql(Type.ORIGINAL, boundSql, cacheKey);
}
List resultList;
if (!this.dialect.skip(ms, parameter, rowBounds)) {
if (this.dialect.beforeCount(ms, parameter, rowBounds)) {
Long count = this.count(executor, ms, parameter, rowBounds, (ResultHandler)null, boundSql);
if (!this.dialect.afterCount(count, parameter, rowBounds)) {
Object var12 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds);
return var12;
}
}
resultList = ExecutorUtil.pageQuery(this.dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
} else {
resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
}
Object var16 = this.dialect.afterPage(resultList, parameter, rowBounds);
return var16;
}
}
this.dialect.skip方法判断是否跳过分页,其实也就是查看是否具备分页的条件。
3、PageHelper
public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) {
if (ms.getId().endsWith("_COUNT")) {
throw new RuntimeException("在系统中发现了多个分页插件,请检查系统配置!");
} else {
Page page = this.pageParams.getPage(parameterObject, rowBounds);
if (page == null) {
return true;
} else {
if (StringUtil.isEmpty(page.getCountColumn())) {
page.setCountColumn(this.pageParams.getCountColumn());
}
this.autoDialect.initDelegateDialect(ms);
return false;
}
}
}
this.pageParams.getPage方法是从参数中获取分页信息。
4、PageParams 分页参数
public Page getPage(Object parameterObject, RowBounds rowBounds) {
Page page = PageHelper.getLocalPage();
if (page == null) {
if (rowBounds != RowBounds.DEFAULT) {
if (this.offsetAsPageNum) {
page = new Page(rowBounds.getOffset(), rowBounds.getLimit(), this.rowBoundsWithCount);
} else {
page = new Page(new int[]{rowBounds.getOffset(), rowBounds.getLimit()}, this.rowBoundsWithCount);
page.setReasonable(false);
}
if (rowBounds instanceof PageRowBounds) {
PageRowBounds pageRowBounds = (PageRowBounds)rowBounds;
page.setCount(pageRowBounds.getCount() == null || pageRowBounds.getCount());
}
} else if (parameterObject instanceof IPage || this.supportMethodsArguments) {
try {
page = PageObjectUtil.getPageFromObject(parameterObject, false);
} catch (Exception var5) {
return null;
}
}
if (page == null) {
return null;
}
PageHelper.setLocalPage(page);
}
return page;
}
如果this.supportMethodsArguments为true,也就是在application.properties/application.yml中配置了pagehelper.support-methods-arguments=true,就会执行PageObjectUtil.getPageFromObject方法,从参数中提取分页信息。
5、PageObjectUtil
public staticPage getPageFromObject(Object params, boolean required) { if (params == null) { throw new PageException("无法获取分页查询参数!"); } else if (params instanceof IPage) { IPage pageParams = (IPage)params; Page page = null; if (pageParams.getPageNum() != null && pageParams.getPageSize() != null) { page = new Page(pageParams.getPageNum(), pageParams.getPageSize()); } if (StringUtil.isNotEmpty(pageParams.getOrderBy())) { if (page != null) { page.setOrderBy(pageParams.getOrderBy()); } else { page = new Page(); page.setOrderBy(pageParams.getOrderBy()); page.setOrderByonly(true); } } return page; } else { metaObject paramsObject = null; if (hasRequest && requestClass.isAssignableFrom(params.getClass())) { try { paramsObject = metaObjectUtil.forObject(getParameterMap.invoke(params)); } catch (Exception var11) { } } else { paramsObject = metaObjectUtil.forObject(params); } if (paramsObject == null) { throw new PageException("分页查询参数处理失败!"); } else { Object orderBy = getParamValue(paramsObject, "orderBy", false); boolean hasOrderBy = false; if (orderBy != null && orderBy.toString().length() > 0) { hasOrderBy = true; } int pageNum; int pageSize; Object _count; try { Object _pageNum = getParamValue(paramsObject, "pageNum", required); _count = getParamValue(paramsObject, "pageSize", required); if (_pageNum == null || _count == null) { if (hasOrderBy) { Page page = new Page(); page.setOrderBy(orderBy.toString()); page.setOrderByonly(true); return page; } return null; } pageNum = Integer.parseInt(String.valueOf(_pageNum)); pageSize = Integer.parseInt(String.valueOf(_count)); } catch (NumberFormatException var12) { throw new PageException("分页参数不是合法的数字类型!", var12); } Page page = new Page(pageNum, pageSize); _count = getParamValue(paramsObject, "count", false); if (_count != null) { page.setCount(Boolean.valueOf(String.valueOf(_count))); } if (hasOrderBy) { page.setOrderBy(orderBy.toString()); } Object reasonable = getParamValue(paramsObject, "reasonable", false); if (reasonable != null) { page.setReasonable(Boolean.valueOf(String.valueOf(reasonable))); } Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false); if (pageSizeZero != null) { page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero))); } return page; } } }
可以看到,如果是自定义的参数对象,会将对象的属性都解析出来。如果同时存在pageNum和pageSize属性,并且能转化为数字类型,则创建并向上级返回Page对象,然后在拦截器中调用ExecutorUtil.pageQuery方法进行分页查询。
至此,就能明白为什么会触发PageHelper的隐式分页了。
PS:如果在使用MyBatis时,未对参数进行对象的封装,采用直接传多个参数的方式,如下形式:
ListgetStudents(@Param("pageNum")Integer num, @Param("pageSize")Integer size, @Param("age")Integer age);
也是可以触发隐式分页的。这是由于@Param指定的参数名为pageNum和pageSize,导致这两个参数会被提取。如果改成@Param("pageNo")和@Param("pageSize"),便不会触发。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)