

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# AWS SDK for Java 2.x에서 페이지가 매겨진 결과 사용
<a name="pagination"></a>

응답 객체가 너무 커서 단일 응답으로 반환할 수 없는 경우 많은 AWS 작업이 페이지 매김된 결과를 반환합니다. AWS SDK for Java 1.0에서 응답에는 결과의 다음 페이지를 검색하는 데 사용하는 토큰이 포함되어 있습니다. 반면, AWS SDK for Java 2.x에는 자동으로 결과의 다음 페이지를 가져오기 위해 여러 서비스를 호출하는 자동 페이지 매김 메서드가 있습니다. 결과를 처리할 코드를 작성하기만 하면 됩니다. 자동 페이지 매김은 동기 클라이언트와 비동기 클라이언트 모두에서 사용할 수 있습니다.

**참고**  
이러한 코드 조각은 사용자가 [SDK 사용의 기본](using.md) 사항을 이해하고 [Single Sign-On 액세스](get-started-auth.md#setup-credentials)로 환경을 구성했다고 가정합니다.

## 동기식 페이지 매김
<a name="synchronous-pagination"></a>

다음 예제에서는 Amazon S3 버킷의 객체를 나열하는 동기식 페이지 매김 방법을 보여줍니다.

### 페이지 반복
<a name="iterate-pages"></a>

첫 번째 예제는 `listRes` 페이지네이터 객체인 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/paginators/ListObjectsV2Iterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/paginators/ListObjectsV2Iterable.html) 인스턴스를 사용하여 `stream` 메서드로 모든 응답 페이지를 반복하는 방법을 보여줍니다. 코드는 응답 페이지를 통해 스트리밍하고 응답 스트림을 `[S3Object](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/model/S3Object.html)` 콘텐츠 스트림으로 변환한 다음 Amazon S3 객체의 콘텐츠를 처리합니다.

다음 가져오기는 이 동기 페이지 매김 단원의 모든 예제에 적용됩니다.

#### 가져오기
<a name="synchronous-pagination-ex-import"></a>

```
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()));
```

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L112)를 참조하세요.

### 객체 반복
<a name="iterate-objects"></a>

다음은 응답 페이지 대신 응답에서 반환된 객체에 대해 반복하는 방법을 설명한 예입니다. `ListObjectsV2Iterable`클래스의 `contents` 메서드는 기본 콘텐츠 요소를 처리하기 위한 여러 메서드를 제공하는 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/pagination/sync/SdkIterable.html)을 반환합니다.

#### 스트림 사용
<a name="use-a-stream"></a>

다음 코드 조각은 응답 내용에 대해 `stream` 메서드를 사용하여 페이지 매김 항목 모음에 대해 반복합니다.

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

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L127)를 참조하세요.

#### for-each 루프를 사용
<a name="for-loop"></a>

`SdkIterable`는 `Iterable` 인터페이스를 확장하므로 내용을 `Iterable`과 같이 처리할 수 있습니다. 다음 코드 조각은 표준 `for-each` 루프를 사용하여 응답 내용을 반복합니다.

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

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L133)를 참조하세요.

### 수동 페이지 매김
<a name="manual-pagination"></a>

사용 사례에 따라 필요한 경우 수동 페이지 매김을 사용할 수도 있습니다. 후속 요청에 응답 객체의 다음 토큰을 사용합니다. 다음 예에는 `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();
        }
```

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/s3/src/main/java/com/example/s3/S3ObjectOperations.java#L90)를 참조하세요.

## 비동기 페이지 매김
<a name="asynchronous-pagination"></a>

다음 예제에서는 DynamoDB 테이블을 나열하는 비동기 페이지 매김 방법을 보여줍니다.

### 테이블 이름 페이지 반복
<a name="iterate-pages-async"></a>

다음 두 예제는 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/paginators/ListTablesPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/dynamodb/paginators/ListTablesPublisher.html)를 가져오기 위한 요청과 함께 `listTablesPaginator` 메서드를 직접적으로 호출하는 비동기식 DynamoDB 클라이언트를 사용합니다. `ListTablesPublisher`는 응답을 처리하기 위한 많은 옵션을 제공하는 2개의 인터페이스를 구현합니다. 각 인터페이스의 메서드를 살펴보겠습니다.

#### `Subscriber` 사용
<a name="use-a-subscriber"></a>

