基於 Spring Boot + MyBatis + PageHelper + Thymeleaf 的數據分頁展示

(一)需求

簡單的前端分頁展示功能:以表格的方式展現每頁數據,在表格標題下填入對應的字段值,頁腳處顯示當前頁、總記錄頁數和條數,一鍵跳轉至首尾頁和相鄰頁。在頁眉處按照始末時間查詢記錄。
API 測試記錄

(二)代碼

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>URL</th>
        <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}">
    &nbsp;&nbsp;
    <label for="endTime" class="form-check-label">結束時間:</label><input name="endTime" id="endTime" type="datetime-local"
                                                                      th:value="${endTime}">
    &nbsp;&nbsp;
    <input type="submit" class="btn-outline-primary" value="按時間查詢"/>
</form>

注意,按時間搜索後,要把填入的時間回寫到 input datetime-local 標籤內。
在這裏插入圖片描述

(三)總結 & 參考博客

本文的核心在於充分利用了 PageInfo 強大的分頁功能,其中封裝了諸多便於做導航欄頁碼展示的字段。再結合 Spring Boot 官方推薦的前後端不分離的框架 Thymeleaf 將 Spring UI Model 中的屬性渲染到頁面上。
本文源碼參考:SpringBoot+PageHelper+Bootstrap+Thymeleaf 實現分頁功能

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章