基于 Spring Boot + MyBatis + PageHelper + Thymeleaf 的数据分页展示

(一)需求

简单的前端分页展示功能:以表格的方式展现每页数据,在表格标题下填入对应的字段值,页脚处显示当前页、总记录页数和条数,一键跳转至首尾页和相邻页。在页眉处按照始末时间查询记录。
基于 Spring Boot + MyBatis + PageHelper + Thymeleaf 的数据分页展示_第1张图片

(二)代码

2.1 后端代码

控制层

在控制层需要返回给前端的 model 属性有分页对象 pageInfo,数据 records;另外,由于按照时间查询后,需要在前端页面中填充时间,所以把 startTime 和 endTime 也添加到 model 的属性里。

@GetMapping("test/records")
public String getRecordsAndPageInfoBetweenTime(String startTime, String endTime, Model model,
                                               @RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                               @RequestParam(defaultValue = "10") Integer pageSize) {
    startTime = TimeUtils.toNull(startTime);
    endTime = TimeUtils.toNull(endTime);
    PageInfo<ApiTestRecordVO> pageInfo = apiTestRecordService.getPageInfoBetweenTime(startTime, endTime, pageNum, pageSize);
    model.addAttribute("pageInfo", pageInfo);
    model.addAttribute("startTime", startTime);
    model.addAttribute("endTime", endTime);
    return "test-records";
}

控制层使用到的工具类 TimeUtils 中的 toNull 方法

public static String toNull(String time) {
    if (StringUtils.equalsIgnoreCase(time, "null") || StringUtils.isBlank(time)) {
        return null;
    }
    return time;
}

服务层

@Override
public PageInfo<ApiTestRecordVO> getPageInfoBetweenTime(String startTime, String endTime, Integer pageNum, Integer pageSize) {
    if (pageNum == null || pageNum <= 0) {
        pageNum = DEFAULT_PAGE_NUM;
    }
    if (pageSize == null || pageSize <= 5) {
        pageSize = DEFAULT_PAGE_SIZE;
    }
    return new PageInfo<>(getRecordsBetweenTimeByPage(startTime, endTime, pageNum, pageSize), DEFAULT_NAVIGATE_PAGES);
}

private List<ApiTestRecordVO> getRecordsBetweenTimeByPage(String startTime, String endTime, Integer pageNum, Integer pageSize) {
    PageHelper.startPage(pageNum, pageSize);
    startTime = TimeUtils.getNormalizedInputTime(startTime);
    endTime = TimeUtils.getNormalizedInputTime(endTime);
    return apiTestRecordMapper.getApiTestRecordVOsBetweenTime(startTime, endTime);
}

控制层使用到的工具类 TimeUtils 中的 getNormalizedInputTime 方法,将前端 input 输入框中的日期格式 yyyy-MM-ddTHH:mm 改为 yyyy-MM-dd HH:mm,以便于作为将日期字符串作为 MySQL 的查询条件。

public static String getNormalizedInputTime(String inputTime) {
    return StringUtils.replaceChars(inputTime, 'T', ' ');
}

持久层的代码为 MyBatis 的 mapper 接口 + xml 配置,比较简单,此处不予赘述。

2.2 前端代码

动态表格

数据展示部分,以表格形式展示,本文引入 Bootstrap CSS 做页面美化。在 tr 标签中对 records 做 Thymealeaf each 遍历,可以将根据数据大小动态添加表格行,在 td 标签中一一添加每个 record 对象的字段值。

<table class="table">
    <thead>
    <tr>
        <th>系统th>
        <th>环境th>
        <th>方法th>
        <th>协议th>
        <th>URLth>
        <th>参数th>
        <th>期望返回值th>
        <th>测试时间th>
        <th>是否通过th>
    tr>
    thead>
    <tbody>
    <tr th:each="record:${pageInfo.list}">
        <td th:text="${record.system}">td>
        <td th:text="${record.environment}">td>
        <td th:text="${record.method}">td>
        <td th:text="${record.protocol}">td>
        <td th:text="${record.url}">td>
        <td th:text="${record.paramStr}">td>
        <td th:text="${record.expectedContain}">td>
        <td th:text="${record.testTime}">td>
        <td th:text="${record.passed}">td>
    tr>
    tbody>
