

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

# DynamoDB용 향상된 문서 API를 사용하여 JSON 문서로 작업
<a name="ddb-en-client-doc-api"></a>

용 [향상된 문서 API](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/package-summary.html) AWS SDK for Java 2.x 는 고정된 스키마가 없는 문서 지향 데이터로 작동하도록 설계되었습니다. 하지만 사용자 지정 클래스를 사용하여 개별 속성을 매핑할 수도 있습니다.

 향상된 문서 API는 AWS SDK for Java v1.x의 [문서 API](https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/document/DynamoDB.html)의 후속 버전입니다.

**Contents**
+ [향상된 문서 API 사용 시작](ddb-en-client-doc-api-steps.md)
  + [`DocumentTableSchema` 및 `DynamoDbTable` 만들기](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema)
+ [향상된 문서 빌드](ddb-en-client-doc-api-steps-create-ed.md)
  + [JSON 문자열로 빌드](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromJson)
  + [개별 요소로 빌드](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)
+ [CRUD 작업을 수행](ddb-en-client-doc-api-steps-use.md)
+ [향상된 문서 속성을 사용자 지정 객체로 액세스](ddb-en-client-doc-api-convert.md)
+ [DynamoDB를 사용하지 `EnhancedDocument` 않고 사용](ddb-en-client-doc-api-standalone.md)

# 향상된 문서 API 사용 시작
<a name="ddb-en-client-doc-api-steps"></a>

