现状:
在使用Mybatis进行数据库分页查询时,我们经常使用的是插件:pagehelper 此插件可以帮助我们很方便的进行数据库分页操作,但是使用此插件每次都需要先开启插件,然后再手动的对参数进行封装,这些都是模板化的套路,有没有一种更简洁的方法,让我们不在关注具体的分页细节,只需要实现我们的业务逻辑呢?所以接下来我将使用Spring AOP技术,对该工具类进行封装,让我们可以更方便的进行分页操作;
依赖:
首先在项目中加入pagehelper 分页插件和AOP的依赖:
<!-- pagehelper 分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-autoconfigure</artifactId>
<version>1.2.3</version>
</dependency>
<!--AOP依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
在配置文件中,配置分页插件:
# PageHelper分页插件
# 使用的数据库,如果是mysql,这里替换成mysql
pagehelper.helperDialect= oracle
# 当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页
pagehelper.reasonable= true
# 支持通过 Mapper 接口参数来传递分页参数
pagehelper.supportMethodsArguments= true
定义一个注解类 @Page:
定义此注解类的作用是,标识哪些是分页的方法,我们将对标注@Page的方法进行分页增强
package com.rems.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @program: rems
* @description: 分页注解
* @author: hu.chen
* @createDate: 2021年05月08日 10:34
**/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Page {
}
接下来定义切面类,并在里面编写增强逻辑:
package com.rems.aop;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.rems.pojo.PageFilter;
import lombok.extern.slf4j.Slf4j;
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.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.util.ObjectUtils;
/**
* @program: rems
* @description: 分页逻辑织入
* @author: hu.chen
* @createDate: 2021年05月08日 10:36
**/
//声明当前类是配置类
@Configuration
//标注当前类是Aop切面类
@Aspect
@Slf4j
//开启Aop增强
@EnableAspectJAutoProxy
public class PageAop {
/**
* 定义切入点
*/
@Pointcut("@annotation(com.rems.annotation.Page)")
public void annotation() {
}
/**
* 环绕增强
*/
@Around("annotation()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
// 当前页码
String pageNum="1";
//每页记录数
String pageSize="10";
PageFilter pageFilter=null;
//获取被增强方法的参数
Object[] args = proceedingJoinPoint.getArgs();
for (Object arg : args) {
if(arg instanceof PageFilter) {
pageFilter=(PageFilter) arg;
pageNum=ObjectUtils.isEmpty(pageFilter.getPageNum())? pageNum:pageFilter.getPageNum();
pageSize=ObjectUtils.isEmpty(pageFilter.getPageSize())? pageSize:pageFilter.getPageSize();
}
}
Object result = null;
try {
//调用分页插件传入开始页码和页面容量
Page<Object> page = PageHelper.startPage(Integer.parseInt(pageNum), Integer.parseInt(pageSize));
//执行被增强的方法,不写,则被增强方法不执行
result = proceedingJoinPoint.proceed(args);
//获取并封装分页后的参数
pageFilter.setPageNum(String.valueOf(page.getPageNum()));
pageFilter.setPages(page.getPages());
pageFilter.setPageSize(String.valueOf(page.getPageSize()));
pageFilter.setTotal(page.getTotal());
} catch (Exception e) {
log.info("查询数据库异常",e);
}
return result;
}
}
定义分页参数类,并让所有封装了查询参数的类继承本类
注意这里面的 getPageFilter 方法
package com.rems.pojo;
import lombok.Data;
import java.util.List;
/**
* @program: rems
* @description: 分页类
* @author: hu.chen
* @createDate: 2021年04月23日 18:26
**/
@Data
public class PageFilter<T> {
/**
* 总条数
*/
private long total;
/**
* 当前页码
*/
private String pageNum;
/**
* 每页记录数
*/
private String pageSize;
/**
* 总页数
*/
private Integer pages;
private List<T> data;
/**
* @param obj 继承了PageFilter类的子类
* @param response 从数据库查询出来的参数
* @return
*/
public PageFilter getPageFilter(PageFilter obj,List<T> response) {
PageFilter<T> pages = new PageFilter();
pages.setPageNum(String.valueOf(obj.getPageNum()));
pages.setPages(obj.getPages());
pages.setPageSize(String.valueOf(obj.getPageSize()));
pages.setTotal(obj.getTotal());
pages.setData(response);
return pages;
}
}
上面的配置都做好后,接下来就可以进行测试:
看一下mapper接口:
在此接口上标注@Page注解,说明当前方法需要分页增强
要注意这个入参:GetDemandDo,这个类继承了上面定义的PageFilter分页类
/**
* @Description: 根据动态条件查询需求表
* @Param: [demand]
* @return: com.rems.pojo.Demand
* @Author: chenhu
* @Date: 2021/4/23
*/
@Page
List<Demand> getDemandByDynamiCondition(GetDemandDo demand);
接下来看一下service业务逻辑层:
/**
* @Description: 查询根据条件动态查询需求列表并分页
* @Param:
* @return:
* @Author: chenhu
*/
@Override
public PageFilter<DemandVo> getDemandByDynamiCondition(GetDemandDo demand) {
//分页查询需求
List<DemandVo> demands = demandMapper.getDemandByDynamiCondition(demand).stream()
.map(item -> {
DemandVo demandVo = new DemandVo();
BeanUtils.copyProperties(item, demandVo);
return demandVo;
}).collect(Collectors.toList());
//这个方法调用的是继承自父类:PageFilter的方法,将封装了查询参数的对象放入,
//再将数据库查询并处理好的返回对象放入即可
return demand.getPageFilter(demand, demands);
}
在controller层调用:
/**
* 根据条件动态查询需求
*
* @param demand
* @return
*/
@GetMapping("/getDemand")
public AjaxData getDemand(GetDemandDo demand) {
return AjaxData.success(demandService.getDemandByDynamiCondition(demand));
}
Postman测试:
到这里就封装测试成功,之后使用只需要在需要分页查询的mapper接口上标注@Page注解,并让传递参数的对象继承PageFilter分页类,然后传递参数的对象调用继承过来的方法:getPageFilter(PageFilter obj,List response) 并将相应的参数传入即可;