1.构建 通用分页 DTO
public class PageParam<T> {
/**
* 每几页
*/
@ApiModelProperty(value = "每几页")
private int pageNum;
/**
* 每页大小
*/
@ApiModelProperty(value = "每页大小")
private int pageSize;
public int getPageNum() {
return pageNum;
}
@ApiModelProperty(value = "关键字")
private String keywords;
@ApiModelProperty(value = "排序字段")
private String orderBy;
@ApiModelProperty(value = "是否查询总条数")
private YesNoEnum isCount;
public <T> Page<T> buildPage() {
return buildPage(false);
}
public <T> Page<T> buildPage(boolean count) {
if (this.pageNum == 0) {
this.pageNum = 1;
}
if (this.pageSize == 0) {
this.pageSize = 15;
}
// 如果为否,则不查询总条件
if (YesNoEnum.NO.equals(isCount)) {
count = false;
}
// 传入:PageHelper
Page<T> page = PageHelper.startPage(this.pageNum, this.pageSize, count);
if (!StringUtil.isStringParamNotLegal(orderBy)) {
if (checkOrderBy(orderBy)) {
page.setOrderBy(orderBy);
}
}
return page;
}
2.传入: 分页参数 --> 传入:PageHelper Page page = PageHelper.startPage(this.pageNum, this.pageSize, count);
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) {
return startPage(pageNum, pageSize, count, (Boolean)null, (Boolean)null);
}
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
Page<E> page = new Page(pageNum, pageSize, count);
page.setReasonable(reasonable);
page.setPageSizeZero(pageSizeZero);
Page<E> oldPage = getLocalPage();
if (oldPage != null && oldPage.isOrderByOnly()) {
page.setOrderBy(oldPage.getOrderBy());
}
setLocalPage(page);
return page;
}
- 将分页参数放进 ThreadLocal LOCAL_PAGE setLocalPage(page);
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal();
-
Mybatis - 通用分页拦截器
@Intercepts(
{
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
}
)
public class PageInterceptor implements Interceptor {
@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();
}
}
}
5.针对 PageHelper 的实现
@Override
public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) {
//处理参数
Page page = getLocalPage();
//如果只是 order by 就不必处理参数
if (page.isOrderByOnly()) {
return parameterObject;
}
Map<String, Object> paramMap = null;
if (parameterObject == null) {
paramMap = new HashMap<String, Object>();
} else if (parameterObject instanceof Map) {
//解决不可变Map的情况
paramMap = new HashMap<String, Object>();
paramMap.putAll((Map) parameterObject);
} else {
paramMap = new HashMap<String, Object>();
//动态sql时的判断条件不会出现在ParameterMapping中,但是必须有,所以这里需要收集所有的getter属性
//TypeHandlerRegistry可以直接处理的会作为一个直接使用的对象进行处理
boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());
MetaObject metaObject = MetaObjectUtil.forObject(parameterObject);
//需要针对注解形式的MyProviderSqlSource保存原值
if (!hasTypeHandler) {
for (String name : metaObject.getGetterNames()) {
paramMap.put(name, metaObject.getValue(name));
}
}
//下面这段方法,主要解决一个常见类型的参数时的问题
if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) {
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
String name = parameterMapping.getProperty();
if (!name.equals(PAGEPARAMETER_FIRST)
&& !name.equals(PAGEPARAMETER_SECOND)
&& paramMap.get(name) == null) {
if (hasTypeHandler
|| parameterMapping.getJavaType().equals(parameterObject.getClass())) {
paramMap.put(name, parameterObject);
break;
}
}
}
}
}
return processPageParameter(ms, paramMap, page, boundSql, pageKey);
}
- 处理分页结果
@Override
public Object afterPage(List pageList, Object parameterObject, RowBounds rowBounds) {
Page page = getLocalPage();
if (page == null) {
return pageList;
}
page.addAll(pageList);
if (!page.isCount()) {
page.setTotal(-1);
} else if ((page.getPageSizeZero() != null && page.getPageSizeZero()) && page.getPageSize() == 0) {
page.setTotal(pageList.size());
} else if(page.isOrderByOnly()){
page.setTotal(pageList.size());
}
return page;
}
6.使用分页结果 CommonPage.toPage(page);
public static <T> CommonPage<T> toPage(Page<T> page) {
CommonPage<T> result = new CommonPage<T>();
result.setTotalPage(page.getPages());
result.setPageNum(page.getPageNum());
result.setPageSize(page.getPageSize());
result.setRecordCount(page.getTotal());
result.setRows(page.getResult());
return result;
}
public List getResult() { return this; }
- 分页完毕,及时关闭流处理 Page extends** ArrayList** implements Closeable
@Override
public void close() {
PageHelper.clearPage();
}
/**
- 移除本地变量 */ public static void clearPage() { LOCAL_PAGE.remove(); }