SpringBoot之使用分页功能在项目中

619 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情

分页功能在前端页面的执行是渲染数据和分页信息展示,在后端页面则需要按照前端传输而来的请求,将分页所需的数据正确地查询出来并返回给前端

前端需要展示所有页码,而后端则只需要提供总页数即可,不需要对总页数进行其他操作。

前端需要根据用户的操作记录当前页码的参数,以便对页码信息进行调整和限制,而后端只需要接收前端传输过来的页码并进行相应判断和查询即可。

后端分页必不可少的两个参数:页码条数(每页)

在实现分页功能时,使用不同的数据库实现方式也不同。因为不同数据库实现分页功能的关键字有些差别,比如SQL Server的top关键字、Oracle的rownum关键字、MySQL的limit关键字。limit关键字如下所示:

select * from tb_xxxx limit 10,20

分页功能的最终实现就是通过页码和条数,确定数据库需要查询的数据。

对于后端代码的实现来说,页码和条数两个参数就显得特别重要,缺少这两个参数查询逻辑就不成立,分页数据也就无从查起。

此外,为了前端分页区的展示,还要将数据总量或者总页数返回给前端。数据总量是必不可少的,而总页数可以计算出来(即数据总量除以每页条数)。数据总量的获取方式:

select * from tb_xxxx 

之后将数据封装,并返回给前端即可

分页功能返回结果的封装

这里的分页数据结果,就需要返回多个字段。在项目开发工作中开发人员会将返回结果进行抽象并封装成一个常用的Java类。

新建util包并在util包中新建Result通用结果类,代码如下所示:


public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private int resultCode;
    private String message;
    private T data;

    public Result() {
    }

    public Result(int resultCode, String message) {
        this.resultCode = resultCode;
        this.message = message;
    }

    public int getResultCode() {
        return resultCode;
    }

    public void setResultCode(int resultCode) {
        this.resultCode = resultCode;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "Result{" +
                "resultCode=" + resultCode +
                ", message='" + message + ''' +
                ", data=" + data +
                '}';
    }
}

后端接口返回的数据会根据以上格式进行数据封装,包括业务码、返回信息、实际的数据结果。

这个格式是开发人员自行设置的,如果有其他更好的方案也可以进行适当的调整。如要为了返回结果的数据统一,前端接收该结果后需要对数据进行解析,并通过业务码进行相应的逻辑操作,再获取data属性中的数据并进行页面渲染或者进行信息提示。

实际返回的数据格式示例

  • 对象列表数据
{
    "resultCode": 200,
        "message": "SUCCESS",
        "data": [{
    "id": 2,
            "name": "user1",
            "password": "123456"
}, {
    "id": 1,
            "name": "13",
            "password": "12345"
}]
}
  • 单条对象数据
{
    "resultCode": 200,
        "message": "SUCCESS",
        "data": {
    "id": 2,
            "name": "user1",
            "password": "123456"
}
}
  • 简单对象数据
{
  "resultCode": 200,
      "message": "SUCCESS",
      "data": true
}

在后端进行业务处理后程序将会返回给前端一串JSON格式的数据。

resultCode等于200表示数据请求成功,该字段也可以自行定义,比如 0、1001、500等。

message值为SUCCESS,也可以自行定义返回信息,比如获取成功、列表数据查询成功等字符串。

这些都需要与前端约定好,一个resultCode码只能表示一种含义。

data属性使用泛型定义,因此在data字段中的数据可以是一个对象数组,也可以是一个字符串数字等类型,它根据不同的业务返回不同的结果,以这种方式返回数据。

public class PageResult implements Serializable {

    //总记录数
    private int totalCount;
    //每页记录数
    private int pageSize;
    //总页数
    private int totalPage;
    //当前页数
    private int currPage;
    //列表数据
    private List<?> list;

    /**
     * 分页
     *
     * @param list       列表数据
     * @param totalCount 总记录数
     * @param pageSize   每页记录数
     * @param currPage   当前页数
     */
    public PageResult(List<?> list, int totalCount, int pageSize, int currPage) {
        this.list = list;
        this.totalCount = totalCount;
        this.pageSize = pageSize;
        this.currPage = currPage;
        this.totalPage = (int) Math.ceil((double) totalCount / pageSize);
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    public int getTotalPage() {
        return totalPage;
    }

    public void setTotalPage(int totalPage) {
        this.totalPage = totalPage;
    }

    public int getCurrPage() {
        return currPage;
    }

    public void setCurrPage(int currPage) {
        this.currPage = currPage;
    }

    public List<?> getList() {
        return list;
    }

    public void setList(List<?> list) {
        this.list = list;
    }
}

分页功能代码的具体实现

数据层分页代码的实现

在Dao接口中新增两个方法返回分页数据列表findUsers()返回数据总数getTotalUser()

在xml文件中新增这两个方法的映射语句

<!-- 查询用户列表 -->
<select id="findUsers" parameterType="Map" resultMap="UserResult">
select id,name,password from tb_user
order by id desc
<if test="start!=null and limit!=null">
limit #{start},#{limit}
</if>
</select>

<!-- 查询用户总数 -->
<select id="getTotalUser" parameterType="Map" resultType="int">
select count(*) from tb_user
</select>

业务层分页代码的实现

@Service
public class UserService {

@Autowired
private UserDao userDao;

public PageResult getUserPage(PageQueryUtil pageUtil) {
// 当前页码中的数据列表
List<User> users = userDao.findUsers(pageUtil);
// 数据总条数,用于计算分页数据
int total = userDao.getTotalUser(pageUtil);
// 分页信息封装
PageResult pageResult = new PageResult(users, total, pageUtil.getLimit(), pageUtil.getPage());
return pageResult;
}
}

首先根据当前页面和每页条数查询当前页的数据集合,然后调用select count(*)语句查询数据的总条数用于计算分页数据,最后将获取的数据封装到PageResult对象中并返回给Controller层。

控制层分页代码的实现

    @RestController
    @RequestMapping("/users")
    public class PageTestController {

        @Autowired
        private UserService userService;

        /**
         * 分页功能测试
         */
        @RequestMapping(value = "/list", method = RequestMethod.GET)
        public Result list(@RequestParam Map<String, Object> params) {
            Result result = new Result();
            //StringUtils.isEmpty判断字符串或者对象是否为空
            if (StringUtils.isEmpty(params.get("page")) || StringUtils.isEmpty(params.get("limit"))) {
// 返回错误码
                result.setResultCode(500);
// 错误信息
                result.setMessage("参数异常!");
                return result;
            }
// 封装查询参数
            PageQueryUtil queryParamList = new PageQueryUtil(params);
// 查询并封装分页结果集
            PageResult userPage = userService.getUserPage(queryParamList);
// 返回成功码
            result.setResultCode(200);
            result.setMessage("查询成功");
// 返回分页数据
            result.setData(userPage);
            return result;
        }
    }

前端将所需页码和条数参数传输给后端,后端在接收分页请求后对分页参数进行计算,并利用MySQL的limit关键字查询对应的记录,在查询结果被封装后返回给前端。

在TestUserControler类上使用的是@RestController注解,该注解相当于@ResponseBody+@Controller的组合注解。