table>

分页详情

在无序列表使用 pagination 类来使其变为一个标准的页码导航栏,在 li 标签中利用 Thymeleaf 的变量表达式对后端返回的 pageInfo的属性做判断、遍历、文本或 href 填充等。

<div class="modal-footer">
    <div class="col-md-6">
        当前第 [[${pageInfo.pageNum}]] 页,共 [[${pageInfo.pages}]] 页,[[${pageInfo.total}]] 条记录
    div>
    <ul class="pagination">
        <li class="page-link" th:if="${pageInfo.hasPreviousPage}">
            <a th:href="'/api/test/records?startTime='+${startTime}+'&endTime='+${endTime}+'&pageNum=1'">首页a>
        li>
        <li class="page-link" th:if="${pageInfo.hasPreviousPage}">
            <a th:href="'/api/test/records?startTime='+${startTime}+'&endTime='+${endTime}+'&pageNum='+${pageInfo.prePage}">上一页a>
        li>
        <li class="page-link" th:each="nav:${pageInfo.navigatepageNums}">
            <a th:href="'/api/test/records?startTime='+${startTime}+'&endTime='+${endTime}+'&pageNum='+${nav}"
               th:text="${nav}" th:if="${nav != pageInfo.pageNum}">a>
            <span style="font-weight: bold;background: lightskyblue;" th:if="${nav == pageInfo.pageNum}"
                  th:text="${nav}">span>
        li>
        <li class="page-link" th:if="${pageInfo.hasNextPage}">
            <a th:href="'/api/test/records?startTime='+${startTime}+'&endTime='+${endTime}+'&pageNum='+${pageInfo.nextPage}">下一页a>
        li>
        <li class="page-link" th:if="${pageInfo.pageNum < pageInfo.pages}">
            <a th:href="'/api/test/records?startTime='+${startTime}+'&endTime='+${endTime}+'&pageNum='+${pageInfo.pages}">尾页a>
        li>
    ul>
div>

从分页导航栏的代码可以看出 PageInfo 对象的强大,其中封装了以下属性:

属性 作用
pageNum 当前页
pages 总页数
total 总记录数
hasPreviousPage 是否有上一页
prePage 上一页
navigatepageNums 导航页码数组
hasNextPage 是否有下一页
nextPage 下一页

这些属性与 Thymealeaf 的变量表达式结合,共同构成了如下图所示的导航功能:
在这里插入图片描述

按时间查询

在表格上方加上按时间搜索表单

<form class="form-check-inline" action="/api/test/records">
    <label for="startTime" class="form-check-label">起始时间:label><input name="startTime" id="startTime"
                                                                        type="datetime-local" th:value="${startTime}">
      
    <label for="endTime" class="form-check-label">结束时间:label><input name="endTime" id="endTime" type="datetime-local"
                                                                      th:value="${endTime}">
      
    <input type="submit" class="btn-outline-primary" value="按时间查询"/>
form>

注意,按时间搜索后,要把填入的时间回写到 input datetime-local 标签内。
在这里插入图片描述

(三)总结 & 参考博客

本文的核心在于充分利用了 PageInfo 强大的分页功能,其中封装了诸多便于做导航栏页码展示的字段。再结合 Spring Boot 官方推荐的前后端不分离的框架 Thymeleaf 将 Spring UI Model 中的属性渲染到页面上。
本文源码参考:SpringBoot+PageHelper+Bootstrap+Thymeleaf 实现分页功能

你可能感兴趣的:(Spring,Boot,PageHelper,Thymeleaf)