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 会过滤掉无分类的数据。

相关推荐
梦帮科技6 分钟前
量子纠缠网络与量子隐形传态攻防:量子中继器信道串扰、纠缠态保真度降解与量子路由劫持
开发语言·网络·人工智能·算法·自动化·php
老王IT26 分钟前
C语言语法基础语法介绍
c语言·开发语言·算法
cfm_291433 分钟前
Leaf-segment号段模式
java
Wang's Blog35 分钟前
Java 项目实战: 交友项目 - 发布圈子动态:数据库表和接口文档介绍
java·数据库·交友
paopaokaka_luck36 分钟前
智慧电玩店管理系统(空闲机台随机分配、游玩时长概率模拟、积分自动结算、积分兑换闭环、 ECharts经营分析、 腾讯地图选址)
java·人工智能·mysql·echarts·推荐算法
LMT流氓兔1 小时前
第五单元——第9课:防止同一次操作重复执行
java·服务器·数据库·算法·ai·langchain
OxYGC1 小时前
Spring 面经系列 · 第 6 篇:Spring MVC 请求全流程、父子容器与零配置原理
java·spring·mvc
code2cat1 小时前
Java高级篇之JDBC:连接数据库,完成查询、更新与事务
java·开发语言·数据库
bksczm1 小时前
Redis数据结构之string
java·redis·mybatis
hzxxxz1 小时前
PHP引擎两个高危漏洞复盘:计数顺序与旧地址缺陷的机理与处置清单
开发语言·php