diff --git a/build.gradle b/build.gradle index 05efb7af..d7941847 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'com.h2database:h2' implementation 'mysql:mysql-connector-java:8.0.33' + // https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-dynamodb + implementation group: 'com.amazonaws', name: 'aws-java-sdk-dynamodb', version: '1.12.592' } dependencyManagement { diff --git a/src/main/java/kr/bb/product/config/DynamoDBConfiguration.java b/src/main/java/kr/bb/product/config/DynamoDBConfiguration.java new file mode 100644 index 00000000..385a0180 --- /dev/null +++ b/src/main/java/kr/bb/product/config/DynamoDBConfiguration.java @@ -0,0 +1,57 @@ +package kr.bb.product.config; + +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +@Configuration +public class DynamoDBConfiguration { + @Value("${aws.dynamodb.endpoint}") + private String endPoint; + + @Value("${aws.region}") + private String region; + + @Value("${aws.accessKey}") + private String accessKey; + + @Value("${aws.secretKey}") + private String secretKey; + + @Bean + public DynamoDBMapper dynamoDBMapper() { + DynamoDBMapperConfig mapperConfig = + DynamoDBMapperConfig.builder() + .withSaveBehavior(DynamoDBMapperConfig.SaveBehavior.CLOBBER) + .withConsistentReads(DynamoDBMapperConfig.ConsistentReads.CONSISTENT) + .withTableNameOverride(null) + .withPaginationLoadingStrategy( + DynamoDBMapperConfig.PaginationLoadingStrategy.EAGER_LOADING) + .build(); + + return new DynamoDBMapper(amazonDynamoDB(), mapperConfig); + } + + @Primary + @Bean + public AWSCredentialsProvider awsCredentialsProvider() { + return new AWSStaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)); + } + + @Bean + public AmazonDynamoDB amazonDynamoDB() { + return AmazonDynamoDBClientBuilder.standard() + .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, region)) + .withCredentials(awsCredentialsProvider()) + .build(); + } +} diff --git a/src/main/java/kr/bb/product/entity/Category.java b/src/main/java/kr/bb/product/entity/Category.java new file mode 100644 index 00000000..19bff879 --- /dev/null +++ b/src/main/java/kr/bb/product/entity/Category.java @@ -0,0 +1,16 @@ +package kr.bb.product.entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Category { + private Long categoryId; + private String categoryName; +} diff --git a/src/main/java/kr/bb/product/entity/Flowers.java b/src/main/java/kr/bb/product/entity/Flowers.java new file mode 100644 index 00000000..49a02ae7 --- /dev/null +++ b/src/main/java/kr/bb/product/entity/Flowers.java @@ -0,0 +1,17 @@ +package kr.bb.product.entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Flowers { + private Long flowerId; + private String flowerName; + private Long stock; +} diff --git a/src/main/java/kr/bb/product/entity/Product.java b/src/main/java/kr/bb/product/entity/Product.java new file mode 100644 index 00000000..54ca05c0 --- /dev/null +++ b/src/main/java/kr/bb/product/entity/Product.java @@ -0,0 +1,56 @@ +package kr.bb.product.entity; + +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey; +import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +@DynamoDBTable(tableName = "product") +public class Product { + @DynamoDBHashKey @DynamoDBAutoGeneratedKey private Long productId; + + @DynamoDBAttribute(attributeName = "category") + private Category category; + + @DynamoDBAttribute(attributeName = "product_name") + private String productName; + + @DynamoDBAttribute(attributeName = "product_summary") + private String productSummary; + + @DynamoDBAttribute(attributeName = "product_price") + private Long productPrice; + + @DynamoDBAttribute(attributeName = "product_sale_status") + private String productSaleStatus; + + @DynamoDBAttribute(attributeName = "tag") + private Tag tag; + + @DynamoDBAttribute(attributeName = "product_flowers") + private Flowers productFlowers; + + @DynamoDBAttribute(attributeName = "product_description_image") + private String productDescriptionImage; + + @DynamoDBAttribute(attributeName = "review_count") + private Long reviewCount; + + @DynamoDBAttribute(attributeName = "product_sale_amount") + private Long productSaleAmount; + + @DynamoDBAttribute(attributeName = "average_rating") + private Double averageRating; + + @DynamoDBAttribute(attributeName = "store_id") + private Long storeId; +} diff --git a/src/main/java/kr/bb/product/entity/Tag.java b/src/main/java/kr/bb/product/entity/Tag.java new file mode 100644 index 00000000..b541ca4b --- /dev/null +++ b/src/main/java/kr/bb/product/entity/Tag.java @@ -0,0 +1,16 @@ +package kr.bb.product.entity; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Tag { + private Long tagId; + private String tagName; +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml deleted file mode 100644 index 3f46f13e..00000000 --- a/src/main/resources/application-local.yml +++ /dev/null @@ -1,11 +0,0 @@ -spring: - # h2 settings - h2: - console: - enabled: true - settings: - web-allow-others: true - path: /h2-console - datasource: - driver-class-name: org.h2.Driver - url: jdbc:h2:mem:product-service;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 63ec1c10..2cdcf21c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,9 @@ server: port: 8800 spring: + mvc: + pathmatch: + matching-strategy: ant_path_matcher application: name: product-service config: @@ -13,4 +16,4 @@ management: exposure: include: - "refresh" - - "bus-refresh" \ No newline at end of file + - "bus-refresh" diff --git a/src/test/java/kr/bb/product/config/DynamoDBConfigurationTest.java b/src/test/java/kr/bb/product/config/DynamoDBConfigurationTest.java new file mode 100644 index 00000000..bf779811 --- /dev/null +++ b/src/test/java/kr/bb/product/config/DynamoDBConfigurationTest.java @@ -0,0 +1,101 @@ +package kr.bb.product.config; + +import static org.assertj.core.api.BDDAssertions.then; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDB; +import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder; +import com.amazonaws.services.dynamodbv2.model.AttributeDefinition; +import com.amazonaws.services.dynamodbv2.model.AttributeValue; +import com.amazonaws.services.dynamodbv2.model.CreateTableRequest; +import com.amazonaws.services.dynamodbv2.model.GetItemRequest; +import com.amazonaws.services.dynamodbv2.model.GetItemResult; +import com.amazonaws.services.dynamodbv2.model.GlobalSecondaryIndex; +import com.amazonaws.services.dynamodbv2.model.KeySchemaElement; +import com.amazonaws.services.dynamodbv2.model.KeyType; +import com.amazonaws.services.dynamodbv2.model.Projection; +import com.amazonaws.services.dynamodbv2.model.ProjectionType; +import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput; +import com.amazonaws.services.dynamodbv2.model.PutItemRequest; +import com.amazonaws.services.dynamodbv2.model.ScalarAttributeType; +import com.amazonaws.services.dynamodbv2.util.TableUtils; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +class DynamoDBConfigurationTest { + private AmazonDynamoDB amazonDynamoDb; + private Map item; + + @BeforeEach + void setup() { + AWSCredentials awsCredentials = new BasicAWSCredentials("key1", "key2"); + AWSCredentialsProvider awsCredentialsProvider = + new AWSStaticCredentialsProvider(awsCredentials); + EndpointConfiguration endpointConfiguration = + new EndpointConfiguration("http://localhost:9000", "ap-northeast-2"); + + amazonDynamoDb = + AmazonDynamoDBClientBuilder.standard() + .withCredentials(awsCredentialsProvider) + .withEndpointConfiguration(endpointConfiguration) + .build(); + + item = new HashMap<>(); + item.put("id", (new AttributeValue()).withS("uuid")); + item.put("orders", (new AttributeValue()).withN("1")); + item.put("content", (new AttributeValue()).withS("comment content")); + item.put("deleted", (new AttributeValue()).withBOOL(false)); + item.put("createdAt", (new AttributeValue()).withS("to be changed")); + item.put("deletedAt", (new AttributeValue()).withS("to be changed")); + } + + @Test + @Disabled + void createTable() { + CreateTableRequest createTableRequest = + (new CreateTableRequest()) + .withAttributeDefinitions( + new AttributeDefinition("id", ScalarAttributeType.S), + new AttributeDefinition("orders", ScalarAttributeType.N), + new AttributeDefinition("createdAt", ScalarAttributeType.S)) + .withTableName("flower") + .withKeySchema(new KeySchemaElement("id", KeyType.HASH)) + .withGlobalSecondaryIndexes( + (new GlobalSecondaryIndex()) + .withIndexName("byFlower") + .withKeySchema( + new KeySchemaElement("orders", KeyType.HASH), + new KeySchemaElement("createdAt", KeyType.RANGE)) + .withProjection((new Projection()).withProjectionType(ProjectionType.ALL)) + .withProvisionedThroughput(new ProvisionedThroughput(1L, 1L))) + .withProvisionedThroughput(new ProvisionedThroughput(1L, 1L)); + + boolean hasTableBeenCreated = + TableUtils.createTableIfNotExists(amazonDynamoDb, createTableRequest); + then(hasTableBeenCreated).isFalse(); + } + + @Test + @Disabled + void getItem_ShouldBeCalledAfterPuttingItem_FoundItem() { + PutItemRequest putItemRequest = (new PutItemRequest()).withTableName("flower").withItem(item); + amazonDynamoDb.putItem(putItemRequest); + + Map key = new HashMap<>(); + key.put("id", (new AttributeValue()).withS("uuid")); + + GetItemRequest getItemRequest = (new GetItemRequest()).withTableName("flower").withKey(key); + + GetItemResult getItemResult = amazonDynamoDb.getItem(getItemRequest); + System.out.println(getItemResult); + + then(getItemResult.getItem()).containsAllEntriesOf(item); + } +}