一、前言
首先我们要知道什么是aop,什么是pagehelper
从而我们知道,pagehelper的实现其实是两行代码
PageHelper.startPage(pageNum, pageSize); // 开始分页
PageInfo pageInfo = new PageInfo(userList); // 返回分页
实现思路:
在前置切面里面就开始PageHelper.startPage(pageNum, pageSize);
然后定义一个同一的返回类,然后在返回类里面定义一个分页结果的方法;
二、实现
一些工具类的使用,看文章
实现步骤:
- 定义一个BaseController,存放所有的controller通用的东西
- 定义一个分页工具类
- 定义一个分页实体类,存储分页信息
- 定义一个分页数据返回类,在BaseController里面指定返回的类
- 定义前置切面以及切入点注解,执行分页开始的操作
2.1.定义一个BaseController,存放所有的controller通用的东西
public class BaseController {
protected final Logger logger = LoggerFactory.getLogger(this.getClass());
protected Response response(){
return IMediaCenterSpringController.responseFactory.createResponse();
}
/**
* 统一封装 onComplete, 简化调用方代码
* @param result
* @return
*/
protected Response onComplete(Object result){
Response response = response();
response.onComplete(result);
return response;
}
/**
* 分页返回
*
* @param list
* @return
*/
public Response onCompleteWithPageResult(List<?> list){
return onComplete(PageHelperUtil.getDataTable(list));
}
/**
* 统一封装 onError, 简化调用方代码
* @param e
* @return
*/
protected Response onError(Exception e){
Response response = response();
response.onError(e);
return response;
}
}
2.2.定义一个分页工具类
这儿可以实现排序和分页
public class PageHelperUtil {
/**
* 当前记录起始索引
*/
public static final String PAGE_NUM = "pageNum";
/**
* 每页显示记录数
*/
public static final String PAGE_SIZE = "pageSize";
/**
* 排序列
*/
public static final String ORDER_BY_COLUMN = "orderByColumn";
/**
* 排序的方向 "desc" 或者 "asc".
*/
public static final String IS_ASC = "isAsc";
/**
* 分页参数合理化
*/
public static final String REASONABLE = "reasonable";
/**
* 封装分页对象(从请求头获取参数)
*/
public static PageDomain getPageDomain()
{
PageDomain pageDomain = new PageDomain();
pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
return pageDomain;
}
/**
* 响应请求分页数据
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static TableDataInfo getDataTable(List<?> list)
{
TableDataInfo rspData = new TableDataInfo();
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
/**
* 设置请求分页数据 - 从请求流里面获得请求的信息,注意只能取出来一次,只针对get接口有效
*/
public static void startPage() {
PageDomain pageDomain = this.getPageDomain();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
// 增加中文的特殊排序处理
String orderByColumn = pageDomain.getOrderByColumn();
if (StringUtils.isNotEmpty(orderByColumn)) {
orderBy = "convert(" + StringUtils.toUnderScoreCase(orderByColumn) + " USING gbk" + ") COLLATE gbk_chinese_ci" + " " + pageDomain.getIsAsc();
}
PageHelper.startPage(pageNum, pageSize, orderBy);
}
}
/**
* 设置请求分页数据
*/
public static void startPage(PageDomain pageDomain) {
// PageDomain pageDomain = this.getPageDomain();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
// 增加中文的特殊排序处理
String orderByColumn = pageDomain.getOrderByColumn();
if (StringUtils.isNotEmpty(orderByColumn)) {
orderBy = "convert(" + StringUtils.toUnderScoreCase(orderByColumn) + " USING gbk" + ") COLLATE gbk_chinese_ci" + " " + pageDomain.getIsAsc();
}
PageHelper.startPage(pageNum, pageSize, orderBy);
}
}
}
2.3.定义一个分页实体类,存储分页信息,真正接受前端传参的实体类集成这个分页实体类
按照哪个字段排序,会自动把字段的驼峰转换成下划线写法;
**
* 分页数据
*
* @author adbmonitor
*/
public class PageDomain {
/**
* 下划线
*/
@TableField(exist = false)
private static final char SEPARATOR = '_';
/**
* 当前记录起始索引
*/
@TableField(exist = false)
private Integer pageNum;
/**
* 每页显示记录数
*/
@TableField(exist = false)
private Integer pageSize;
/**
* 排序列
*/
@TableField(exist = false)
private String orderByColumn;
/**
* 排序的方向desc或者asc
*/
@TableField(exist = false)
private String isAsc = "asc";
/**
* 分页参数合理化
*/
@TableField(exist = false)
private Boolean reasonable = true;
public String getOrderBy() {
if (isEmpty(orderByColumn)) {
return "";
}
return toUnderScoreCase(orderByColumn) + " " + isAsc;
}
public Integer getPageNum() {
return pageNum;
}
public void setPageNum(Integer pageNum) {
this.pageNum = pageNum;
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public String getOrderByColumn() {
return orderByColumn;
}
public void setOrderByColumn(String orderByColumn) {
this.orderByColumn = orderByColumn;
}
public String getIsAsc() {
return isAsc;
}
public void setIsAsc(String isAsc) {
if (!isEmpty(isAsc)) {
// 兼容前端排序类型
if ("ascending".equals(isAsc)) {
isAsc = "asc";
} else if ("descending".equals(isAsc)) {
isAsc = "desc";
}
this.isAsc = isAsc;
}
}
public Boolean getReasonable() {
if (reasonable == null) {
return Boolean.TRUE;
}
return reasonable;
}
public void setReasonable(Boolean reasonable) {
this.reasonable = reasonable;
}
/**
* 驼峰转下划线命名
*/
public static String toUnderScoreCase(String str) {
if (str == null) {
return null;
}
StringBuilder sb = new StringBuilder();
// 前置字符是否大写
boolean preCharIsUpperCase = true;
// 当前字符是否大写
boolean curreCharIsUpperCase = true;
// 下一字符是否大写
boolean nexteCharIsUpperCase = true;
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
if (i > 0) {
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
} else {
preCharIsUpperCase = false;
}
curreCharIsUpperCase = Character.isUpperCase(c);
if (i < (str.length() - 1)) {
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
}
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
sb.append(SEPARATOR);
} else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
sb.append(SEPARATOR);
}
sb.append(Character.toLowerCase(c));
}
return sb.toString();
}
public boolean isEmpty(CharSequence cs) {
return cs == null || cs.length() == 0;
}
}
2.4.定义一个分页数据返回的格式类
import java.io.Serializable;
import java.util.List;
/**
* 表格分页数据对象
*
* @author adbmonitor
*/
public class TableDataInfo implements Serializable
{
private static final long serialVersionUID = 1L;
/** 总记录数 */
private long total;
/** 列表数据 */
private List<?> rows;
/**
* 表格数据对象
*/
public TableDataInfo()
{
}
/**
* 分页
*
* @param list 列表数据
* @param total 总记录数
*/
public TableDataInfo(List<?> list, int total)
{
this.rows = list;
this.total = total;
}
public long getTotal()
{
return total;
}
public void setTotal(long total)
{
this.total = total;
}
public List<?> getRows()
{
return rows;
}
public void setRows(List<?> rows)
{
this.rows = rows;
}
}
2.5. 定义前置切面,执行分页开始的操作
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import static net.facelib.eam.mediacenter.page.PageHelperUtil;
@Aspect
@Component
public class PagingQueryAspect {
// 前置通知,所有被这个注解了的接口调用前这个切面被调用
@Before("@annotation(net.facelib.eam.mediacenter.annotation.PagingQuery)")
public void before() {
PageHelperUtil.startPage();
}
}
/**
* @ClassName PagingQuery
* @Description 分页注解
* @Author Pathfinder
* @Date 2022年06月09日 13时38分
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PagingQuery {
}
2.6 使用
controller的方法上加上这个注解
@RestController
@RequestMapping("/material")
@CrossOrigin
@Api(tags = "素材控制器")
public class MaterialController extends BaseController{
@PagingQuery
public Response getMaterial(Material material){
return onCompleteWithPageResult(materialService.getMaterialList(material));
}
}
service
@Override
@SetCreateUpdateByUserName
public List<Material> getMaterialList(Material material) {
QueryWrapper<Material> wrapper = new QueryWrapper<>(material);
material.setDeptId(UserAccessor.getCurrentUserDeptId());
assembleTimeQueryRule(material, wrapper.lambda());
List<Material> materials = materialMapper.selectList(wrapper);
return materials;
}
/**
* 时间搜索规则
*
* @param material
* @param wrapper
* @return
*/
private LambdaQueryWrapper<Material> assembleTimeQueryRule(Material material, LambdaQueryWrapper<Material> wrapper) {
Date searchStartTime = material.getSearchStartTime();
Date searchEndTime = material.getSearchEndTime();
if (searchStartTime != null) {
searchStartTime = DateUtils.getStartTime(searchStartTime);
if (searchEndTime != null) {
searchEndTime = DateUtils.getEndTime(searchEndTime);
return wrapper.between(Material::getCreateTime, searchStartTime, searchEndTime);
}
return wrapper.gt(Material::getCreateTime, searchStartTime);
}
return wrapper;
}
/**
* 创建者搜索
*
* @param material
* @param wrapper
* @return
*/
private LambdaQueryWrapper<Material> assembleCreateByQueryRule(Material material, LambdaQueryWrapper<Material> wrapper) {
Long createBy = material.getCreateBy();
if (createBy != null) {
return wrapper.eq(Material::getCreateBy, createBy);
}
return wrapper;
}
从上面可以看到,接口的入参实体类会继承我们自定义的分页筛选类用来存放分页筛选信息,然后,把service返回的集合通过controller的分页返回方法onCompleteWithPageResult返回分页筛选后的数据;
三、注意事项
-
类别查询只能是get请求,且是单表的数据库操作;
-
定义的接收前端传参的实体类,假如要实现模糊搜索,需要在属性上面加注解;
@TableField(condition = SqlCondition.LIKE)
private String name;
- 排序的问题 ?
orderByColumn 属性决定按照哪个字段排序,isAsc属性觉得升降序