在 Spring Boot 中,实现分页查询有多种方式,下面我将介绍几种常见的分页实现方法,包括 Spring Data JPA 分页、MyBatis 分页、手动分页等。
这是最简单和常用的分页方式,Spring Data JPA 内置了分页支持。
首先,添加依赖:
org.springframework.boot
spring-boot-starter-data-jpa
com.mysql
mysql-connector-j
实体类:
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// getters, setters, constructors...
}
Repository 接口:
public interface UserRepository extends JpaRepository {
Page findByNameContaining(String name, Pageable pageable);
}
Service 层:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public Page getUsersByName(String name, int page, int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
return userRepository.findByNameContaining(name, pageable);
}
}
Controller 层:
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public ResponseEntity> getUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(userService.getUsersByName(name, page, size));
}
}
有时我们需要自定义返回数据结构:
public class PageResult {
private List content;
private int page;
private int size;
private long totalElements;
private int totalPages;
// getters, setters...
public static PageResult fromPage(Page page) {
PageResult result = new PageResult<>();
result.setContent(page.getContent());
result.setPage(page.getNumber());
result.setSize(page.getSize());
result.setTotalElements(page.getTotalElements());
result.setTotalPages(page.getTotalPages());
return result;
}
}
然后在 Controller 中使用:
@GetMapping("/custom")
public ResponseEntity> getUsersCustom(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Page userPage = userService.getUsersByName(name, page, size);
return ResponseEntity.ok(PageResult.fromPage(userPage));
}
添加依赖:
com.github.pagehelper
pagehelper-spring-boot-starter
最新版本
Mapper 接口:
@Mapper
public interface UserMapper {
List findByName(@Param("name") String name);
}
Service 层:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public PageInfo getUsersByName(String name, int page, int size) {
PageHelper.startPage(page, size);
List users = userMapper.findByName(name);
return new PageInfo<>(users);
}
}
Controller 层:
@GetMapping("/mybatis")
public ResponseEntity> getUsersMybatis(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(userService.getUsersByName(name, page, size));
}
添加依赖:
com.baomidou
mybatis-plus-boot-starter
最新版本
配置分页插件:
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
Mapper 接口:
public interface UserMapper extends BaseMapper {
// 继承基本方法
}
Service 层:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public IPage getUsersByName(String name, int page, int size) {
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.like("name", name);
return userMapper.selectPage(new Page<>(page, size), wrapper);
}
}
Controller 层:
@GetMapping("/mybatis-plus")
public ResponseEntity> getUsersMybatisPlus(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return ResponseEntity.ok(userService.getUsersByName(name, page, size));
}
当数据量不大或需要特殊处理时,可以使用手动分页:
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List getUsersManually(String name, int page, int size) {
List allUsers = userRepository.findByNameContaining(name);
int fromIndex = page * size;
if (fromIndex >= allUsers.size()) {
return Collections.emptyList();
}
int toIndex = Math.min(fromIndex + size, allUsers.size());
return allUsers.subList(fromIndex, toIndex);
}
public Map getUsersWithTotal(String name, int page, int size) {
List allUsers = userRepository.findByNameContaining(name);
List pageContent = getUsersManually(name, page, size);
Map result = new HashMap<>();
result.put("content", pageContent);
result.put("currentPage", page);
result.put("pageSize", size);
result.put("totalElements", allUsers.size());
result.put("totalPages", (int) Math.ceil((double) allUsers.size() / size));
return result;
}
}
Controller 层:
@GetMapping("/manual")
public ResponseEntity
可以创建一个分页参数类来自动绑定分页参数:
public class PageParam {
@Min(0)
private int page = 0;
@Min(1)
@Max(100)
private int size = 10;
private String sort = "id,asc"; // 格式: field,direction
// getters, setters...
public Pageable toPageable() {
String[] parts = sort.split(",");
if (parts.length == 2) {
return PageRequest.of(page, size,
Sort.by(Sort.Direction.fromString(parts[1]), parts[0]));
}
return PageRequest.of(page, size);
}
}
Controller 使用:
@GetMapping("/auto-page")
public ResponseEntity> getUsersAutoPage(
@RequestParam(required = false) String name,
PageParam pageParam) {
return ResponseEntity.ok(userRepository.findByNameContaining(name, pageParam.toPageable()));
}
如果使用 Spring WebFlux:
添加依赖:
org.springframework.boot
spring-boot-starter-data-mongodb-reactive
org.springframework.boot
spring-boot-starter-webflux
Repository:
public interface ReactiveUserRepository extends ReactiveMongoRepository {
Flux findByNameContaining(String name, Pageable pageable);
}
Service:
@Service
public class ReactiveUserService {
@Autowired
private ReactiveUserRepository userRepository;
public Mono> getUsers(String name, int page, int size) {
Pageable pageable = PageRequest.of(page, size);
Flux userFlux = userRepository.findByNameContaining(name, pageable);
Mono countMono = userRepository.countByNameContaining(name);
return Mono.zip(userFlux.collectList(), countMono)
.map(tuple -> new PageImpl<>(tuple.getT1(), pageable, tuple.getT2()));
}
}
Controller:
@RestController
@RequestMapping("/api/reactive/users")
public class ReactiveUserController {
@Autowired
private ReactiveUserService userService;
@GetMapping
public Mono>> getUsers(
@RequestParam(required = false) String name,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
return userService.getUsers(name, page, size)
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
}
Spring Data JPA 分页:最简单,适合大多数 CRUD 应用
MyBatis 分页:
PageHelper:简单易用
MyBatis-Plus:功能更强大
手动分页:灵活,适合特殊需求
自动绑定分页参数:提高代码整洁度
响应式分页:适合响应式应用
根据项目需求和技术栈选择合适的分页方式。对于大多数 Spring Boot 项目,Spring Data JPA 或 MyBatis-Plus 的分页功能已经足够强大且易于使用。