다음 코드 예제에서는 `ListTablesPublisher`에서 구현된 `org.reactivestreams.Publisher` 인터페이스를 사용하여 페이지가 매겨진 결과를 처리하는 방법을 보여줍니다. 반응적 스트림 모델에 대한 자세한 내용은 [반응적 스트림 GitHub 리포지토리](https://github.com/reactive-streams/reactive-streams-jvm/blob/v1.0.2/README.md)를 참조하세요.

다음 가져오기는 이 비동기 페이지 매김 단원의 모든 예제에 적용됩니다.

##### 가져오기
<a name="use-a-subscriber-ex-imports"></a>

```
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;
```

다음 코드는 `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);
```

다음 코드는 `org.reactivestreams.Subscriber`의 익명 구현을 사용하여 각 페이지의 결과를 처리합니다.

`onSubscribe` 메서드가 `Subscription.request` 메서드를 호출해 게시자에게 데이터를 요청하기 시작합니다. 게시자에게 데이터를 가져오기 시작할 때 호출해야 하는 메서드입니다.

구독자의 `onNext` 메서드는 모든 테이블 이름에 액세스하고 각 이름을 인쇄하여 응답 페이지를 처리합니다. 페이지가 처리된 후 게시자에게 다른 페이지가 요청됩니다. 모든 페이지를 검색할 때까지 반복적으로 호출되는 메서드입니다.

데이터 검색 동안 오류가 발생할 경우 `onError` 메서드가 트리거됩니다. 마지막으로 모든 페이지를 다 요청했을 때 `onComplete` 메서드가 호출됩니다.

```
        // 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.
            }
        });
```

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L83)를 참조하세요.

#### `Consumer` 사용
<a name="id1pagination"></a>

`ListTablesPublisher`가 구현하는 `SdkPublisher` 인터페이스에는 `Consumer`를 받아서 `CompletableFuture<Void>`를 반환하는 `subscribe` 메서드가 있습니다.

이 인터페이스의 `subscribe` 메서드는 `org.reactivestreams.Subscriber`의 오버헤드가 너무 클 때 간단한 사용 사례에 사용할 수 있습니다. 아래 코드는 각 페이지를 사용하므로 각 페이지에서 `tableNames` 메서드를 호출합니다. `tableNames` 메서드는 `forEach` 메서드로 처리된 DynamoDB 테이블 이름 중 `java.util.List`를 반환합니다.

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

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L96)를 참조하세요.

### 테이블 이름 반복
<a name="iterate-objects-async"></a>

다음은 응답 페이지 대신 응답에서 반환된 객체에 대해 반복하는 방법을 설명한 예입니다. 이전에 해당 `contents` 메서드와 함께 표시된 동기 Amazon S3 예제와 마찬가지로, DynamoDB 비동기 결과 클래스 `ListTablesPublisher`에는 기본 항목 컬렉션과 상호 작용할 수 있는 편리한 `tableNames` 메서드가 있습니다. `tableNames` 메서드의 반환 유형은 모든 페이지에서 항목을 요청하기 위해 사용할 수 있는 [https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/core/async/SdkPublisher.html)입니다.

#### `Subscriber` 사용
<a name="id2"></a>

다음 코드는 테이블 이름의 기본 컬렉션 중 `SdkPublisher`를 가져옵니다.

```
        // 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();
```

다음 코드는 `org.reactivestreams.Subscriber`의 익명 구현을 사용하여 각 페이지의 결과를 처리합니다.

구독자의 `onNext` 메서드는 컬렉션의 개별 요소를 처리합니다. 이 경우에는 테이블 이름입니다. 테이블 이름이 처리된 후 게시자로부터 다른 테이블 이름을 요청합니다. 이 메서드는 모든 페이지를 검색할 때까지 호출을 반복합니다.

```
        // 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() {
            }
        });
```

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L147)를 참조하세요.

#### `Consumer` 사용
<a name="for-loop-async"></a>

다음 예제는 `SdkPublisher`의 `subscribe` 메서드를 사용해 `Consumer`로 각 항목을 처리합니다.

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

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L161)를 참조하세요.

### 타사 라이브러리 사용
<a name="use-third-party-library"></a>

사용자 지정 구독자를 구현하는 대신 타사 라이브러리를 사용할 수 있습니다. 이 예제는 RxJava의 사용을 보여 주지만 반응형 스트림 인터페이스를 구현하는 모든 라이브러리를 사용할 수 있습니다. 해당 라이브러리에 대한 자세한 내용은 [GitHub의 RxJava 위키 페이지](https://github.com/ReactiveX/RxJava/wiki)를 참조하세요.

라이브러리를 사용하려면 종속성으로 추가합니다. 이 예에서는 Maven을 사용하는 경우에 사용할 POM 조각을 알려줍니다.

 **POM 항목** 

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

 **코드** 

```
        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);
```

GitHub의 [전체 예제](https://github.com/awsdocs/aws-doc-sdk-examples/blob/f807d60010caf3d14fe4cd0801b842fb8e9511ca/javav2/example_code/dynamodbasync/src/main/java/com/example/dynamodbasync/AsyncPagination.java#L198)를 참조하세요.