Trabalhar com resultados paginados usando o AWS SDK for Java 2.x - AWS SDK for Java 2.x

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Trabalhar com resultados paginados usando o AWS SDK for Java 2.x

Muitas AWS operações retornam resultados paginados quando o objeto de resposta é muito grande para ser retornado em uma única resposta. Na AWS SDK for Java versão 1.0, a resposta contém um token que você usa para recuperar a próxima página de resultados. Por outro lado, o AWS SDK for Java 2.x tem métodos de autopaginação que fazem várias chamadas de serviço para obter automaticamente a próxima página de resultados para você. Você precisa somente escrever um código que processa os resultados. A autopaginação está disponível para clientes síncronos e assíncronos.

nota

Esses trechos de código pressupõem que você entenda os conceitos básicos do uso do SDK e tenha configurado seu ambiente com acesso de login único.

Paginação síncrona

Os exemplos a seguir demonstram métodos de paginação síncrona para listar objetos em um bucket do Amazon S3 .

Iterar sobre páginas

O primeiro exemplo demonstra o uso de um objeto listRes paginador, uma ListObjectsV2Iterableinstância, para percorrer todas as páginas de resposta com o método. stream O código é transmitido pelas páginas de resposta, converte o fluxo de resposta em um fluxo de S3Object conteúdo e, em seguida, processa o conteúdo do Amazon S3 objeto.

As importações a seguir se aplicam a todos os exemplos nesta seção de paginação síncrona.

import java.io.IOException; import java.nio.ByteBuffer; import java.util.Random; import software.amazon.awssdk.core.waiters.WaiterResponse; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.paginators.ListObjectsV2Iterable; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; import software.amazon.awssdk.services.s3.model.S3Object; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; import software.amazon.awssdk.services.s3.model.DeleteBucketRequest; import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest; import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse; import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; import software.amazon.awssdk.services.s3.model.CompletedPart; import software.amazon.awssdk.services.s3.model.CreateBucketConfiguration; import software.amazon.awssdk.services.s3.model.UploadPartRequest; import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadRequest; import software.amazon.awssdk.services.s3.waiters.S3Waiter; import software.amazon.awssdk.services.s3.model.HeadBucketRequest; import software.amazon.awssdk.services.s3.model.HeadBucketResponse;
ListObjectsV2Request listReq = ListObjectsV2Request.builder() .bucket(bucketName) .maxKeys(1) .build(); ListObjectsV2Iterable listRes = s3.listObjectsV2Paginator(listReq); // Process response pages listRes.stream() .flatMap(r -> r.contents().stream()) .forEach(content -> System.out .println(" Key: " + content.key() + " size = " + content.size()));

Veja o exemplo completo em GitHub.

Iterar sobre objetos

Os exemplos a seguir mostram maneiras de iterar sobre os objetos retornados na resposta e não nas páginas de resposta. O método contents da classe ListObjectsV2Iterable retorna um SdkIterable que fornece vários métodos para processar os elementos do conteúdo subjacente.

Usar um stream

O seguinte trecho usa o método stream no conteúdo de resposta para iterar sobre a coleção de itens paginados.

// Helper method to work with paginated collection of items directly. listRes.contents().stream() .forEach(content -> System.out .println(" Key: " + content.key() + " size = " + content.size()));

Veja o exemplo completo em GitHub.

Usar um loop for-each

Como SdkIterable estende a interface Iterable, você pode processar o conteúdo como qualquer outro Iterable. O trecho a seguir usa um loop for-each padrão para percorrer o conteúdo da resposta.

for (S3Object content : listRes.contents()) { System.out.println(" Key: " + content.key() + " size = " + content.size()); }

Veja o exemplo completo em GitHub.

Paginação manual

Se seu caso de uso exigir isto, a paginação manual ainda estará disponível. Use o próximo token no objeto de resposta para as solicitações subsequentes. O exemplo a seguir usa o loop while.

ListObjectsV2Request listObjectsReqManual = ListObjectsV2Request.builder() .bucket(bucketName) .maxKeys(1) .build(); boolean done = false; while (!done) { ListObjectsV2Response listObjResponse = s3.listObjectsV2(listObjectsReqManual); for (S3Object content : listObjResponse.contents()) { System.out.println(content.key()); } if (listObjResponse.nextContinuationToken() == null) { done = true; } listObjectsReqManual = listObjectsReqManual.toBuilder() .continuationToken(listObjResponse.nextContinuationToken()) .build(); }

Veja o exemplo completo em GitHub.

Paginação assíncrona

Os exemplos a seguir demonstram métodos de paginação assíncrona para listar tabelas. DynamoDB

Iterar sobre páginas de nomes de tabelas

Os dois exemplos a seguir usam um cliente assíncrono do DynamoDB que chama listTablesPaginator o método com uma solicitação para obter um. ListTablesPublisher ListTablesPublisherimplementa duas interfaces, que oferecem muitas opções para processar respostas. Examinaremos os métodos de cada interface.

Usar um Subscriber

O exemplo de código a seguir demonstra como processar resultados paginados usando a interface org.reactivestreams.Publisher implementada pelo ListTablesPublisher. Para saber mais sobre o modelo de fluxos reativos, consulte o repositório Reactive Streams. GitHub

As importações a seguir se aplicam a todos os exemplos nesta seção de paginação assíncrona.

import io.reactivex.rxjava3.core.Flowable; import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import reactor.core.publisher.Flux; import software.amazon.awssdk.core.async.SdkPublisher; import software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient; import software.amazon.awssdk.services.dynamodb.model.ListTablesRequest; import software.amazon.awssdk.services.dynamodb.model.ListTablesResponse; import software.amazon.awssdk.services.dynamodb.paginators.ListTablesPublisher; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException;

