ruoyi分页问题

气死了

气得我直接刚刚解决这个问题,就马上来写这篇文章了

这样也好,我能把整个过程完整记录下来

那开始吧

过程

最近在做毕设嘛,用的是RuoYi-Vue,用起来真的非常方便,极大的提高了开发效率。做起毕设或其他小项目真的非常容易,尤其加上它的代码生成工具,非常方便。而且我不光是在用,同时其实也是在学习,从中还是能学到很多东西的。

还有一个感触就是对于长期被业务折腾到半死,对代码失去信心的程序员,他们看到这样的开源项目,我相信他们肯定是开心,因为这种开源项目代码风格上很统一、规范标准执行的很到位,看起来真的赏心悦目。

问题简述

好了,回到正题!

今天做毕设,造数据测试的时候,发现分页功能失效了,前端调用后端分页接口返回的total有问题

1
2
3
4
5
{total: 10,}
code: 200
msg: "查询成功"
rows: [{searchValue: null, createBy: null, createTime: "2022-03-18 20:36:55", updateBy: null,},]
total: 10

total总是返回当前数据的size

我很是不解,自认为对于ruoyi分页流程很是熟悉,对照官网找问题,愣是找了半天没发现问题

官网:后台手册 | RuoYi

检查了半天没发现什么问题,只好先去找找有没有遇到同样问题的,果然,有不少

  • https://cloud.tencent.com/developer/article/1786290
  • https://zhuanlan.zhihu.com/p/159199627
  • https://blog.csdn.net/qq_40942359/article/details/121429234
  • https://www.cnblogs.com/mantishell/p/13674818.html
  • https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/108017635

看完后,大致明白是怎么回事,这其实是PageHelper的问题

梳理流程

按照ruoyi的流程理一遍

1、后端分页接口SysUserController extends BaseController

1
2
3
4
5
6
7
8
9
10
11
/**
* 获取用户列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user) {
// 开启分页,要紧接着分页(service/mapper),这里ruoyi进行了封装
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}

点开startPage();,这是父类BaseController的方法

1
2
3
4
5
6
7
8
9
10
11
12
protected void startPage() {
// 获取request中关于分页的请求,具体有关于一个ServletUtils的类,可以自行了解
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize)) {
String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
Boolean reasonable = pageDomain.getReasonable();
// 真正的开始分页
PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
}
}

2、来到SysUserServiceImpl

1
2
3
4
5
6
7
8
9
10
11
/**
* 根据条件分页查询用户列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List<SysUser> selectUserList(SysUser user) {
return userMapper.selectUserList(user);
}

发现这里的service就一行?

PageHelper就是在这发挥了作用,进行了分页

其实我的问题就在这里,不过我要先把后面的流程走完

3、查到数据我们回到SysUserController,这次关注他的return getDataTable(list);

1
2
3
4
5
6
7
8
9
10
11
12
/**
* 响应请求分页数据
*/
@SuppressWarnings({"rawtypes", "unchecked"})
protected TableDataInfo getDataTable(List<?> list) {
TableDataInfo rspData = new TableDataInfo();
rspData.setCode(HttpStatus.SUCCESS);
rspData.setMsg("查询成功");
rspData.setRows(list);
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}

这就是最终的相应结果,既然是total出问题,那就重点关注setTotal方法,直接点进new PageInfo(list).getTotal()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public PageInfo(List<T> list) {
this(list, 8);
}

public PageInfo(List<T> list, int navigatePages) {
super(list);
this.isFirstPage = false;
this.isLastPage = false;
this.hasPreviousPage = false;
this.hasNextPage = false;
if (list instanceof Page) {
Page page = (Page)list;
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.pages = page.getPages();
this.size = page.size();
if (this.size == 0) {
this.startRow = 0L;
this.endRow = 0L;
} else {
this.startRow = page.getStartRow() + 1L;
this.endRow = this.startRow - 1L + (long)this.size;
}
} else if (list instanceof Collection) {
this.pageNum = 1;
this.pageSize = list.size();
this.pages = this.pageSize > 0 ? 1 : 0;
this.size = list.size();
this.startRow = 0L;
this.endRow = list.size() > 0 ? (long)(list.size() - 1) : 0L;
}

if (list instanceof Collection) {
this.calcByNavigatePages(navigatePages);
}

}

最终调用的是下面的构造方法,那么就进到super(list);

1
2
3
4
5
6
7
8
9
10
public PageSerializable(List<T> list) {
this.list = list;
// 是否是Page对象
if (list instanceof Page) {
this.total = ((Page)list).getTotal();
} else {
this.total = (long)list.size();
}

}

这是com.github.pagehelper包下的,就是在这里为PageInfo设置了total,当然也是为我们最终相应设置了

???

Page哪里来的

4、Page

1
2
3
4
5
package com.github.pagehelper;

public class Page<E> extends ArrayList<E> implements Closeable {
...
}

从这里可以看出Page继承了ArrayList也是就实现了List

debug结果如下,发现在执行完service代码后,PageHelper就已经完成这一步,那么自然就设置好了total

正常分页debug-PageHelper

上面是正常流程梳理,接下看我的代码,哪里出了问题,导致total总是错的

问题与解决

上面是举得ruoyi原本的例子,因为我没有改动,所以也就没有问题

在我的模块上,我其他的代码实现也相同,就是在service上又处理了一次

1
2
3
4
5
6
7
8
9
10
/**
* 查询任务列表
*
* @param task 任务
* @return 任务
*/
@Override
public List<Task> selectTaskList(Task task) {
return taskMapper.selectTaskList(task).stream().map(this::fill).collect(Collectors.toList());
}

这里的fill就是又一个填充数据的流程

打印sql日志没有问题,是有分页流程的(查总数,然后limit

debug发现这里list变成了ArrayList,并非Page,也就把total设置为list.size()

异常分页debug-PageHelper

其实问题早就在查到资料后发现了,但是大多数处理方法我都看不上,什么再调用PageHelper.startPage,转换成PageInfo之类的,都会让我怀疑我是否有必要用了

尤其是在已经使用了ruoyi之后,重新在service做那简直太麻烦了,因为那样我还需要把ruoyi封装在Controller上的一些东西拿过去,折腾不了

最后,找到一种非常简单的方法解决了

就是,看上面的代码其是又调用了stream的转换流程的,可能就是在这里PageHelper出现了问题

那么试着将fill方法变成void,反正也是填充数据,没有影响的,改动后如下

1
2
3
4
5
6
@Override
public List<Task> selectTaskList(Task task) {
List<Task> taskList = taskMapper.selectTaskList(task);
taskList.forEach(this::fill);
return taskList;
}

这次debug就是Page对象了,一切都正常了

总结

如果你成功带入我的节奏,那很好,你认真看了;如果你发现其中问题了,那更好了,欢迎指正;如果你还能发现我另一个想讨论的问题,那我更开心了

我想讨论的就藏在

发现这里的service就一行?

这句话里了

很奇怪我们的业务逻辑代码不都是几十行,上百行的吗?🤔

为什么service就一行mapper

篇幅问题,一下在讨论吧!!!😁