Introdução à paginação de dados com o Quarkus e o MongoDB: um tutorial abrangente
Otavio Santana7 min read • Published Apr 25, 2024 • Updated Apr 25, 2024
APLICATIVO COMPLETO
Avalie esse Tutorial
No desenvolvimento moderno da Web, o gerenciamento eficiente de grandes conjuntos de dados por meio de API é crucial para melhorar o desempenho do aplicativo e a experiência do usuário. Este tutorial explora técnicas de paginação usando Quarkus e MongoDB, uma combinação robusta para entrega de dados escalonável. Por meio de uma sessão de codificação ao vivo, nos aprofundaremos em diferentes métodos de paginação e demonstraremos como implementá-los em um ambiente MongoDB conectado ao Quarkus. Este guia capacita os desenvolvedores a otimizar REST API para um tratamento eficaz de dados.
1 git clone git@github.com:mongodb-developer/quarkus-pagination-sample.git
Para este tutorial, você precisará de:
- Java 21.
- Maven.
- Um cluster do MongoDB.
- MongoDB Atlas (Opção 1)
- Docker (Opção 2)
Você pode usar o seguinte comando do Docker para iniciar uma instância MongoDB standalone:
1 docker run --rm -d --name mongodb-instance -p 27017:27017 mongo
Ou você pode usar o MongoDB Atlas e experimentar o nível gratuito M0 para implantar seu cluster.
- Configure seu projeto selecionando as opções desejadas, como o ID do grupo e do artefato.
- Adicione as dependências necessárias ao seu projeto. Para este tutorial, adicionaremos:
- JNoSQL Document MongoDB [quarkus-jnosql-document-mongodb].
- RESTEasy Reactive [quakus-restasy-reactive].
- RESTEasy Reactive Jackson [quarkus-resteasy-reactive-jackson].
- OpenAPI [quarkus-smallrye-openapi].
Observação: se você não conseguir encontrar algumas dependências, poderá adicioná-las manualmente no
pom.xml
. Veja o arquivo abaixo.- Gere o projeto, baixe o arquivo ZIP e extraia-o no local de sua preferência. Lembre-se de que a estrutura do arquivo pode variar de acordo com as diferentes versões do Quarkus, mas isso deve ser suficiente para o tutorial. O foco principal será a modificação do arquivo
pom.xml
e do código-fonte, que permanece relativamente consistente em todas as versões. Quaisquer pequenas diferenças estruturais devem ser boas para o seu progresso, e você pode consultar a documentação específica da versão, se necessário, para obter uma experiência de aprendizado perfeita.
Neste ponto, seu arquivo pom.xml deve ficar assim:
1 <dependencies> 2 <dependency> 3 <groupId>io.quarkus</groupId> 4 <artifactId>quarkus-smallrye-openapi</artifactId> 5 </dependency> 6 <dependency> 7 <groupId>io.quarkiverse.jnosql</groupId> 8 <artifactId>quarkus-jnosql-document-mongodb</artifactId> 9 <version>3.3.0</version> 10 </dependency> 11 <dependency> 12 <groupId>io.quarkus</groupId> 13 <artifactId>quarkus-resteasy</artifactId> 14 </dependency> 15 <dependency> 16 <groupId>io.quarkus</groupId> 17 <artifactId>quarkus-resteasy-jackson</artifactId> 18 </dependency> 19 <dependency> 20 <groupId>io.quarkus</groupId> 21 <artifactId>quarkus-arc</artifactId> 22 </dependency> 23 <dependency> 24 <groupId>io.quarkus</groupId> 25 <artifactId>quarkus-junit5</artifactId> 26 <scope>test</scope> 27 </dependency> 28 <dependency> 29 <groupId>io.rest-assured</groupId> 30 <artifactId>rest-assured</artifactId> 31 <scope>test</scope> 32 </dependency> 33 </dependencies>
Trabalharemos com a versão mais recente do Quarkus junto com o Eclipse NoSQL Lite, uma integração simplificada que, notavelmente, não depende da reflexão. Essa abordagem melhora o desempenho e simplifica o processo de configuração, tornando-a a escolha ideal para desenvolvedores que buscam maximizar a eficiência em seus aplicativos.
Antes de mergulhar na implementação, é essencial configurar seu MongoDB database corretamente. No MongoDB, você deve definir credenciais e configurações específicas para se conectar à sua instância do banco de dados. O Eclipse JNoSQL fornece um mecanismo de configuração flexível que permite gerenciar essas configurações com eficiência.
Você pode encontrar configurações e configurações detalhadas para vários bancos de dados, incluindo o MongoDB, no repositório do Eclipse JNoSQL no GitHub.
Para executar o aplicativo localmente, você pode configurar o nome e as propriedades do banco de dados no arquivo
application.properties
do aplicativo . Abra esse arquivo e adicione a seguinte linha para definir o nome do banco de dados:1 quarkus.mongodb.connection-string = mongodb://localhost 2 jnosql.document.database = fruits
Esta configuração habilitará seu aplicativo para:
- Use o banco de dados "Frutas".
- Conecte-se ao cluster MongoDB disponível na connection string fornecida.
Na produção, certifique-se de ativar o controle de acesso e impor a autenticação. Consulte a lista de verificação de segurança para obter mais detalhes.
Importa realçar que o Eclipse JNoSQL utiliza o Eclipse MicroProfile Configuration, projetado para facilitar a implementação de aplicativos de 12 fatores, especialmente no gerenciamento de configurações. Isso significa que você pode substituir propriedades por variáveis de ambiente, permitindo alternar entre diferentes configurações para desenvolvimento, teste e produção sem modificar seu código. Essa flexibilidade é um aspecto valorizado na construção de aplicativos robustos e facilmente implementáveis.
Agora que seu banco de dados está configurado, você pode prosseguir com o tutorial e criar sua API RESTful com Quarkus e Eclipse JNoSQL para MongoDB.
Nesta etapa, criaremos uma entidade
Fruit
simples utilizando registros Java. Crie uma nova classe no diretóriosrc/main/java
denominada Fruit
.1 import jakarta.nosql.Column; 2 import jakarta.nosql.Convert; 3 import jakarta.nosql.Entity; 4 import jakarta.nosql.Id; 5 import org.eclipse.jnosql.databases.mongodb.mapping.ObjectIdConverter; 6 7 8 public class Fruit { 9 10 11 12 private String id; 13 14 15 private String name; 16 17 public String getId() { 18 return id; 19 } 20 21 public void setId(String id) { 22 this.id = id; 23 } 24 25 public String getName() { 26 return name; 27 } 28 29 public void setName(String name) { 30 this.name = name; 31 } 32 33 34 public String toString() { 35 return "Fruit{" + 36 "id='" + id + '\'' + 37 ", name='" + name + '\'' + 38 '}'; 39 } 40 41 public static Fruit of(String name) { 42 Fruit fruit = new Fruit(); 43 fruit.setName(name); 44 return fruit; 45 } 46 47 }
Simplificaremos a integração entre Java e MongoDB usando o repositório de dados Jakarta criando uma interface que estenda o NoSQLRepository. A estrutura implementa automaticamente essa interface, permitindo-nos definir métodos para recuperação de dados que se integram perfeitamente ao MongoDB. Vamos nos concentrar na implementação de dois tipos de paginação: paginação offset representada por
Page
e paginação keyset (cursor) representada por CursoredPage
.Veja como definimos a interface FruitRepository para incluir métodos para ambas as estratégias de paginação:
1 import jakarta.data.Sort; 2 import jakarta.data.page.CursoredPage; 3 import jakarta.data.page.Page; 4 import jakarta.data.page.PageRequest; 5 import jakarta.data.repository.BasicRepository; 6 import jakarta.data.repository.Find; 7 import jakarta.data.repository.OrderBy; 8 import jakarta.data.repository.Repository; 9 10 11 public interface FruitRepository extends BasicRepository<Fruit, String> { 12 13 14 CursoredPage<Fruit> cursor(PageRequest pageRequest, Sort<Fruit> order); 15 16 17 18 Page<Fruit> offSet(PageRequest pageRequest); 19 20 long countBy(); 21 22 }
Demonstraremos como preencher e gerenciar o MongoDB database com uma coleção de entradas de frutas no início do aplicativo usando o Quarkus. Garantiremos que nosso banco de dados seja inicializado com dados predefinidos e também faremos a limpeza no desligamento do aplicativo. Veja como podemos estruturar a classe SetupDatabase:
1 import jakarta.enterprise.context.ApplicationScoped; 2 3 import jakarta.enterprise.event.Observes; 4 5 import io.quarkus.runtime.ShutdownEvent; 6 import io.quarkus.runtime.StartupEvent; 7 import org.jboss.logging.Logger; 8 9 import java.util.List; 10 11 12 public class SetupDatabase { 13 14 private static final Logger LOGGER = Logger.getLogger(SetupDatabase.class.getName()); 15 16 private final FruitRepository fruitRepository; 17 18 public SetupDatabase(FruitRepository fruitRepository) { 19 this.fruitRepository = fruitRepository; 20 } 21 22 23 void onStart( StartupEvent ev) { 24 LOGGER.info("The application is starting..."); 25 long count = fruitRepository.countBy(); 26 if (count > 0) { 27 LOGGER.info("Database already populated"); 28 return; 29 } 30 List<Fruit> fruits = List.of( 31 Fruit.of("apple"), 32 Fruit.of("banana"), 33 Fruit.of("cherry"), 34 Fruit.of("date"), 35 Fruit.of("elderberry"), 36 Fruit.of("fig"), 37 Fruit.of("grape"), 38 Fruit.of("honeydew"), 39 Fruit.of("kiwi"), 40 Fruit.of("lemon") 41 ); 42 fruitRepository.saveAll(fruits); 43 } 44 45 void onStop( ShutdownEvent ev) { 46 LOGGER.info("The application is stopping..."); 47 fruitRepository.deleteAll(fruitRepository.findAll().toList()); 48 } 49 50 }
Agora, vamos criar uma API RESTful para gerenciar registros de desenvolvedores. Crie uma nova classe no
src/main/java
denominada FruitResource
.1 import jakarta.data.Sort; 2 import jakarta.data.page.PageRequest; 3 import jakarta.ws.rs.DefaultValue; 4 import jakarta.ws.rs.GET; 5 import jakarta.ws.rs.Path; 6 import jakarta.ws.rs.Produces; 7 import jakarta.ws.rs.QueryParam; 8 import jakarta.ws.rs.core.MediaType; 9 10 11 public class FruitResource { 12 13 private final FruitRepository fruitRepository; 14 15 private static final Sort<Fruit> ASC = Sort.asc("name"); 16 private static final Sort<Fruit> DESC = Sort.asc("name"); 17 18 public FruitResource(FruitRepository fruitRepository) { 19 this.fruitRepository = fruitRepository; 20 } 21 22 23 24 25 public Iterable<Fruit> hello( long page, 26 int size) { 27 var pageRequest = PageRequest.ofPage(page).size(size); 28 return fruitRepository.offSet(pageRequest).content(); 29 } 30 31 32 33 34 public Iterable<Fruit> cursor( String after, 35 String before, 36 int size) { 37 if (!after.isBlank()) { 38 var pageRequest = PageRequest.ofSize(size).afterCursor(PageRequest.Cursor.forKey(after)); 39 return fruitRepository.cursor(pageRequest, ASC).content(); 40 } else if (!before.isBlank()) { 41 var pageRequest = PageRequest.ofSize(size).beforeCursor(PageRequest.Cursor.forKey(before)); 42 return fruitRepository.cursor(pageRequest, DESC).stream().toList(); 43 } 44 var pageRequest = PageRequest.ofSize(size); 45 return fruitRepository.cursor(pageRequest, ASC).content(); 46 } 47 48 }
Agora que criamos nossa API RESTful para gerenciar registros de desenvolvedores, é hora de colocá-la em teste. Mostraremos como interagir com a API usando várias solicitações HTTP e ferramentas de linha de comando.
1 ./mvnw compile quarkus:dev
Usaremos
curl
para saber mais sobre paginação usando os URL fornecidos. Trata-se de uma ferramenta de linha de comando que é frequentemente usada para enviar solicitações HTTP. Os URL que você recebeu são usados para acessar um endpoint da REST API que busca páginas de frutas usando a paginação compensada. Cada URL solicita uma página diferente, o que nos permite observar como a paginação funciona por meio da API. Veja a seguir como você pode interagir com esses pontos de extremidade usando a curl
ferramenta.Este comando solicita a primeira página de frutas do servidor.
1 curl --location http://localhost:8080/fruits/offset?page=1
Este comando obtém o próximo conjunto de frutas, que é a segunda página.
1 curl --location http://localhost:8080/fruits/offset?page=2
Ao solicitar a quinta página, você pode ver como a API responde quando você solicita uma página que pode estar além do intervalo dos dados existentes.
1 curl --location http://localhost:8080/fruits/offset?page=5
Para continuar explorando a paginação baseada em cursor com sua API, o uso dos parâmetros
after
e before
oferece uma maneira de navegar pelo conjunto de dados para frente e para trás, respectivamente. Esse método permite a recuperação flexível de dados, o que pode ser particularmente útil para interfaces que permitem que os usuários passem para o conjunto de resultados seguinte ou anterior. Veja como você pode estruturar seus comandoscurl
para usar esses parâmetros de forma eficaz:Este comando obtém o primeiro lote de frutas sem especificar um cursor, começando do início.
1 curl --location http://localhost:8080/fruits/cursor
Esse comando busca a lista de frutas que aparecem depois de "banana" em seu conjunto de dados. Isso é útil para avançar na lista.
1 curl --location http://localhost:8080/fruits/cursor?after=banana
Este comando é usado para Go ao conjunto de frutas que precedem "data" no conjunto de dados. Isso é particularmente útil para implementar a funcionalidade de página "Anterior".
1 curl --location http://localhost:8080/fruits/cursor?before=date
Este tutorial explorou os fundamentos e a implementação da paginação usando o Quarkus e o MongoDB, demonstrando como gerenciar grandes conjuntos de dados em aplicativos da Web de forma eficaz. Ao integrar o repositório de dados de Jakarta com o Quarkus, projetamos interfaces que simplificam a interação entre Java e MongoDB, suportando técnicas de paginação baseadas em offset e cursor. Começamos configurando um aplicativo básico do Quartokus e configurando as conexões do MongoDB. Em seguida, demonstramos como preencher o banco de dados com dados iniciais e garantir um comportamento de desligamento limpo.
Ao longo deste tutorial, participamos de sessões de codificação ao vivo, implementando e testando vários métodos de paginação. Usamos o comando
curl
para interagir com a API, buscando dados sem parâmetros e usando os parâmetrosafter
e before
para navegar pelo conjunto de dados para frente e para trás. O uso da paginação baseada em cursor, em particular, demonstrou seus benefícios em cenários em que os conjuntos de dados são atualizados com frequência ou quando é necessário um controle preciso da recuperação de dados. Essa abordagem não só aumenta o desempenho, evitando os problemas comuns da paginação offset, mas também oferece uma maneira fácil de navegar pelos dados.Principais comentários nos fóruns
Ainda não há comentários sobre este artigo.