Visão geral
Este tutorial mostra como implementar técnicas de paginação em um aplicativo do Quarkus conectado ao MongoDB. Você aprenderá a usar o repositório de dados de Jakarta para criar pontos de extremidade de REST API com suporte para métodos de paginação baseados em offset e em cursor.
Paginação
A paginação é uma técnica usada para dividir grandes conjuntos de dados em partes menores e mais gerenciáveis. Este tutorial implementa métodos de paginação baseados em offset e em cursor. A paginação baseada em offset utiliza números de página para recuperar subconjuntos específicos de dados, enquanto a paginação baseada em cursor utiliza um ponto de referência, ou um cursor, para navegar pelo conjunto de dados.
Tutorial
Este tutorial mostra como executar as seguintes ações:
Verifique os pré-requisitos
Criar um projeto Quartokus com as dependências necessárias
Configurar a conexão do MongoDB
Definir uma entidade de dados e um repositório
Implementar pontos de extremidade de REST API para paginação
Teste os pontos de extremidade da paginação
Verifique os pré-requisitos.
Antes de começar, conclua as seguintes tarefas de pré-requisito:
Configurar um cluster MongoDB , seja no MongoDB Atlas ou em uma instância local do Docker
Para iniciar uma instância local do MongoDB com Docker, execute o seguinte comando:
docker run --rm -d --name mongodb-instance -p 27017:27017 mongo
Alternativamente, você pode usar o MongoDB Atlas e implantar um cluster M0 gratuito. Para aprender como criar uma conta e um cluster do Atlas, consulte o guia Introdução ao MongoDB.
Criar um projeto no Quartokus.
Navegue até o Gerador de Código Quarto e configure seu projeto com as seguintes configurações:
Selecione seu grupo preferido e ID do artefato.
Adicione as seguintes dependências:
Documento JNoSQL MongoDB (
quarkus-jnosql-document-mongodb)RESTEasy Reactive (
quarkus-resteasy-reactive)RESTEasy Reactive jackson (
quarkus-resteasy-reactive-jackson)OpenAPI (
quarkus-smallrye-openapi)
Gere o projeto, baixe o arquivo ZIP e extraia-o.
Observação
Se você não conseguir encontrar uma dependência no gerador, adicione-a manualmente ao arquivo pom.xml.
Depois de concluir a configuração, verifique se seu arquivo pom.xml inclui as seguintes dependências:
<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>
Configure o banco de dados MongoDB.
Abra o arquivo application.properties e adicione as seguintes propriedades de configuração para conectar à sua instância MongoDB :
quarkus.mongodb.connection-string = <your connection string> jnosql.document.database = fruits
Esta configuração permite que seu aplicativo se conecte ao cluster MongoDB na string de conexão especificada e use o banco de dados fruits.
Importante
Em ambientes de produção, habilite o controle de acesso e imponha a autenticação. Para obter mais informações, consulte a Lista de verificação de segurança.
Você pode substituir essas propriedades usando variáveis de ambiente, que permitem especificar diferentes configurações para desenvolvimento, teste e produção sem modificar seu código.
Crie uma entidade de dados.
Crie uma classe de entidade Fruit no diretório src/main/java. O seguinte código define a entidade com campos id e 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; } }
Crie uma interface de repositório.
Crie uma interface FruitRepository que estenda a classe BasicRepository . O código a seguir define métodos para paginação baseada em offset e cursor:
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(); }
O framework implementa automaticamente essa interface, permitindo que você execute operações de banco de dados sem escrever código boilerplate.
Crie uma classe de configuração de banco de dados.
Crie uma classe SetupDatabase no diretório src/main/java. O seguinte código preenche o banco de dados com dados de amostra na inicialização e exclui os dados no desligamento:
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()); } }
Crie pontos de extremidade de REST API.
Crie uma classe FruitResource no diretório src/main/java. Em seguida, cole o seguinte código no arquivo da classe :
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(); } }
Esta classe define os seguintes pontos de extremidade:
/fruits/offset: suporta paginação baseada em offset usando o parâmetro de querypage./fruits/cursor: suporta paginação baseada em cursor utilizando os parâmetros de consultaafterebefore.
Ambos os endpoints também aceitam o parâmetro de query do size para especificar o número de itens por página.
Teste a paginação baseada em offset.
Em uma janela de terminal separada, use os seguintes comandos curl para testar o ponto de extremidade da paginação de deslocamento. Estes comandos solicitam diferentes páginas de dados de frutas.
Para buscar a primeira página, execute o seguinte comando:
curl --location http://localhost:8080/fruits/offset?page=1
Para buscar a segunda página, execute o seguinte comando:
curl --location http://localhost:8080/fruits/offset?page=2
Para buscar a quinta página, execute o seguinte comando:
curl --location http://localhost:8080/fruits/offset?page=5
Teste a paginação baseada em cursor.
Use os seguintes comandos curl para testar o ponto de extremidade da paginação do cursor. Estes comandos utilizam os parâmetros after e before para navegar pelo conjunto de dados.
Para buscar o conjunto inicial de frutas, execute o seguinte comando:
curl --location http://localhost:8080/fruits/cursor
Para buscar frutas com valores de campo name que vêm após "banana", execute o seguinte comando:
curl --location http://localhost:8080/fruits/cursor?after=banana
Para buscar frutas com valores de campo name que vêm antes de "date", execute o seguinte comando:
curl --location http://localhost:8080/fruits/cursor?before=date
Recursos adicionais
Para saber mais sobre paginação no MongoDB, consulte o guia Paginar resultados na documentação do MongoDB Atlas.
Para saber mais sobre o Quarkus, consulte a documentação do Quarkus.