一、MongoTemplate 实现分页
springboot集成Mongodb好像没有现成的分页工具,只能自己先查总数再查数据,需要进行两次查询。
例如:
@Test
public void test_119() throws Exception{
Query query = new Query();
long total = mongoTemplate.count(query, Dog.class);
query.with(PageRequest.of(0,3));
List<Dog> dogList = mongoTemplate.find(query, Dog.class);
System.out.println("总行数:"+total);
System.out.println(JSON.toJSONString(dogList, SerializerFeature.PrettyFormat));
}
上述代码查询了dog列表的第0页,每页3条数据。运行结果如下:
PS:注意PageRequest起始页码为0。与MySQL起始页为1不同。
二、自定义AOP实现分页工具
可以发现分页都是这个逻辑:先查总数、添加分页信息、再查列表数据。
由于开发中同时用到了MyBatis,MyBatis有自己的分页插件 PageHelper 。PageHelper还是很好用的,只需要PageHelper.
startPage
(0,3);
之后的首次查询就自带分页了。
那能否让 PageHelper 也对 MongoTemplate 有效呢?
PageHelper是通过ThreadLocal来传递数据的,我们可以通过自定义一个AOP对MongoTemplate的查询方法进行增强即可。
首先引入AOP相关starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
编写切面类:
package org.example.aop;
import com.github.pagehelper.Page;
import com.github.pagehelper.SqlUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import java.util.List;
@Aspect
@Component
public class MongoTemplateAop {
@Autowired
private MongoTemplate mongoTemplate;
@Pointcut("execution(public * org.springframework.data.mongodb.core.MongoTemplate.find(..))")
public void findPoint(){}
@Pointcut("execution(public * org.springframework.data.mongodb.core.MongoTemplate.findAll(..))")
public void findAllPoint(){}
@Around("findPoint()")
public Object findPointAround(ProceedingJoinPoint pjp){
try {
Object[] args = pjp.getArgs();
// 是否开启了分页查询
Page<Object> localPage = SqlUtil.getLocalPage();
if (localPage != null && args[0] instanceof Query) {
Query query = (Query) args[0];
int pageNum = localPage.getPageNum();
int pageSize = localPage.getPageSize();
// 没有主动设置过分页相关的限制时,PageHelper 才生效
if (query.getLimit() == 0 && query.getSkip() == 0) {
// 查询总数
long total = 0;
Class<?> entityClass = (Class<?>) args[1];
if (args.length == 3) {
String collectionName = (String) args[2];
total = mongoTemplate.count(query, entityClass, collectionName);
} else {
total = mongoTemplate.count(query, entityClass);
}
localPage.setTotal(total);
// 添加分页条件
query.with(PageRequest.of(pageNum - 1, pageSize));
List<?> result = (List<?>) pjp.proceed(args);
localPage.addAll(result);
return localPage;
}
}
// 不分页直接查询
return pjp.proceed(args);
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
// PageHelper 作废
SqlUtil.clearLocalPage();
}
}
@Around("findAllPoint()")
public Object findAllPointAround(ProceedingJoinPoint pjp){
try {
Object[] args = pjp.getArgs();
// 是否开启了分页查询
Page<Object> localPage = SqlUtil.getLocalPage();
if (localPage != null) {
Query query = new Query();
int pageNum = localPage.getPageNum();
int pageSize = localPage.getPageSize();
// 没有主动设置过分页相关的限制时,PageHelper 才生效
if (query.getLimit() == 0 && query.getSkip() == 0) {
// 查询总数
long total = 0;
List<?> result;
Class<?> entityClass = (Class<?>) args[0];
if (args.length == 2) {
String collectionName = (String) args[1];
total = mongoTemplate.count(query, entityClass, collectionName);
// 分页查询
query.with(PageRequest.of(pageNum - 1, pageSize));
result = mongoTemplate.find(query, entityClass, collectionName);
} else {
total = mongoTemplate.count(query, entityClass);
// 分页查询
query.with(PageRequest.of(pageNum - 1, pageSize));
result = mongoTemplate.find(query, entityClass);
}
localPage.setTotal(total);
localPage.addAll(result);
return localPage;
}
}
// 不分页直接查询
return pjp.proceed(args);
} catch (Throwable e) {
throw new RuntimeException(e);
} finally {
// PageHelper 作废
SqlUtil.clearLocalPage();
}
}
}
使用:
@Test
public void test_82() throws Exception{
PageHelper.startPage(1,3);
List<Dog> dogList = mongoTemplate.find(Query.query(Criteria.where("type").is(DogTypeEnum.ROBOT_DOG)), Dog.class);
// 包装分页信息
PageInfo<Dog> dogPageInfo = new PageInfo<>(dogList);
System.out.println(JSON.toJSONString(dogPageInfo, SerializerFeature.PrettyFormat));
}
结果: