SSM 框架實現分頁顯示查詢(基於用户管理案例)

在 SSM 框架中實現分頁查詢,最常用且高效的方案是集成MyBatis 分頁插件(PageHelper),它能自動攔截 SQL 並添加分頁語句(LIMIT),無需手動編寫複雜分頁 SQL。以下基於之前的 “用户管理” 案例,完整補充分頁查詢的實現步驟,包含配置、代碼編寫與測試。

一、前期準備:集成 PageHelper 分頁插件

1.1 引入 PageHelper 依賴(pom.xml)

在原有 Maven 依賴中添加 PageHelper 座標,需注意與 MyBatis 版本兼容(此處適配 MyBatis 3.4.6):

<!-- MyBatis分頁插件PageHelper --><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>5.1.10</version></dependency><!-- PageHelper與Spring整合依賴(若用MyBatis-Spring需引入) --><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper-spring-boot-starter</artifactId>    <version>1.2.13</version>    <!-- 排除Spring Boot依賴(因當前是純SSM項目,非Spring Boot) -->    <exclusions>        <exclusion>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter</artifactId>        </exclusion>    </exclusions></dependency>

1.2 配置 PageHelper 插件(mybatis-config.xml)

在 MyBatis 全局配置文件中,通過<plugins>標籤配置 PageHelper,指定數據庫方言(如 MySQL):

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <!-- 配置分頁插件PageHelper -->    <plugins>        <plugin interceptor="com.github.pagehelper.PageInterceptor">            <!-- 指定數據庫方言:MySQL、Oracle等,PageHelper會根據方言生成對應分頁SQL -->            <property name="helperDialect" value="mysql"/>            <!-- 啓用合理化分頁:若pageNum<1則查詢第一頁,若pageNum>總頁數則查詢最後一頁 -->            <property name="reasonable" value="true"/>            <!-- 支持通過Mapper接口參數傳遞分頁參數(可選) -->            <property name="supportMethodsArguments" value="true"/>        </plugin>    </plugins>    <!-- 其他配置(如別名、環境等,原有配置不變) -->    <typeAliases>        <!-- 給POJO包配置別名,後續XML中可直接用“User”代替“com.pojo.User” -->        <package name="com.pojo"/>    </typeAliases></configuration>

二、第二步:修改持久層(Mapper)支持分頁

分頁查詢的核心是 “攔截原有查詢 SQL 並添加分頁條件”,因此無需修改原有selectAllUsers方法,僅需確保 Mapper 接口方法返回 List(PageHelper 會自動將結果封裝為分頁對象)。

2.1 Mapper 接口(UserMapper.java)

無需新增方法,複用原有查詢所有用户的方法(PageHelper 會自動處理分頁):