향상된 문서 API에는 DynamoDB 향상된 클라이언트 API에 필요한 것과 동일한 [종속성](ddb-en-client-getting-started.md#ddb-en-client-gs-dep)이 필요합니다. 또한 이 항목의 시작 부분에 표시된 것처럼 [`DynamoDbEnhancedClient` 인스턴스](ddb-en-client-getting-started-dynamodbTable.md#ddb-en-client-getting-started-dynamodbTable-eclient)도 필요합니다.

Enhanced Document API는 버전 2.20.3과 함께 릴리스되었으므로 해당 버전 이상이 AWS SDK for Java 2.x필요합니다.

## `DocumentTableSchema` 및 `DynamoDbTable` 만들기
<a name="ddb-en-client-doc-api-steps-createschema"></a>

향상된 문서 API를 사용하여 DynamoDB 테이블에 대해 명령을 호출하려면 테이블을 클라이언트 측 [DynamoDbTable<EnhancedDocument>](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html) 리소스 객체와 연결하세요.

향상된 클라이언트의 `table()` 메서드는 `DynamoDbTable<EnhancedDocument>` 인스턴스를 생성하고 DynamoDB 테이블 이름 및 `DocumentTableSchema`에 대한 파라미터를 필요로 합니다.

[DocumentTableSchema](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/DocumentTableSchema.html)의 빌더에는 기본 인덱스 키와 하나 이상의 속성 변환기 제공자가 필요합니다. `AttributeConverterProvider.defaultProvider()` 메서드는 [기본 유형](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/internal/converter/attribute/package-summary.html)에 대한 변환기를 제공합니다. 사용자 지정 특성 변환기 공급자를 제공하는 경우에도 지정해야 합니다. 선택적인 보조 인덱스 키를 빌더에 추가할 수 있습니다.

다음 코드 조각은 스키마가 없는 `EnhancedDocument` 객체를 저장하는 `person` DynamoDB 테이블의 클라이언트 측 표현을 생성하는 코드를 보여줍니다.

```
DynamoDbTable<EnhancedDocument> documentDynamoDbTable = 
                enhancedClient.table("person",
                        TableSchema.documentSchemaBuilder()
                            // Specify the primary key attributes.
                            .addIndexPartitionKey(TableMetadata.primaryIndexName(),"id", AttributeValueType.S)
                            .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                            // Specify attribute converter providers. Minimally add the default one.
                            .attributeConverterProviders(AttributeConverterProvider.defaultProvider())
                            .build());
                                                         
// Call documentTable.createTable() if "person" does not exist in DynamoDB.
// createTable() should be called only one time.
```

다음은 이 단원 전체에서 사용되는 `person` 객체의 JSON 표현을 보여줍니다.

### JSON `person` 객체
<a name="ddb-en-client-doc-api-steps-createschema-obj"></a>

```
{
  "id": 1,
  "firstName": "Richard",
  "lastName": "Roe",
  "age": 25,
  "addresses":
    {
      "home": {
        "zipCode": "00000",
        "city": "Any Town",
        "state": "FL",
        "street": "123 Any Street"
      },
      "work": {
        "zipCode": "00001",
        "city": "Anywhere",
        "state": "FL",
        "street": "100 Main Street"
      }
    },
  "hobbies": [
    "Hobby 1",
    "Hobby 2"
  ],
  "phoneNumbers": [
    {
      "type": "Home",
      "number": "555-0100"
    },
    {
      "type": "Work",
      "number": "555-0119"
    }
  ]
}
```

# 향상된 문서 빌드
<a name="ddb-en-client-doc-api-steps-create-ed"></a>

`[EnhancedDocument](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/document/EnhancedDocument.html)`는 속성이 중첩된 복잡한 구조를 가진 문서 유형 객체를 나타냅니다. `EnhancedDocument`에는 `DocumentTableSchema`에 지정된 기본 키 속성과 일치하는 최상위 속성이 필요합니다. 나머지 내용은 임의적이며 최상위 속성과 깊이 중첩된 속성으로 구성될 수 있습니다.

요소를 추가하는 여러 가지 방법을 제공하는 빌더를 사용하여 `EnhancedDocument` 인스턴스를 만듭니다.

## JSON 문자열로 빌드
<a name="ddb-en-client-doc-api-steps-create-ed-fromJson"></a>

JSON 문자열을 사용하면 호출 한 번으로 `EnhancedDocument`을 만들 수 있습니다. 다음 코드 조각은 `jsonPerson()` 헬퍼 메서드에서 반환한 JSON 문자열에서 `EnhancedDocument`를 생성합니다. `jsonPerson()` 메서드는 이전에 표시된 [사람 객체](ddb-en-client-doc-api-steps.md#ddb-en-client-doc-api-steps-createschema-obj)의 JSON 문자열 버전을 반환합니다.

```
EnhancedDocument document = 
        EnhancedDocument.builder()
                        .json( jsonPerson() )
                        .build());
```

## 개별 요소로 빌드
<a name="ddb-en-client-doc-api-steps-create-ed-fromparts"></a>

또는 빌더의 형식이 안전한 메서드를 사용하여 개별 구성 요소에서 `EnhancedDocument` 인스턴스를 빌드할 수 있습니다.

다음 예제는 이전 예제의 JSON 문자열로 빌드된 향상된 문서와 유사한 `person` 향상된 문서를 빌드합니다.

```
        /* Define the shape of an address map whose JSON representation looks like the following.
           Use 'addressMapEnhancedType' in the following EnhancedDocument.builder() to simplify the code.
           "home": {
             "zipCode": "00000",
             "city": "Any Town",
             "state": "FL",
             "street": "123 Any Street"
           }*/
        EnhancedType<Map<String, String>> addressMapEnhancedType =
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class));


        //  Use the builder's typesafe methods to add elements to the enhanced document.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                /* Add the map of addresses whose JSON representation looks like the following.
                        {
                          "home": {
                            "zipCode": "00000",
                            "city": "Any Town",
                            "state": "FL",
                            "street": "123 Any Street"
                          }
                        } */
                .putMap("addresses", getAddresses(), EnhancedType.of(String.class), addressMapEnhancedType)
                .putList("hobbies", List.of("Theater", "Golf"), EnhancedType.of(String.class))
                .build();
```

### 도우미 메서드
<a name="ddb-en-client-doc-api-steps-use-fromparts-helpers"></a>

```
    private static String phoneNumbersJSONString() {
        return "  [" +
                "    {" +
                "      \"type\": \"Home\"," +
                "      \"number\": \"555-0140\"" +
                "    }," +
                "    {" +
                "      \"type\": \"Work\"," +
                "      \"number\": \"555-0155\"" +
                "    }" +
                "  ]";
    }

    private static Map<String, Map<String, String>> getAddresses() {
        return Map.of(
                "home", Map.of(
                        "zipCode", "00002",
                        "city", "Any Town",
                        "state", "ME",
                        "street", "123 Any Street"));

    }
```

# CRUD 작업을 수행
<a name="ddb-en-client-doc-api-steps-use"></a>

`EnhancedDocument` 인스턴스를 정의한 후 DynamoDB 테이블에 저장할 수 있습니다. 다음 코드 조각은 개별 요소에서 생성된 [PersonDocument](ddb-en-client-doc-api-steps-create-ed.md#ddb-en-client-doc-api-steps-create-ed-fromparts)를 사용합니다.

```
documentDynamoDbTable.putItem(personDocument);
```

DynamoDB에서 향상된 문서 인스턴스를 읽은 후에는 접근자를 사용하여 개별 속성 값을 추출할 수 있습니다. 다음 코드 조각은 `personDocument`에서 저장한 데이터에 액세스합니다. 또는 예제 코드의 마지막 부분에 표시된 대로 전체 콘텐츠를 JSON 문자열로 추출할 수 있습니다.

```
        // Read the item.
        EnhancedDocument personDocFromDb = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).build());

        // Access top-level attributes.
        logger.info("Name: {} {}", personDocFromDb.getString("firstName"), personDocFromDb.getString("lastName"));
        // Name: Shirley Rodriguez

        // Typesafe access of a deeply nested attribute. The addressMapEnhancedType shown previously defines the shape of an addresses map.
        Map<String, Map<String, String>> addresses = personDocFromDb.getMap("addresses", EnhancedType.of(String.class), addressMapEnhancedType);
        addresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));
        // {zipCode=00002, city=Any Town, street=123 Any Street, state=ME}

        // Alternatively, work with AttributeValue types checking along the way for deeply nested attributes.
        Map<String, AttributeValue> addressesMap = personDocFromDb.getMapOfUnknownType("addresses");
        addressesMap.keySet().forEach((String k) -> {
            logger.info("Looking at data for [{}] address", k);
            // Looking at data for [home] address
            AttributeValue value = addressesMap.get(k);
            AttributeValue cityValue = value.m().get("city");
            if (cityValue != null) {
                logger.info(cityValue.s());
                // Any Town
            }
        });

        List<AttributeValue> phoneNumbers = personDocFromDb.getListOfUnknownType("phoneNumbers");
        phoneNumbers.forEach((AttributeValue av) -> {
            if (av.hasM()) {
                AttributeValue type = av.m().get("type");
                if (type.s() != null) {
                    logger.info("Type of phone: {}", type.s());
                    // Type of phone: Home
                    // Type of phone: Work
                }
            }
        });

        String jsonPerson = personDocFromDb.toJson();
        logger.info(jsonPerson);
        // {"firstName":"Shirley","lastName":"Rodriguez","addresses":{"home":{"zipCode":"00002","city":"Any Town","street":"123 Any Street","state":"ME"}},"hobbies":["Theater","Golf"],
        //     "id":50,"nullAttribute":null,"age":53,"phoneNumbers":[{"number":"555-0140","type":"Home"},{"number":"555-0155","type":"Work"}]}
```

`EnhancedDocument` 인스턴스는 매핑된 데이터 클래스 대신 `[DynamoDbTable](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbTable.html)`의 모든 메서드 또는 [DynamoDbEnhancedClient](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/DynamoDbEnhancedClient.html)와 함께 사용할 수 있습니다.

# 향상된 문서 속성을 사용자 지정 객체로 액세스
<a name="ddb-en-client-doc-api-convert"></a>

향상된 문서 API를 사용하면 스키마가 없는 구조의 속성을 읽고 쓸 수 있는 API를 제공할 뿐만 아니라 사용자 정의 클래스의 인스턴스 간에 속성을 변환할 수 있습니다.

향상된 문서 API는 DynamoDB 향상된 클라이언트 API의 일부로 [제어 속성 변환](ddb-en-client-adv-features-conversion.md) 단원에 표시된 `AttributeConverterProvider`와 `AttributeConverter`를 사용합니다.

다음 예제는 `CustomAttributeConverterProvider`를 중첩된 `AddressConverter` 클래스와 함께 사용하여 `Address` 객체를 변환합니다.

이 예제는 클래스의 데이터와 필요에 따라 빌드된 구조의 데이터를 혼합할 수 있음을 보여줍니다. 또한 이 예제는 사용자 정의 클래스가 중첩 구조의 모든 수준에서 사용될 수 있음을 보여줍니다. 이 예제의 `Address` 객체는 맵에서 사용되는 값입니다.

```
    public static void attributeToAddressClassMappingExample(DynamoDbEnhancedClient enhancedClient, DynamoDbClient standardClient) {
        String tableName = "customer";

        // Define the DynamoDbTable for an enhanced document.
        // The schema builder provides methods for attribute converter providers and keys.
        DynamoDbTable<EnhancedDocument> documentDynamoDbTable = enhancedClient.table(tableName,
                DocumentTableSchema.builder()
                        // Add the CustomAttributeConverterProvider along with the default when you build the table schema.
                        .attributeConverterProviders(
                                List.of(
                                        new CustomAttributeConverterProvider(),
                                        AttributeConverterProvider.defaultProvider()))
                        .addIndexPartitionKey(TableMetadata.primaryIndexName(), "id", AttributeValueType.N)
                        .addIndexSortKey(TableMetadata.primaryIndexName(), "lastName", AttributeValueType.S)
                        .build());
        // Create the DynamoDB table if needed.
        documentDynamoDbTable.createTable();
        waitForTableCreation(tableName, standardClient);


        // The getAddressesForCustomMappingExample() helper method that provides 'addresses' shows the use of a custom Address class
        // rather than using a Map<String, Map<String, String> to hold the address data.
        Map<String, Address> addresses = getAddressesForCustomMappingExample();

        // Build an EnhancedDocument instance to save an item with a mix of structures defined as needed and static classes.
        EnhancedDocument personDocument = EnhancedDocument.builder()
                .putNumber("id", 50)
                .putString("firstName", "Shirley")
                .putString("lastName", "Rodriguez")
                .putNumber("age", 53)
                .putNull("nullAttribute")
                .putJson("phoneNumbers", phoneNumbersJSONString())
                // Note the use of 'EnhancedType.of(Address.class)' instead of the more generic
                // 'EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(String.class))' that was used in a previous example.
                .putMap("addresses", addresses, EnhancedType.of(String.class), EnhancedType.of(Address.class))
                .putList("hobbies", List.of("Hobby 1", "Hobby 2"), EnhancedType.of(String.class))
                .build();
        // Save the item to DynamoDB.
        documentDynamoDbTable.putItem(personDocument);

        // Retrieve the item just saved.
        EnhancedDocument srPerson = documentDynamoDbTable.getItem(Key.builder().partitionValue(50).sortValue("Rodriguez").build());

        // Access the addresses attribute.
        Map<String, Address> srAddresses = srPerson.get("addresses",
                EnhancedType.mapOf(EnhancedType.of(String.class), EnhancedType.of(Address.class)));

        srAddresses.keySet().forEach(k -> logger.info(addresses.get(k).toString()));

        documentDynamoDbTable.deleteTable();

// The content logged to the console shows that the saved maps were converted to Address instances.
Address{street='123 Main Street', city='Any Town', state='NC', zipCode='00000'}
Address{street='100 Any Street', city='Any Town', state='NC', zipCode='00000'}
```

## `CustomAttributeConverterProvider` 코드
<a name="ddb-en-client-doc-api-convert-provider"></a>

```
public class CustomAttributeConverterProvider implements AttributeConverterProvider {

    private final Map<EnhancedType<?>, AttributeConverter<?>> converterCache = ImmutableMap.of(
            // 1. Add AddressConverter to the internal cache.
            EnhancedType.of(Address.class), new AddressConverter());

    public static CustomAttributeConverterProvider create() {
        return new CustomAttributeConverterProvider();
    }

    // 2. The enhanced client queries the provider for attribute converters if it
    //    encounters a type that it does not know how to convert.
    @SuppressWarnings("unchecked")
    @Override
    public <T> AttributeConverter<T> converterFor(EnhancedType<T> enhancedType) {
        return (AttributeConverter<T>) converterCache.get(enhancedType);
    }

    // 3. Custom attribute converter
    private class AddressConverter implements AttributeConverter<Address> {
        // 4. Transform an Address object into a DynamoDB map.
        @Override
        public AttributeValue transformFrom(Address address) {

            Map<String, AttributeValue> attributeValueMap = Map.of(
                    "street", AttributeValue.fromS(address.getStreet()),
                    "city", AttributeValue.fromS(address.getCity()),
                    "state", AttributeValue.fromS(address.getState()),
                    "zipCode", AttributeValue.fromS(address.getZipCode()));

            return AttributeValue.fromM(attributeValueMap);
        }

        // 5. Transform the DynamoDB map attribute to an Address oject.
        @Override
        public Address transformTo(AttributeValue attributeValue) {
            Map<String, AttributeValue> m = attributeValue.m();
            Address address = new Address();
            address.setStreet(m.get("street").s());
            address.setCity(m.get("city").s());
            address.setState(m.get("state").s());
            address.setZipCode(m.get("zipCode").s());

            return address;
        }

        @Override
        public EnhancedType<Address> type() {
            return EnhancedType.of(Address.class);
        }

        @Override
        public AttributeValueType attributeValueType() {
            return AttributeValueType.M;
        }
    }
}
```

## `Address` 클래스
<a name="ddb-en-client-doc-api-convert-address"></a>

```
public class Address {
                  private String street;
                  private String city;
                  private String state;
                  private String zipCode;

                  public Address() {
                  }

                  public String getStreet() {
                  return this.street;
                  }

                  public String getCity() {
                  return this.city;
                  }

                  public String getState() {
                  return this.state;
                  }

                  public String getZipCode() {
                  return this.zipCode;
                  }

                  public void setStreet(String street) {
                  this.street = street;
                  }

                  public void setCity(String city) {
                  this.city = city;
                  }

                  public void setState(String state) {
                  this.state = state;
                  }

                  public void setZipCode(String zipCode) {
                  this.zipCode = zipCode;
                  }
                  }
```

## 주소를 제공하는 도우미 메서드
<a name="ddb-en-client-doc-api-convert-helper"></a>

다음 도우미 메서드는 값에 대한 일반 `Map<String, String>` 인스턴스가 아닌 사용자 지정 `Address` 인스턴스를 값에 사용하는 맵을 제공합니다.

```
    private static Map<String, Address> getAddressesForCustomMappingExample() {
        Address homeAddress = new Address();
        homeAddress.setStreet("100 Any Street");
        homeAddress.setCity("Any Town");
        homeAddress.setState("NC");
        homeAddress.setZipCode("00000");

        Address workAddress = new Address();
        workAddress.setStreet("123 Main Street");
        workAddress.setCity("Any Town");
        workAddress.setState("NC");
        workAddress.setZipCode("00000");

        return Map.of("home", homeAddress,
                "work", workAddress);
    }
```

# DynamoDB를 사용하지 `EnhancedDocument` 않고 사용
<a name="ddb-en-client-doc-api-standalone"></a>

일반적으로 `EnhancedDocument`의 인스턴스를 사용하여 문서 유형 DynamoDB 항목을 읽고 쓰지만 DynamoDB와 독립적으로 사용할 수도 있습니다.

`EnhancedDocuments`을 사용하면 JSON 문자열이나 사용자 지정 객체를 다음 예제와 같은 `AttributeValues`의 하위 수준 맵으로 변환하는 기능을 사용할 수 있습니다.

```
    public static void conversionWithoutDynamoDbExample() {
        Address address = new Address();
        address.setCity("my city");
        address.setState("my state");
        address.setStreet("my street");
        address.setZipCode("00000");

        // Build an EnhancedDocument instance for its conversion functionality alone.
        EnhancedDocument addressEnhancedDoc = EnhancedDocument.builder()
                // Important: You must specify attribute converter providers when you build an EnhancedDocument instance not used with a DynamoDB table.
                .attributeConverterProviders(new CustomAttributeConverterProvider(), DefaultAttributeConverterProvider.create())
                .put("addressDoc", address, Address.class)
                .build();

        // Convert address to a low-level item representation.
        final Map<String, AttributeValue> addressAsAttributeMap = addressEnhancedDoc.getMapOfUnknownType("addressDoc");
        logger.info("addressAsAttributeMap: {}", addressAsAttributeMap.toString());

        // Convert address to a JSON string.
        String addressAsJsonString = addressEnhancedDoc.getJson("addressDoc");
        logger.info("addressAsJsonString: {}", addressAsJsonString);
        // Convert addressEnhancedDoc back to an Address instance.
        Address addressConverted =  addressEnhancedDoc.get("addressDoc", Address.class);
        logger.info("addressConverted: {}", addressConverted.toString());
    }

   /* Console output:
          addressAsAttributeMap: {zipCode=AttributeValue(S=00000), state=AttributeValue(S=my state), street=AttributeValue(S=my street), city=AttributeValue(S=my city)}
          addressAsJsonString: {"zipCode":"00000","state":"my state","street":"my street","city":"my city"}
          addressConverted: Address{street='my street', city='my city', state='my state', zipCode='00000'}
   */
```

**참고**  
DynamoDB 테이블과 별개로 향상된 문서를 사용하는 경우 빌더에서 속성 변환기 공급자를 명시적으로 설정했는지 확인하세요.  
반대로 문서 테이블 스키마는 향상된 문서가 DynamoDB 테이블과 함께 사용될 때 변환기 제공자에게 제공합니다.