程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

SpringBoot 各种分页查询方式详解(全网最全)

balukai 2025-06-09 20:07:45 文章精选 9 ℃

一、分页查询基础概念与原理

1.1 什么是分页查询

分页查询是指将大量数据分割成多个小块(页)进行展示的技术,它是现代Web应用中必不可少的功能。想象一下你去图书馆找书,如果所有书都堆在一张桌子上,你很难找到想要的那本。但如果书被整齐地放在多个书架上(每书架相当于一页),并标有编号,查找起来就方便多了。

分页查询的核心价值体现在:

  • 提升用户体验:避免用户面对海量数据时的信息过载
  • 提高系统性能:减少单次请求传输的数据量
  • 降低服务器压力:避免一次性处理过多数据

1.2 分页查询的基本参数

所有分页实现都围绕以下几个核心参数展开:

参数名

说明

默认值示例

使用场景说明

pageNum

当前页码(从0或1开始)

1

用户想查看第几页数据

pageSize

每页显示记录数

10

控制单页数据量

totalPages

总页数

计算得出

用于生成分页导航

totalElements

总记录数

查询得出

显示数据总量信息

sortField

排序字段

createTime

按哪个字段排序

sortOrder

排序方向(ASC/DESC)

DESC

升序还是降序排列

1.3 分页查询的SQL原理

在数据库层面,不同数据库的分页实现语法有所差异:

MySQL分页语法:

SELECT * FROM table_name LIMIT offset, pageSize
-- 例如:获取第2页,每页10条
SELECT * FROM user LIMIT 10, 10

Oracle分页语法:

SELECT * FROM (
    SELECT a.*, ROWNUM rn FROM (
        SELECT * FROM table_name ORDER BY sort_field
    ) a WHERE ROWNUM <= pageNum*pageSize
) WHERE rn > (pageNum-1)*pageSize

PostgreSQL分页语法:

SELECT * FROM table_name LIMIT pageSize OFFSET offset

1.4 SpringBoot中的分页抽象

Spring Data项目对分页进行了高度抽象,主要包含以下核心接口:

  1. Pageable:分页请求的抽象接口,包含分页和排序信息
  2. Page:包含数据和分页信息的接口
  3. Sort:排序规则的抽象

这种抽象使得开发者可以用统一的方式处理不同数据源的分页,无论是JPA、MongoDB还是Elasticsearch。

二、SpringBoot基础分页实现

2.1 使用Spring Data JPA实现分页

2.1.1 基础环境搭建

首先确保你的项目包含必要依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>

2.1.2 实体类定义

定义一个简单的用户实体:

@Entity
@Table(name = "t_user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(nullable = false, length = 50)
    private String username;
    
    @Column(nullable = false, length = 100)
    private String email;
    
    @Column(name = "create_time", updatable = false)
    @CreationTimestamp
    private LocalDateTime createTime;
    
    // 省略getter/setter和toString
}

2.1.3 Repository接口定义

创建支持分页的Repository接口:

public interface UserRepository extends JpaRepository<User, Long> {
    
    // 方法1:使用预定义的findAll(Pageable)
    // 已由父接口提供,无需额外声明
    
    // 方法2:自定义查询+分页
    @Query("SELECT u FROM User u WHERE u.email LIKE %:email%")
    Page<User> findByEmailContaining(@Param("email") String email, Pageable pageable);
    
    // 方法3:基于方法命名规则的查询
    Page<User> findByUsernameContaining(String username, Pageable pageable);
}

2.1.4 服务层实现

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    
    /**
     * 基础分页查询
     * @param pageNum 页码(从0开始)
     * @param pageSize 每页大小
     * @return 分页数据
     */
    public Page<User> getUsers(int pageNum, int pageSize) {
        // 构建分页请求
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return userRepository.findAll(pageable);
    }
    
    /**
     * 带条件的分页查询
     * @param username 用户名模糊查询条件
     * @param pageNum 页码
     * @param pageSize 每页大小
     * @return 分页数据
     */
    public Page<User> getUsersByUsername(String username, int pageNum, int pageSize) {
        Pageable pageable = PageRequest.of(pageNum, pageSize);
        return userRepository.findByUsernameContaining(username, pageable);
    }
}

2.1.5 控制器层

@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
    private final UserService userService;
    
    /**
     * 获取用户分页列表
     * @param page 页码,默认为0
     * @param size 每页大小,默认为10
     * @return 分页结果
     */
    @GetMapping
    public ResponseEntity<Page<User>> listUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<User> users = userService.getUsers(page, size);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据用户名搜索用户
     * @param username 搜索关键词
     * @param page 页码
     * @param size 每页大小
     * @return 分页结果
     */
    @GetMapping("/search")
    public ResponseEntity<Page<User>> searchUsers(
            @RequestParam String username,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<User> users = userService.getUsersByUsername(username, page, size);
        return ResponseEntity.ok(users);
    }
}

2.1.6 分页结果分析

调用/api/users?page=0&size=5将返回类似如下的JSON结构:

{
  "content": [
    {
      "id": 1,
      "username": "user1",
      "email": "user1@example.com",
      "createTime": "2023-01-01T10:00:00"
    },
    // ...其他4条数据
  ],
  "pageable": {
    "sort": {
      "sorted": false,
      "unsorted": true,
      "empty": true
    },
    "pageNumber": 0,
    "pageSize": 5,
    "offset": 0,
    "paged": true,
    "unpaged": false
  },
  "last": false,
  "totalPages": 20,
  "totalElements": 100,
  "number": 0,
  "size": 5,
  "sort": {
    "sorted": false,
    "unsorted": true,
    "empty": true
  },
  "first": true,
  "numberOfElements": 5,
  "empty": false
}

总结

本文全面探讨了SpringBoot中的各种分页查询技术,从基础的JPA和MyBatis实现,到高级的分页技巧和复杂场景解决方案。我们涵盖了:

  1. 分页的核心概念与原理
  2. 基础分页实现方式
  3. 高级分页功能(排序、动态条件等)
  4. 前端整合与最佳实践
  5. 性能优化与常见问题
  6. 特殊场景解决方案
  7. 测试策略
  8. 未来发展方向

分页作为数据展示的基础功能,其实现质量直接影响用户体验和系统性能。希望本文能帮助你在实际项目中实现高效、稳定的分页功能。记住,没有放之四海而皆准的分业方案,最重要的是根据你的具体业务需求和技术环境选择最适合的实现方式。

由于篇幅原因,这里只展示了一种方法,关注微信公众号获取更多更全的分页方法。

关注我?别别别,我怕你笑出腹肌找我赔钱。


头条对markdown的文章显示不太友好,想了解更多的可以关注微信公众号:“Eric的技术杂货库”,有更多的干货以及资料下载。

最近发表
标签列表