气死了
气得我直接刚刚解决这个问题,就马上来写这篇文章了
这样也好,我能把整个过程完整记录下来
那开始吧
过程
最近在做毕设嘛,用的是RuoYi-Vue,用起来真的非常方便,极大的提高了开发效率。做起毕设或其他小项目真的非常容易,尤其加上它的代码生成工具,非常方便。而且我不光是在用,同时其实也是在学习,从中还是能学到很多东西的。
还有一个感触就是对于长期被业务折腾到半死,对代码失去信心的程序员,他们看到这样的开源项目,我相信他们肯定是开心,因为这种开源项目代码风格上很统一、规范标准执行的很到位,看起来真的赏心悦目。
问题简述
好了,回到正题!
今天做毕设,造数据测试的时候,发现分页功能失效了,前端调用后端分页接口返回的total
有问题
{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
/**
* 获取用户列表
*/
@PreAuthorize("@ss.hasPermi('system:user:list')")
@GetMapping("/list")
public TableDataInfo list(SysUser user) {
// 开启分页,要紧接着分页(service/mapper),这里ruoyi进行了封装
startPage();
List list = userService.selectUserList(user);
return getDataTable(list);
}
点开startPage();
,这是父类BaseController
的方法
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
/**
* 根据条件分页查询用户列表
*
* @param user 用户信息
* @return 用户信息集合信息
*/
@Override
@DataScope(deptAlias = "d", userAlias = "u")
public List selectUserList(SysUser user) {
return userMapper.selectUserList(user);
}
发现这里的service
就一行?
PageHelper
就是在这发挥了作用,进行了分页
其实我的问题就在这里,不过我要先把后面的流程走完
3、查到数据我们回到SysUserController
,这次关注他的return getDataTable(list);
/**
* 响应请求分页数据
*/
@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()
public PageInfo(List list) {
this(list, 8);
}
public PageInfo(List 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);
public PageSerializable(List 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
package com.github.pagehelper;
public class Page extends ArrayList implements Closeable {
...
}
从这里可以看出Page
继承了ArrayList
也是就实现了List
debug
结果如下,发现在执行完service
代码后,PageHelper
就已经完成这一步,那么自然就设置好了total
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcoj9Laf-1648217426077)(https://cdn.jsdelivr.net/gh/wnhyang/clouding@master/cloud-picture/image.2n0r5fmnpj80.webp)]
上面是正常流程梳理,接下看我的代码,哪里出了问题,导致total
总是错的
问题与解决
上面是举得ruoyi
原本的例子,因为我没有改动,所以也就没有问题
在我的模块上,我其他的代码实现也相同,就是在service
上又处理了一次
/**
* 查询任务列表
*
* @param task 任务
* @return 任务
*/
@Override
public List selectTaskList(Task task) {
return taskMapper.selectTaskList(task).stream().map(this::fill).collect(Collectors.toList());
}
这里的fill
就是又一个填充数据的流程
打印sql日志没有问题,是有分页流程的(查总数,然后limit
)
debug
发现这里list
变成了,并非Page
,也就把total
设置为list.size()
[图片上传失败...(image-fca05e-1677945618204)]
其实问题早就在查到资料后发现了,但是大多数处理方法我都看不上,什么再调用PageHelper.startPage
,转换成PageInfo
之类的,都会让我怀疑我是否有必要用了
尤其是在已经使用了ruoyi
之后,重新在service做那简直太麻烦了,因为那样我还需要把ruoyi
封装在Controller
上的一些东西拿过去,折腾不了
最后,找到一种非常简单的方法解决了
就是,看上面的代码其是又调用了stream
的转换流程的,可能就是在这里PageHelper
出现了问题
那么试着将fill
方法变成void
,反正也是填充数据,没有影响的,改动后如下
@Override
public List selectTaskList(Task task) {
List taskList = taskMapper.selectTaskList(task);
taskList.forEach(this::fill);
return taskList;
}
这次debug
就是Page
对象了,一切都正常了
总结
如果你成功带入我的节奏,那很好,你认真看了;如果你发现其中问题了,那更好了,欢迎指正;如果你还能发现我另一个想讨论的问题,那我更开心了
我想讨论的就藏在
发现这里的
service
就一行?
这句话里了
很奇怪我们的业务逻辑代码不都是几十行,上百行的吗?
为什么service
就一行mapper
?
篇幅问题,一下在讨论吧!!!