package com.mapper;import com.pojo.User;import org.apache.ibatis.annotations.Param;import java.util.List;public interface UserMapper {    // 原有方法:查詢所有用户(分頁時PageHelper會自動攔截此方法,添加LIMIT)    List<User> selectAllUsers();    // (可選)帶條件的分頁查詢(如按用户名模糊查詢)    List<User> selectUsersByUsername(@Param("username") String username);}

2.2 Mapper XML(UserMapper.xml)

若需 “帶條件的分頁查詢”,補充對應的 SQL(無需手動加 LIMIT,PageHelper 自動處理):

<mapper namespace="com.mapper.UserMapper">    <!-- 原有結果集映射(不變) -->    <resultMap id="UserResultMap" type="User">        <id column="id" property="id"/>        <result column="username" property="username"/>        <result column="age" property="age"/>        <result column="email" property="email"/>        <result column="create_time" property="createTime"/>    </resultMap>    <!-- 1. 原有查詢所有用户(分頁時自動添加LIMIT) -->    <select id="selectAllUsers" resultMap="UserResultMap">        SELECT id, username, age, email, create_time        FROM tb_user        ORDER BY create_time DESC    </select>    <!-- 2. 帶條件的分頁查詢(按用户名模糊查詢) -->    <select id="selectUsersByUsername" parameterType="string" resultMap="UserResultMap">        SELECT id, username, age, email, create_time        FROM tb_user        WHERE username LIKE CONCAT('%', #{username}, '%') <!-- 模糊查詢條件 -->        ORDER BY create_time DESC    </select></mapper>

三、第三步:業務層(Service)處理分頁邏輯

Service 層需接收 “頁碼(pageNum)” 和 “每頁條數(pageSize)” 參數,通過 PageHelper 啓動分頁,再調用 Mapper 方法查詢,最終返回分頁結果對象(包含總條數、總頁數、當前頁數據)。

3.1 Service 接口(UserService.java)

新增分頁查詢方法,區分 “無條件分頁” 和 “帶條件分頁”:

package com.service;import com.github.pagehelper.PageInfo;import com.pojo.User;import java.util.List;public interface UserService {    // 原有CRUD方法(不變)...    /**     * 1. 無條件分頁查詢所有用户     * @param pageNum 頁碼(從1開始)     * @param pageSize 每頁顯示條數     * @return 分頁結果對象(含總條數、當前頁數據等)     */    PageInfo<User> getUserPage(int pageNum, int pageSize);    /**     * 2. 帶條件分頁查詢(按用户名模糊查詢)     * @param pageNum 頁碼     * @param pageSize 每頁條數     * @param username 模糊查詢的用户名(可為null,null時查所有)     * @return 分頁結果對象     */    PageInfo<User> getUserPageByUsername(int pageNum, int pageSize, String username);}

3.2 Service 實現類(UserServiceImpl.java)

實現分頁方法,核心是通過PageHelper.startPage(pageNum, pageSize)啓動分頁,後續的第一個 Mapper 查詢會自動被分頁:

package com.service;import com.github.pagehelper.PageHelper;import com.github.pagehelper.PageInfo;import com.mapper.UserMapper;import com.pojo.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;@Servicepublic class UserServiceImpl implements UserService {    @Autowired    private UserMapper userMapper;    // 原有CRUD方法實現(不變)...    /**     * 無條件分頁查詢     */    @Override    public PageInfo<User> getUserPage(int pageNum, int pageSize) {        // 1. 啓動分頁:pageNum=當前頁碼,pageSize=每頁條數        PageHelper.startPage(pageNum, pageSize);        // 2. 調用Mapper查詢(此查詢會自動被分頁,添加LIMIT)        List<User> userList = userMapper.selectAllUsers();        // 3. 封裝分頁結果:PageInfo包含總條數、總頁數、當前頁數據等信息        PageInfo<User> pageInfo = new PageInfo<>(userList);        return pageInfo;    }    /**     * 帶條件分頁查詢(按用户名模糊查詢)     */    @Override    public PageInfo<User> getUserPageByUsername(int pageNum, int pageSize, String username) {        PageHelper.startPage(pageNum, pageSize);        // 若用户名不為null,則按條件查詢;否則查詢所有        List<User> userList = (username != null && !username.trim().isEmpty())                 ? userMapper.selectUsersByUsername(username)                 : userMapper.selectAllUsers();        return new PageInfo<>(userList);    }}

關鍵説明:PageInfo 對象的核心屬性

PageInfo 是 PageHelper 提供的分頁結果封裝類,包含前端分頁顯示所需的所有信息,常用屬性如下:

屬性名

含義

示例值

pageNum

當前頁碼

1

pageSize

每頁條數

10

total

總記錄數

100

pages

總頁數(total/pageSize,向上取整)

10

list

當前頁的數據列表

[User1, User2,...]

isFirstPage

是否為第一頁

true

isLastPage

是否為最後一頁

false

navigatePages

導航頁碼數(默認 5,如 1 2 3 4 5)

5

navigatepageNums

導航頁碼數組

[1,2,3,4,5]

四、第四步:控制層(Controller)接收分頁請求

Controller 層接收前端傳遞的分頁參數(pageNum、pageSize、查詢條件),調用 Service 分頁方法,返回包含分頁結果的 JSON 數據,供前端渲染分頁組件。

4.1 Controller 類(UserController.java)

新增分頁查詢接口,支持 “無條件分頁” 和 “帶條件分頁”:

package com.controller;import com.github.pagehelper.PageInfo;import com.pojo.User;import com.service.UserService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody;import java.util.HashMap;import java.util.Map;@Controller@RequestMapping("/user")@ResponseBodypublic class UserController {    @Autowired    private UserService userService;    // 原有CRUD接口(不變)...    /**     * 1. 無條件分頁查詢接口     * URL示例:/user/page?pageNum=1&pageSize=10     * @param pageNum 頁碼(默認1)     * @param pageSize 每頁條數(默認10)     * @return 分頁結果JSON     */    @GetMapping("/page")    public Map<String, Object> getUserPage(            // @RequestParam設置默認值,避免前端未傳參時報錯            @RequestParam(defaultValue = "1") int pageNum,            @RequestParam(defaultValue = "10") int pageSize) {        Map<String, Object> result = new HashMap<>();        try {            PageInfo<User> pageInfo = userService.getUserPage(pageNum, pageSize);            result.put("code", 200);            result.put("msg", "分頁查詢成功!");            result.put("data", pageInfo); // 分頁結果對象        } catch (Exception e) {            result.put("code", 500);            result.put("msg", "分頁查詢失敗:" + e.getMessage());        }        return result;    }    /**     * 2. 帶條件分頁查詢接口(按用户名模糊查詢)     * URL示例:/user/page/condition?pageNum=1&pageSize=10&username=張三     * @param pageNum 頁碼(默認1)     * @param pageSize 每頁條數(默認10)     * @param username 模糊查詢的用户名(可為null)     * @return 分頁結果JSON     */    @GetMapping("/page/condition")    public Map<String, Object> getUserPageByUsername(            @RequestParam(defaultValue = "1") int pageNum,            @RequestParam(defaultValue = "10") int pageSize,            @RequestParam(required = false) String username) { // required=false表示參數可選        Map<String, Object> result = new HashMap<>();        try {            PageInfo<User> pageInfo = userService.getUserPageByUsername(pageNum, pageSize, username);            result.put("code", 200);            result.put("msg", "條件分頁查詢成功!");            result.put("data", pageInfo);        } catch (Exception e) {            result.put("code", 500);            result.put("msg", "條件分頁查詢失敗:" + e.getMessage());        }        return result;    }}

五、第五步:前端分頁組件渲染(示例)

前端需接收 Controller 返回的 PageInfo 數據,渲染分頁列表和分頁導航(以 Vue 為例,其他框架邏輯類似):

5.1 前端請求示例(Axios)

// 1. 無條件分頁查詢(第1頁,每頁10條)axios.get("/user/page", {    params: {        pageNum: 1,        pageSize: 10    }}).then(res => {    if (res.data.code === 200) {        const pageInfo = res.data.data;        console.log("總記錄數:", pageInfo.total);        console.log("當前頁數據:", pageInfo.list);        console.log("總頁數:", pageInfo.pages);        // 渲染列表和分頁導航        this.userList = pageInfo.list;        this.pageInfo = pageInfo;    }});// 2. 帶條件分頁查詢(查詢用户名含“張三”的第1頁數據)axios.get("/user/page/condition", {    params: {        pageNum: 1,        pageSize: 10,        username: "張三"    }}).then(res => {    // 邏輯同上...});

5.2 分頁導航組件示例(Vue 模板)

<template>    <div class="pagination">        <!-- 上一頁 -->        <button @click="changePage(pageInfo.pageNum - 1)" :disabled="pageInfo.isFirstPage">            上一頁        </button>                <!-- 導航頁碼 -->        <button             v-for="num in pageInfo.navigatepageNums"             :key="num"            @click="changePage(num)"            :class="{ active: num === pageInfo.pageNum }"        >            {{ num }}        </button>                <!-- 下一頁 -->        <button @click="changePage(pageInfo.pageNum + 1)" :disabled="pageInfo.isLastPage">            下一頁        </button>                <!-- 分頁信息 -->        <span>            共{{ pageInfo.total }}條記錄,當前第{{ pageInfo.pageNum }}頁/共{{ pageInfo.pages }}頁        </span>    </div></template><script>export default {    data() {        return {            userList: [],            pageInfo: {} // 存儲分頁結果        };    },    methods: {        // 切換頁碼        changePage(pageNum) {            // 調用分頁查詢接口,傳入新頁碼            this.getUserPage(pageNum);        },        // 分頁查詢方法        getUserPage(pageNum) {            axios.get("/user/page", {                params: {                    pageNum: pageNum,                    pageSize: 10                }            }).then(res => {                if (res.data.code === 200) {                    this.userList = res.data.data.list;                    this.pageInfo = res.data.data;                }            });        }    }};</script>

六、關鍵注意事項

  1. PageHelper 啓動時機:PageHelper.startPage(pageNum, pageSize)必須在 “查詢方法調用前” 執行,且僅對 “後續第一個 Mapper 查詢” 生效,若有多個查詢,需多次調用 startPage。
  2. 數據庫方言適配:在 mybatis-config.xml 中必須指定helperDialect,否則 PageHelper 無法生成正確的分頁 SQL(如 MySQL 用 LIMIT,Oracle 用 ROWNUM)。
  3. 合理化分頁:開啓reasonable=true後,若前端傳遞 pageNum=0 或 pageNum > 總頁數,會自動修正為第 1 頁或最後一頁,避免查詢為空。
  4. 性能優化:分頁查詢本質是通過 LIMIT 優化,但當數據量極大(如千萬級)時,建議結合 “索引” 使用(如按 create_time 排序時,給 create_time 字段建索引),避免全表掃描。