java: 分页查询(自用笔记)

1. Controller 层

1.1 示例代码(含详细备注)

复制代码
@GetMapping("/admin/dish/page")
public Result<PageResult> page(DishPageQueryDTO dto) {

    /*
     * 说明:
     * 1. Spring MVC 会自动将 Query 参数绑定到 dto 中
     *    例如:/page?page=1&pageSize=10&name=鱼
     *    dto.page = 1
     *    dto.pageSize = 10
     *    dto.name = "鱼"
     *
     * 2. Controller 不处理业务,仅调用 service 层
     */

    PageResult result = dishService.page(dto);

    // 使用统一响应结构
    return Result.success(result);
}

1.2 关键细节解释

  1. 参数封装方式

    • Spring 自动将 URL 查询参数映射到 DTO 中(按字段名匹配)。

    • 同名参数会被完整填充,无需使用 @RequestParam。

  2. Controller 不执行分页逻辑

    • 分页逻辑完全放在 service 层,使 Controller 保持轻量与无业务状态。
  3. 返回类型使用 Result

    • Result 为统一响应包装类。

    • PageResult 存储 total 和 records(分页数据)。

  4. DTO 字段规则

    DTO 的字段名必须与前端传参保持一致,如 page、pageSize、name 等,Spring 才能自动封装。


1.3 问题总结

  1. Query 参数能否自动封装为对象?

    可以,只需参数名与 DTO 字段名一致。

  2. 是否必须用 @RequestParam?

    不是。分页查询使用 DTO 封装更规范。

  3. Controller 能否直接调用 PageHelper?

    不建议。分页逻辑属于业务层,由 service 层统一处理。


2. ServiceImpl 层

2.1 示例代码(含详细备注)

复制代码
@Override
public PageResult page(DishPageQueryDTO dto) {

    /*
     * PageHelper.startPage 必须放在查询前执行。
     * 内部原理:
     * 1. 创建 Page 对象并绑定到 ThreadLocal
     * 2. 拦截接下来执行的 SQL
     * 3. 自动拼接 limit offset
     * 4. 自动执行 count 查询获取总数
     */
    PageHelper.startPage(dto.getPage(), dto.getPageSize());

    // 执行 Mapper 查询。此时 SQL 会被分页插件自动改写。
    List<DishVO> list = dishMapper.page(dto);

    /*
     * PageInfo 的作用:
     * 1. 识别 list 是否为 Page 类型
     * 2. 自动读取 total 和当前页数据
     */
    PageInfo<DishVO> pageInfo = new PageInfo<>(list);

    // 封装为通用分页返回结构
    return new PageResult(pageInfo.getTotal(), pageInfo.getList());
}

2.2 关键细节解释

  1. PageHelper.startPage 的作用

    创建分页上下文,使下一条 SQL 自动拼接分页语句。

    offset = (page - 1) * pageSize

  2. Page 对象与 PageInfo 的关联

    • list 在 PageHelper 处理后会成为 Page 类型

    • PageInfo 可以从 list 中读取分页信息(total, records)

  3. PageHelper 必须在执行 SQL 之前调用

    如果写在 SQL 之后,则不会生效。

  4. 返回统一的 PageResult

    PageResult 包含:

    • total:总条数

    • records:当前页数据列表


2.3 常见问题总结

  1. PageHelper.startPage 是否会执行 SQL?

    不执行,只是设置上下文。

  2. PageHelper 如何知道要分页哪条 SQL?

    startPage 与下一条 mapper 查询绑定,通过拦截器实现。

  3. PageInfo 必须 new 吗?

    是的,用于自动解析分页数据。

  4. ServiceImpl 是否需要 try-catch?

    可选,按项目统一规范处理。


3. Mapper XML 层

3.1 示例 SQL(含详细备注)

复制代码
<select id="page" resultType="com.sky.vo.DishVO">

    /*
     * 说明:
     * 1. 通过 LEFT JOIN 关联 category 表,获取分类名称
     * 2. 使用别名将不一致字段映射到 VO 字段
     * 3. 动态构建 WHERE 条件
     */

    SELECT
        d.id,
        d.name,
        d.price,
        d.status,

        -- 数据库字段 update_time 与 VO 字段 updateTime 不同,必须指定别名
        d.update_time AS updateTime,

        -- 分类名称来自 category 表
        c.name AS categoryName

    FROM dish d
    LEFT JOIN category c ON d.category_id = c.id

    <where>
        <!-- 模糊搜索 name -->
        <if test="name != null and name != ''">
            AND d.name LIKE CONCAT('%', #{name}, '%')
        </if>

        <!-- 分类过滤 -->
        <if test="categoryId != null">
            AND d.category_id = #{categoryId}
        </if>

        <!-- 状态过滤 -->
        <if test="status != null">
            AND d.status = #{status}
        </if>
    </where>

    ORDER BY d.update_time DESC
</select>

3.2 关键细节解释

  1. JOIN 逻辑说明

    菜品表不包含 categoryName,因此需要关联 category 表的 name 字段。

  2. 字段别名规则

    • 当数据库字段与 VO 字段名不同,必须使用 AS

    • MyBatis 使用字段名匹配映射(非位置匹配)

  3. 标签处理逻辑

    • 自动添加 WHERE

    • 自动剔除多余 AND/OR

    • 若所有 条件均不成立,则不会生成 WHERE

  4. 动态 SQL

    根据 DTO 字段是否为 null 或空字符串决定是否拼接 SQL 条件。


3.3 常见问题总结

  1. 为什么能自动去掉第一个 AND?

    因为 MyBatis 会对生成的 SQL 进行修剪处理。

  2. 字段名不一致为什么需要 AS?

    MyBatis 使用字段名与 VO 字段名直接匹配,不一致不会自动映射。

  3. 查询时 DTO 字段为 null 会怎样?

    不会拼接对应 SQL 片段。

  4. 是否必须使用 LEFT JOIN?

    若希望无分类的菜品也能展示,则使用 LEFT JOIN;否则 INNER JOIN 会过滤掉无分类的数据。

相关推荐
阿里嘎多学长3 小时前
2026-04-30 GitHub 热点项目精选
开发语言·程序员·github·代码托管
abcnull5 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡5 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan5 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054735 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路6 小时前
C++23概述
java·c++·c++23
时空系6 小时前
第10篇:继承扩展——面向对象编程进阶 python中文编程
开发语言·python·ai编程
专注API从业者7 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
CHANG_THE_WORLD7 小时前
python 批量终止进程exe
开发语言·python