【Spring Boot】 JPA分页查询实现方式小结

当接口请求需要分页数据时,分页参数(如 page 和 size)通常不需要存储在实体中,而是通过 Spring Data JPA 提供的分页功能来实现。这涉及到对 Controller、 Service 和 Repository 的改造。以下是完整的实现说明和代码示例。

1. 使用 Pageable 和 Page 接口

Spring Data JPA 内置了分页支持,可以直接通过 Pageable 和 Page 来处理分页逻辑。

Controller 层

示例代码

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public Page<User> getUsers(
            @PageableDefault(size = 10, page = 0) Pageable pageable) {
        return userService.getUsers(pageable);
    }
}

关键点

1.	分页参数的注解:
•	使用 @PageableDefault 提供默认分页参数,如每页大小为 10,起始页为 0。
2.	返回值类型:使用 Page<User>,直接返回分页结果,包含总记录数、总页数等元信息。

Service 层

示例代码

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public Page<User> getUsers(Pageable pageable) {
        return userRepository.findAll(pageable);
    }
}

关键点

1.	方法参数:接收 Pageable 对象,用于封装分页参数。
2.	返回结果:直接返回 Page<User>,由 Repository 提供。

Repository 层

Spring Data JPA 已内置分页支持,因此无需额外改动,只需确保 Repository 继承自 JpaRepository。

示例代码

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}

前端示例请求

假设分页参数为 page 和 size,请求示例如下:

GET /api/users?page=1&size=5

返回结果示例

Spring Data JPA 自动封装分页结果,返回类似以下的 JSON:

{
  "content": [
    { "id": 1, "name": "Alice", "email": "alice@example.com" },
    { "id": 2, "name": "Bob", "email": "bob@example.com" }
  ],
  "pageable": {
    "sort": {
      "empty": true,
      "sorted": false,
      "unsorted": true
    },
    "offset": 5,
    "pageNumber": 1,
    "pageSize": 5,
    "paged": true,
    "unpaged": false
  },
  "last": false,
  "totalPages": 10,
  "totalElements": 50,
  "size": 5,
  "number": 1,
  "sort": {
    "empty": true,
    "sorted": false,
    "unsorted": true
  },
  "numberOfElements": 5,
  "first": false,
  "empty": false
}

优化分页结果(可选)

如果不想返回冗余的分页元数据,可以自定义响应格式:

修改 Controller

@GetMapping
public Map<String, Object> getUsers(
        @PageableDefault(size = 10, page = 0) Pageable pageable) {
    Page<User> page = userService.getUsers(pageable);

    Map<String, Object> response = new HashMap<>();
    response.put("users", page.getContent());
    response.put("currentPage", page.getNumber());
    response.put("totalItems", page.getTotalElements());
    response.put("totalPages", page.getTotalPages());

    return response;
}

自定义返回的 JSON

{
  "users": [
    { "id": 1, "name": "Alice", "email": "alice@example.com" },
    { "id": 2, "name": "Bob", "email": "bob@example.com" }
  ],
  "currentPage": 1,
  "totalItems": 50,
  "totalPages": 10
}

总结

•	Controller 层:接受分页参数 Pageable。
•	Service 层:直接调用 Repository 的分页方法。
•	Repository 层:无需额外修改,Spring Data JPA 自动支持分页。
•	可选优化:根据业务需求,定制化分页响应格式。

通过改造,分页参数不会存储到实体中,同时接口可以支持灵活的分页查询。


在 Spring Boot 中,默认情况下,分页参数的名称是 page 和 size,如果需要自定义这些参数的名称,可以使用 @PageableDefault 和 @Qualifier 注解进行设置。

自定义分页参数名称的实现方法

通过 @RequestParam 手动绑定自定义参数名,然后构造一个 Pageable 对象传递给 Service 层。

修改 Controller

import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public Page<User> getUsers(
            @RequestParam(name = "currentPage", defaultValue = "0") int page,
            @RequestParam(name = "pageSize", defaultValue = "10") int size) {
        Pageable pageable = PageRequest.of(page, size);
        return userService.getUsers(pageable);
    }
}

示例请求

GET /api/users?currentPage=1&pageSize=5

自定义分页参数的全局配置(更高级方法)

如果希望在全局范围内统一自定义分页参数名称,可以自定义 HandlerMethodArgumentResolver 来修改默认的分页参数行为。

自定义配置类

import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
public class CustomWebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
        resolver.setPageParameterName("currentPage"); // 自定义分页参数名称
        resolver.setSizeParameterName("pageSize");   // 自定义每页大小参数名称
        resolver.setOneIndexedParameters(true);      // 支持从 1 开始的分页
        resolvers.add(resolver);
    }
}

Controller 使用分页参数(无需手动绑定)

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping
    public Page<User> getUsers(Pageable pageable) {
        return userService.getUsers(pageable);
    }
}

示例请求

GET /api/users?currentPage=1&pageSize=5

返回结果示例

无论使用哪种方法,Spring Data JPA 都会处理分页逻辑,返回包含分页元信息和数据内容的结果,例如:

{
  "content": [
    { "id": 1, "name": "Alice", "email": "alice@example.com" },
    { "id": 2, "name": "Bob", "email": "bob@example.com" }
  ],
  "pageable": {
    "sort": {
      "empty": true,
      "sorted": false,
      "unsorted": true
    },
    "offset": 5,
    "pageNumber": 1,
    "pageSize": 5,
    "paged": true,
    "unpaged": false
  },
  "totalPages": 10,
  "totalElements": 50,
  "last": false,
  "size": 5,
  "number": 1,
  "numberOfElements": 5,
  "first": false,
  "empty": false
}

总结

1.	自定义分页参数名称:
•	方法 1:在 Controller 中使用 @RequestParam 手动绑定。
•	方法 2:全局配置,通过自定义 PageableHandlerMethodArgumentResolver 修改默认行为。
2.	关键点:
•	setPageParameterName(String):设置分页参数名称。
•	setSizeParameterName(String):设置每页大小的参数名称。
•	setOneIndexedParameters(boolean):设置是否支持 1 基索引。
3.	推荐方式:
•	若需要全局统一修改参数名称,优先选择方法 2,代码更简洁。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值