气死了

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

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

那开始吧

过程

最近在做毕设嘛,用的是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<SysUser> 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<SysUser> 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<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);

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

package com.github.pagehelper;

public class Page<E> extends ArrayList<E> 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<Task> selectTaskList(Task task) {
    return taskMapper.selectTaskList(task).stream().map(this::fill).collect(Collectors.toList());
}

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

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

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

image

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

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

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

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

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

@Override
public List<Task> selectTaskList(Task task) {
    List<Task> taskList = taskMapper.selectTaskList(task);
    taskList.forEach(this::fill);
    return taskList;
}

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

总结

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

我想讨论的就藏在

发现这里的service就一行?

这句话里了

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

为什么service就一行mapper

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

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