O código a seguir adquire uma instância ListTablesPublisher.

// Creates a default client with credentials and region loaded from the // environment. final DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create(); ListTablesRequest listTablesRequest = ListTablesRequest.builder().limit(3).build(); ListTablesPublisher publisher = asyncClient.listTablesPaginator(listTablesRequest);

O código a seguir usa uma implementação anônima de org.reactivestreams.Subscriber para processar os resultados de cada página.

O método onSubscribe chama o método Subscription.request para iniciar solicitações de dados do editor. Esse método deve ser chamado para iniciar a obtenção de dados do editor.

O método onNext do assinante processa uma página de resposta acessando todos os nomes das tabelas e imprimindo cada um. Depois que a página é processada, outra página é solicitada ao publicador. Este método é chamado repetidamente até que todas as páginas sejam recuperadas.

O método onError será acionado se ocorrer um erro durante a recuperação de dados. Por fim, o método onComplete será chamado quando todas as páginas tiverem sido solicitadas.

// A Subscription represents a one-to-one life-cycle of a Subscriber subscribing // to a Publisher. publisher.subscribe(new Subscriber<ListTablesResponse>() { // Maintain a reference to the subscription object, which is required to request // data from the publisher. private Subscription subscription; @Override public void onSubscribe(Subscription s) { subscription = s; // Request method should be called to demand data. Here we request a single // page. subscription.request(1); } @Override public void onNext(ListTablesResponse response) { response.tableNames().forEach(System.out::println); // After you process the current page, call the request method to signal that // you are ready for next page. subscription.request(1); } @Override public void onError(Throwable t) { // Called when an error has occurred while processing the requests. } @Override public void onComplete() { // This indicates all the results are delivered and there are no more pages // left. } });

Veja o exemplo completo em GitHub.

Usar um Consumer

A interface do SdkPublisher que ListTablesPublisher implementa tem um método subscribe que pega um Consumer e retorna um CompletableFuture<Void>.

O método subscribe dessa interface pode ser usado para casos de uso simples, quando um org.reactivestreams.Subscriber pode ser uma sobrecarga. Como o código abaixo consome cada página, ele chama o método tableNames em cada uma. O método tableNames retorna um java.util.List dos nomes de tabela do DynamoDB que são processados com o método forEach.

// Use a Consumer for simple use cases. CompletableFuture<Void> future = publisher.subscribe( response -> response.tableNames() .forEach(System.out::println));

Veja o exemplo completo em GitHub.

Iterar sobre nomes de tabela

Os exemplos a seguir mostram maneiras de iterar sobre os objetos retornados na resposta e não nas páginas de resposta. Semelhante ao exemplo síncrono do Amazon S3 mostrado anteriormente com seu método contents, a classe de resultados assíncronos do DynamoDB, ListTablesPublisher tem o método conveniente tableNames para interagir com a coleção de itens subjacente. O tipo de retorno do método tableNames é um SdkPublisher que pode ser usado para solicitar itens em todas as páginas.

Usar um Subscriber

O código a seguir adquire um SdkPublisher da coleção subjacente de nomes de tabelas.

// Create a default client with credentials and region loaded from the // environment. final DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create(); ListTablesRequest listTablesRequest = ListTablesRequest.builder().limit(3).build(); ListTablesPublisher listTablesPublisher = asyncClient.listTablesPaginator(listTablesRequest); SdkPublisher<String> publisher = listTablesPublisher.tableNames();

O código a seguir usa uma implementação anônima de org.reactivestreams.Subscriber para processar os resultados de cada página.

O método onNext do assinante processa um elemento individual da coleção. Nesse caso, é um nome de tabela. Depois que o nome da tabela é processado, outro nome de tabela é solicitado ao publicador. Este método é chamado repetidamente até que todos os nomes de tabelas sejam recuperados.

// Use a Subscriber. publisher.subscribe(new Subscriber<String>() { private Subscription subscription; @Override public void onSubscribe(Subscription s) { subscription = s; subscription.request(1); } @Override public void onNext(String tableName) { System.out.println(tableName); subscription.request(1); } @Override public void onError(Throwable t) { } @Override public void onComplete() { } });

Veja o exemplo completo em GitHub.

Usar um Consumer

O exemplo a seguir usa o método subscribe do SdkPublisher que utiliza um Consumer para processar cada item.

// Use a Consumer. CompletableFuture<Void> future = publisher.subscribe(System.out::println); future.get();

Veja o exemplo completo em GitHub.

Usar bibliotecas de terceiros

Você pode usar outras bibliotecas de terceiros em vez de implementar um assinante personalizado. Este exemplo demonstra o uso de RxJava, mas qualquer biblioteca que implemente as interfaces de fluxo reativo pode ser usada. Consulte a página RxJava wiki GitHub para obter mais informações sobre essa biblioteca.

Para usar a biblioteca, adicione-a como uma dependência. Se estiver usando o Maven, o exemplo mostra o trecho POM a ser usado.

Entrada POM

<dependency> <groupId>io.reactivex.rxjava3</groupId> <artifactId>rxjava</artifactId> <version>3.1.6</version> </dependency>

Código

DynamoDbAsyncClient asyncClient = DynamoDbAsyncClient.create(); ListTablesPublisher publisher = asyncClient.listTablesPaginator(ListTablesRequest.builder() .build()); // The Flowable class has many helper methods that work with // an implementation of an org.reactivestreams.Publisher. List<String> tables = Flowable.fromPublisher(publisher) .flatMapIterable(ListTablesResponse::tableNames) .toList() .blockingGet(); System.out.println(tables);

Veja o exemplo completo em GitHub.