Spring Boot 分页
最后修改于 2023 年 7 月 27 日
在本文中,我们将展示如何在 Spring 应用中对数据进行分页。
Spring 是一个流行的 Java 应用程序框架,而 Spring Boot 是 Spring 的一个演进,它有助于轻松创建独立的、生产级的基于 Spring 的应用程序。
分页
分页是将数据分成合适的块以节省资源的过程。
PagingAndSortingRepository
PagingAndSortingRepository
是 CrudRepository
的扩展,提供额外的使用分页和排序检索实体的方法。
Spring Boot 分页示例
在下面的应用中,我们创建一个简单的 Spring Boot Restful 应用,它允许对数据进行分页。
build.gradle ... src ├───main │ ├───java │ │ └───com │ │ └───zetcode │ │ │ Application.java │ │ ├───controller │ │ │ MyController.java │ │ ├───model │ │ │ Country.java │ │ ├───repository │ │ │ CountryRepository.java │ │ └───service │ │ CountryService.java │ │ ICountryService.java │ └───resources │ application.properties │ import.sql └───test └───java
这是项目结构。
plugins { id 'org.springframework.boot' version '3.1.1' id 'io.spring.dependency-management' version '1.1.0' id 'java' } group = 'com.zetcode' version = '0.0.1-SNAPSHOT' sourceCompatibility = '17' repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' }
这是 Gradle 构建文件。h2
依赖项包含 H2 数据库驱动程序。
spring-boot-starter-web
启用 Web 应用,包括经典应用和 RESTful 应用。它使用 Tomcat 作为默认的嵌入式容器。spring-boot-starter-data-jpa
是一个用于将 Spring Data JPA 与 Hibernate 结合使用的启动器。
spring.main.banner-mode=off spring.jpa.hibernate.ddl-auto=create-drop
在 application.properties
文件中,我们编写了 Spring Boot 应用的各种配置设置。使用 banner-mode
属性,我们关闭了 Spring 横幅。
create-drop
选项会自动创建和删除数据库模式。H2 数据库在内存中运行。
INSERT INTO countries(name, population) VALUES('China', 1382050000); INSERT INTO countries(name, population) VALUES('India', 1313210000); INSERT INTO countries(name, population) VALUES('USA', 324666000); INSERT INTO countries(name, population) VALUES('Indonesia', 260581000); INSERT INTO countries(name, population) VALUES('Brazil', 207221000); INSERT INTO countries(name, population) VALUES('Pakistan', 196626000); INSERT INTO countries(name, population) VALUES('Nigeria', 186988000); INSERT INTO countries(name, population) VALUES('Bangladesh', 162099000); INSERT INTO countries(name, population) VALUES('Russia', 146838000); INSERT INTO countries(name, population) VALUES('Japan', 126830000); INSERT INTO countries(name, population) VALUES('Mexico', 122273000); INSERT INTO countries(name, population) VALUES('Philippines', 103738000); INSERT INTO countries(name, population) VALUES('Ethiopia', 101853000); INSERT INTO countries(name, population) VALUES('Vietnam', 92700000); INSERT INTO countries(name, population) VALUES('Egypt', 92641000); INSERT INTO countries(name, population) VALUES('Germany', 82800000); INSERT INTO countries(name, population) VALUES('the Congo', 82243000); INSERT INTO countries(name, population) VALUES('Iran', 82800000); INSERT INTO countries(name, population) VALUES('Turkey', 79814000); INSERT INTO countries(name, population) VALUES('Thailand', 68147000); INSERT INTO countries(name, population) VALUES('France', 66984000); INSERT INTO countries(name, population) VALUES('United Kingdom', 60589000); INSERT INTO countries(name, population) VALUES('South Africa', 55908000); INSERT INTO countries(name, population) VALUES('Myanmar', 51446000); INSERT INTO countries(name, population) VALUES('South Korea', 68147000); INSERT INTO countries(name, population) VALUES('Colombia', 49129000); INSERT INTO countries(name, population) VALUES('Kenya', 47251000); INSERT INTO countries(name, population) VALUES('Spain', 46812000); INSERT INTO countries(name, population) VALUES('Argentina', 43850000); INSERT INTO countries(name, population) VALUES('Ukraine', 42603000); INSERT INTO countries(name, population) VALUES('Sudan', 41176000); INSERT INTO countries(name, population) VALUES('Algeria', 40400000); INSERT INTO countries(name, population) VALUES('Poland', 38439000); INSERT INTO countries(name, population) VALUES('Canada', 37742154); INSERT INTO countries(name, population) VALUES('Morocco', 36910560); INSERT INTO countries(name, population) VALUES('Saudi Arabia', 34813871); INSERT INTO countries(name, population) VALUES('Uzbekistan', 33469203); INSERT INTO countries(name, population) VALUES('Peru', 32971854); INSERT INTO countries(name, population) VALUES('Angola', 32866272); INSERT INTO countries(name, population) VALUES('Malaysia', 32365999); INSERT INTO countries(name, population) VALUES('Mozambique', 31255435); INSERT INTO countries(name, population) VALUES('Ghana', 31072940); INSERT INTO countries(name, population) VALUES('Yemen', 29825964); INSERT INTO countries(name, population) VALUES('Nepal', 29136808); INSERT INTO countries(name, population) VALUES('Venezuela', 28435940);
模式由 Hibernate 自动创建;之后,执行 import.sql
文件以填充表数据。
package com.zetcode.model; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import java.util.Objects; @Entity @Table(name = "countries") public class Country { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private int population; public Country() { } public Country(Long id, String name, int population) { this.id = id; this.name = name; this.population = population; } public Long getId() { return id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPopulation() { return population; } public void setPopulation(int population) { this.population = population; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Country country = (Country) o; return population == country.population && Objects.equals(id, country.id) && Objects.equals(name, country.name); } @Override public int hashCode() { return Objects.hash(id, name, population); } @Override public String toString() { final StringBuilder sb = new StringBuilder("Country{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", population=").append(population); sb.append('}'); return sb.toString(); } }
这是 Country
实体。每个实体必须至少定义两个注解:@Entity
和 @Id
。之前,我们将 ddl-auto
选项设置为 create-drop
,这意味着 Hibernate 将从该实体创建表模式。
@Entity @Table(name = "countries") public class Country {
@Entity
注解指定该类是一个实体,并映射到一个数据库表。@Table
注解指定用于映射的数据库表的名称。
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;
@Id
注解指定实体的**主键**,而 @GeneratedValue
为主键的值提供了生成策略。
package com.zetcode.repository; import com.zetcode.model.Country; import org.springframework.data.repository.PagingAndSortingRepository; import org.springframework.stereotype.Repository; @Repository public interface CountryRepository extends PagingAndSortingRepository<Country, Long> { }
CountryRepository
使用 @Repository
注解进行修饰。通过从 Spring 的 PagingAndSortingRepository
扩展,我们有一些方法可以对数据进行分页。
package com.zetcode.service; import com.zetcode.model.Country; import java.util.List; public interface ICountryService { List<Country> findPaginated(int pageNo, int pageSize); }
ICountryService
包含 findPaginated
契约方法。它包含两个参数:页码和页面大小。
package com.zetcode.service; import com.zetcode.model.Country; import com.zetcode.repository.CountryRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import java.util.List; @Service public class CountryService implements ICountryService { private final CountryRepository repository; @Autowired public CountryService(CountryRepository repository) { this.repository = repository; } @Override public List<Country> findPaginated(int pageNo, int pageSize) { Pageable paging = PageRequest.of(pageNo, pageSize); Page<Country> pagedResult = repository.findAll(paging); return pagedResult.toList(); } }
CountryService
包含 findPaginated
方法的实现。
private final CountryRepository repository; @Autowired public CountryService(CountryRepository repository) { this.repository = repository; }
CountryRepository
被注入到字段中。
Pageable paging = PageRequest.of(pageNo, pageSize); Page<Country> pagedResult = repository.findAll(paging);
一个 PageRequest
从提供的值创建并传递给 findAll
存储库方法。
package com.zetcode.controller; import com.zetcode.model.Country; import com.zetcode.service.ICountryService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class MyController { private final ICountryService countryService; @Autowired public MyController(ICountryService countryService) { this.countryService = countryService; } @GetMapping("/countries/{pageNo}/{pageSize}") public List<Country> getPaginatedCountries(@PathVariable int pageNo, @PathVariable int pageSize) { return countryService.findPaginated(pageNo, pageSize); } }
MyController
处理来自客户端的请求。
private final ICountryService countryService; @Autowired public MyController(ICountryService countryService) { this.countryService = countryService; }
ICountryService
被注入到 countryService
字段中。
@GetMapping("/countries/{pageNo}/{pageSize}") public List<Country> getPaginatedCountries(@PathVariable int pageNo, @PathVariable int pageSize) { return countryService.findPaginated(pageNo, pageSize); }
我们提供页码和页面大小作为路径变量。这些值被传递给 findPaginated
服务方法。
package com.zetcode; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Application
是设置 Spring Boot 应用程序的入口点。
$ ./gradlew bootRun
我们运行应用程序。
$ curl localhost:8080/countries/0/5 [{"id":1,"name":"China","population":1382050000},{"id":2,"name":"India","population":1313210000}, {"id":3,"name":"USA","population":324666000},{"id":4,"name":"Indonesia","population":260581000}, {"id":5,"name":"Brazil","population":207221000}]
我们获得第一页的 5 行。索引从 0 开始。
$ curl localhost:8080/countries/1/5 [{"id":6,"name":"Pakistan","population":196626000},{"id":7,"name":"Nigeria","population":186988000}, {"id":8,"name":"Bangladesh","population":162099000},{"id":9,"name":"Russia","population":146838000}, {"id":10,"name":"Japan","population":126830000}]
我们获得下一页。
在本文中,我们展示了如何在 Spring Boot 应用中创建分页。