Overview
本教程向您展示如何在连接到MongoDB 的Quarkus应用程序中实现分页技术。您学习如何使用 Jakarta 数据存储库创建同时支持基于偏移和基于游标的分页方法的 REST API 终结点。
分页
分页是一种将大型数据集划分为更小、更易于管理的数据块的技术。 本教程实现了基于偏移和基于游标的分页方法。基于偏移量的分页使用页码来检索特定的数据子集,而基于游标的分页使用参考点或游标来浏览数据集。
Tutorial
本教程介绍如何执行以下操作:
验证先决条件
创建具有所需依赖项的 Quarkus项目
配置MongoDB连接
定义数据实体和存储库
实现用于分页的REST API终结点
测试分页终结点
验证先决条件。
在开始之前,请完成以下先决任务:
在MongoDB Atlas或本地Docker实例上配置MongoDB 集群
要使用Docker启动本地MongoDB实例,运行以下命令:
docker run --rm -d --name mongodb-instance -p 27017:27017 mongo
或者,您可以使用MongoDB Atlas并部署免费的 M0集群。要学习;了解如何创建Atlas帐户和集群,请参阅MongoDB入门指南。
创建 Quarkus项目。
导航到 Quarkus Code Generator 并使用以下设置配置您的项目:
选择首选群组和工件ID。
添加以下依赖项:
JNoSQL 文档MongoDB (
quarkus-jnosql-document-mongodb)RESTEasy 响应式 (
quarkus-resteasy-reactive)RESTEasy Reactive Jackson (
quarkus-resteasy-reactive-jackson)OpenAPI (
quarkus-smallrye-openapi)
生成项目,下载ZIP文件并将其解压缩。
注意
如果在生成器中找不到依赖项,请将其手动添加到 pom.xml文件中。
完成设置后,请验证您的 pom.xml文件是否包含以下依赖项:
<dependencies> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-smallrye-openapi</artifactId> </dependency> <dependency> <groupId>io.quarkiverse.jnosql</groupId> <artifactId>quarkus-jnosql-document-mongodb</artifactId> <version>3.3.0</version> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-reactive</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-resteasy-reactive-jackson</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-arc</artifactId> </dependency> <dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-junit5</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.rest-assured</groupId> <artifactId>rest-assured</artifactId> <scope>test</scope> </dependency> </dependencies>
配置MongoDB 数据库。
打开 application.properties文件并添加以下配置属性以连接到MongoDB实例:
quarkus.mongodb.connection-string = <your connection string> jnosql.document.database = fruits
此配置使您的应用程序能够通过指定的连接字符串连接到MongoDB 集群并使用 fruits数据库。
重要
在生产环境中,启用访问权限控制并实施身份验证。有关详细信息,请参阅安全检查清单。
您可以使用环境变量覆盖这些属性,这样您就可以为开发、测试和生产指定不同的配置,而无需修改代码。
创建数据实体。
在 src/main/java目录中创建 Fruit 实体类。以下代码定义具有 id 和 name 字段的实体:
import jakarta.nosql.Column; import jakarta.nosql.Convert; import jakarta.nosql.Entity; import jakarta.nosql.Id; import org.eclipse.jnosql.databases.mongodb.mapping.ObjectIdConverter; public class Fruit { private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return "Fruit{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; } public static Fruit of(String name) { Fruit fruit = new Fruit(); fruit.setName(name); return fruit; } }
创建存储库接口。
创建用于扩展 BasicRepository 类的 FruitRepository 接口。以下代码定义了基于偏移和基于游标的分页方法:
import jakarta.data.Sort; import jakarta.data.page.CursoredPage; import jakarta.data.page.Page; import jakarta.data.page.PageRequest; import jakarta.data.repository.BasicRepository; import jakarta.data.repository.Find; import jakarta.data.repository.OrderBy; import jakarta.data.repository.Repository; public interface FruitRepository extends BasicRepository<Fruit, String> { CursoredPage<Fruit> cursor(PageRequest pageRequest, Sort<Fruit> order); Page<Fruit> offSet(PageRequest pageRequest); long countBy(); }
框架会自动实现此接口,使您无需编写样板代码即可执行数据库操作。
创建数据库设置程序类。
在 src/main/java目录中创建一个 SetupDatabase 类。以下代码在初创企业时使用示例数据填充数据库,并在关闭时删除数据:
import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; import io.quarkus.runtime.ShutdownEvent; import io.quarkus.runtime.StartupEvent; import org.jboss.logging.Logger; import java.util.List; public class SetupDatabase { private static final Logger LOGGER = Logger.getLogger(SetupDatabase.class.getName()); private final FruitRepository fruitRepository; public SetupDatabase(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } void onStart( StartupEvent ev) { LOGGER.info("The application is starting..."); long count = fruitRepository.countBy(); if (count > 0) { LOGGER.info("Database already populated"); return; } List<Fruit> fruits = List.of( Fruit.of("apple"), Fruit.of("banana"), Fruit.of("cherry"), Fruit.of("date"), Fruit.of("elderberry"), Fruit.of("fig"), Fruit.of("grape"), Fruit.of("honeydew"), Fruit.of("kiwi"), Fruit.of("lemon") ); fruitRepository.saveAll(fruits); } void onStop( ShutdownEvent ev) { LOGGER.info("The application is stopping..."); fruitRepository.deleteAll(fruitRepository.findAll().toList()); } }
创建REST API端点。
在 src/main/java目录中创建一个 FruitResource 类。然后,将以下代码粘贴到类文件中:
import jakarta.data.Sort; import jakarta.data.page.PageRequest; import jakarta.ws.rs.DefaultValue; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.QueryParam; import jakarta.ws.rs.core.MediaType; public class FruitResource { private final FruitRepository fruitRepository; private static final Sort<Fruit> ASC = Sort.asc("name"); private static final Sort<Fruit> DESC = Sort.desc("name"); public FruitResource(FruitRepository fruitRepository) { this.fruitRepository = fruitRepository; } public Iterable<Fruit> offset( long page, int size) { var pageRequest = PageRequest.ofPage(page).size(size); return fruitRepository.offSet(pageRequest).content(); } public Iterable<Fruit> cursor( String after, String before, int size) { if (!after.isBlank()) { var pageRequest = PageRequest.ofSize(size).afterCursor(PageRequest.Cursor.forKey(after)); return fruitRepository.cursor(pageRequest, ASC).content(); } else if (!before.isBlank()) { var pageRequest = PageRequest.ofSize(size).beforeCursor(PageRequest.Cursor.forKey(before)); return fruitRepository.cursor(pageRequest, DESC).stream().toList(); } var pageRequest = PageRequest.ofSize(size); return fruitRepository.cursor(pageRequest, ASC).content(); } }
该类定义了以下终结点:
/fruits/offset:使用page查询参数支持基于偏移量的分页。/fruits/cursor:使用after和before查询参数支持基于游标的分页。
两个终结点还接受 size查询参数来指定每页的列项数。
测试基于游标的分页。
使用以下 curl 命令测试游标分页端点。这些命令使用 after 和 before 参数浏览数据集。
要获取初始水果设立,运行以下命令:
curl --location http://localhost:8080/fruits/cursor
要获取 name字段值在 "banana" 之后的水果,运行以下命令:
curl --location http://localhost:8080/fruits/cursor?after=banana
要获取 name字段值在 "date" 之前的水果,运行以下命令:
curl --location http://localhost:8080/fruits/cursor?before=date
其他资源
要学习有关MongoDB分页的更多信息,请参阅MongoDB Atlas文档中的分页结果指南。
要学习;了解有关 Quarkus 的更多信息,请参阅Quarkus 文档。