From c5e7057c119f80db8db8b8e3101cb5167c0d69f6 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Sun, 29 Oct 2023 15:16:14 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat(store):=20redis=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +++ docker-compose.yml | 17 +++++++++ .../cakeke/server/config/RedisConfig.java | 36 +++++++++++++++++++ src/main/resources/application.yml | 4 +++ 4 files changed, 61 insertions(+) create mode 100644 docker-compose.yml create mode 100644 src/main/java/prography/cakeke/server/config/RedisConfig.java diff --git a/build.gradle b/build.gradle index 3a658ec..09e79da 100644 --- a/build.gradle +++ b/build.gradle @@ -21,10 +21,14 @@ repositories { dependencies { //data implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-validation' runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' + implementation('it.ozimov:embedded-redis:0.7.3') { + exclude group: 'org.slf4j', module: 'slf4j-simple' + } // sql implementation group: 'org.postgresql', name: 'postgresql', version: '42.3.1' diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6bb8b6b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,17 @@ +version: "3" + +services: + redis: + image: redis:6 + volumes: + - ./data/redis:/data + command: redis-server --port 6379 + ports: + - "6379:6379" + networks: + - cakk + +networks: + cakk: + labels: + - cakk \ No newline at end of file diff --git a/src/main/java/prography/cakeke/server/config/RedisConfig.java b/src/main/java/prography/cakeke/server/config/RedisConfig.java new file mode 100644 index 0000000..294a114 --- /dev/null +++ b/src/main/java/prography/cakeke/server/config/RedisConfig.java @@ -0,0 +1,36 @@ +package prography.cakeke.server.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Value("${spring.data.redis.host}") + private String host; + + @Value("${spring.data.redis.port}") + private Long port; + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(); + configuration.setHostName(host); + configuration.setPort(port.intValue()); + return new LettuceConnectionFactory(configuration); + } + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + return redisTemplate; + } +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 3dbdb58..5f4d4e9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,6 +13,10 @@ spring: database: postgresql hibernate: ddl-auto: update + data: + redis: + host: ENC(pCIBlNunKRquFLxqCT3VgUicVCF6Z1si) + port: 6379 management: endpoints: From 086f275b41d937d2c5a98185b6ac0aea17a03630 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Mon, 30 Oct 2023 15:14:37 +0900 Subject: [PATCH 2/7] =?UTF-8?q?rename(image):=20S3=20port=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prography/cakeke/server/image/application/port/out/.gitkeep | 0 .../{store => image}/application/port/out/UploadS3Port.java | 2 +- .../cakeke/server/image/application/service/ImageService.java | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 src/main/java/prography/cakeke/server/image/application/port/out/.gitkeep rename src/main/java/prography/cakeke/server/{store => image}/application/port/out/UploadS3Port.java (68%) diff --git a/src/main/java/prography/cakeke/server/image/application/port/out/.gitkeep b/src/main/java/prography/cakeke/server/image/application/port/out/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/prography/cakeke/server/store/application/port/out/UploadS3Port.java b/src/main/java/prography/cakeke/server/image/application/port/out/UploadS3Port.java similarity index 68% rename from src/main/java/prography/cakeke/server/store/application/port/out/UploadS3Port.java rename to src/main/java/prography/cakeke/server/image/application/port/out/UploadS3Port.java index b65a84c..8c0efb0 100644 --- a/src/main/java/prography/cakeke/server/store/application/port/out/UploadS3Port.java +++ b/src/main/java/prography/cakeke/server/image/application/port/out/UploadS3Port.java @@ -1,4 +1,4 @@ -package prography.cakeke.server.store.application.port.out; +package prography.cakeke.server.image.application.port.out; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/prography/cakeke/server/image/application/service/ImageService.java b/src/main/java/prography/cakeke/server/image/application/service/ImageService.java index 4de49b7..909ffe4 100644 --- a/src/main/java/prography/cakeke/server/image/application/service/ImageService.java +++ b/src/main/java/prography/cakeke/server/image/application/service/ImageService.java @@ -10,8 +10,8 @@ import lombok.RequiredArgsConstructor; import prography.cakeke.server.image.application.port.in.ImageUseCase; +import prography.cakeke.server.image.application.port.out.UploadS3Port; import prography.cakeke.server.image.exceptions.NotSupportedFileFormatException; -import prography.cakeke.server.store.application.port.out.UploadS3Port; @Service @RequiredArgsConstructor From e776f50789199fdc6a019720c3da5f9a2a411d01 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Thu, 2 Nov 2023 13:39:47 +0900 Subject: [PATCH 3/7] =?UTF-8?q?rename(image):=20S3=20port=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../prography/cakeke/server/image/adaper/out/AwsS3Adapter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/prography/cakeke/server/image/adaper/out/AwsS3Adapter.java b/src/main/java/prography/cakeke/server/image/adaper/out/AwsS3Adapter.java index 49af7f5..c8dbd9b 100644 --- a/src/main/java/prography/cakeke/server/image/adaper/out/AwsS3Adapter.java +++ b/src/main/java/prography/cakeke/server/image/adaper/out/AwsS3Adapter.java @@ -16,8 +16,8 @@ import com.amazonaws.services.s3.model.PutObjectRequest; import lombok.RequiredArgsConstructor; +import prography.cakeke.server.image.application.port.out.UploadS3Port; import prography.cakeke.server.image.exceptions.InvalidFileNameException; -import prography.cakeke.server.store.application.port.out.UploadS3Port; @Component @RequiredArgsConstructor From e999ce6caa60c9e23cd9b279e969bb2a9281b7a3 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Thu, 2 Nov 2023 13:42:29 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat(store):=20store=20id=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=A5=BC=20redis=EC=97=90=20cache=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 ++ .../adapter/out/external/RedisAdapter.java | 35 +++++++++++++++++++ .../application/port/out/LoadRedisPort.java | 5 +++ .../application/port/out/SaveRedisPort.java | 5 +++ .../application/service/StoreService.java | 27 ++++++++++++-- 5 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 src/main/java/prography/cakeke/server/store/adapter/out/external/RedisAdapter.java create mode 100644 src/main/java/prography/cakeke/server/store/application/port/out/LoadRedisPort.java create mode 100644 src/main/java/prography/cakeke/server/store/application/port/out/SaveRedisPort.java diff --git a/.gitignore b/.gitignore index c2065bc..ce4a75c 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ out/ ### VS Code ### .vscode/ + +### DATA ### +data \ No newline at end of file diff --git a/src/main/java/prography/cakeke/server/store/adapter/out/external/RedisAdapter.java b/src/main/java/prography/cakeke/server/store/adapter/out/external/RedisAdapter.java new file mode 100644 index 0000000..784dcce --- /dev/null +++ b/src/main/java/prography/cakeke/server/store/adapter/out/external/RedisAdapter.java @@ -0,0 +1,35 @@ +package prography.cakeke.server.store.adapter.out.external; + +import java.time.Duration; + +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.stereotype.Repository; + +import lombok.RequiredArgsConstructor; +import prography.cakeke.server.store.application.port.out.LoadRedisPort; +import prography.cakeke.server.store.application.port.out.SaveRedisPort; + +@Repository +@RequiredArgsConstructor +public class RedisAdapter implements LoadRedisPort, SaveRedisPort { + private final RedisTemplate redisTemplate; + private final Integer TTL = 86400; + + @Override + public String save(String key, String value) { + getOperations().set(key, value, Duration.ofMillis(TTL)); + return value; + } + + @Override + public String getByKey(String key) { + return getOperations().get(key); + } + + private ValueOperations getOperations() { + redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class)); + return redisTemplate.opsForValue(); + } +} diff --git a/src/main/java/prography/cakeke/server/store/application/port/out/LoadRedisPort.java b/src/main/java/prography/cakeke/server/store/application/port/out/LoadRedisPort.java new file mode 100644 index 0000000..b68d113 --- /dev/null +++ b/src/main/java/prography/cakeke/server/store/application/port/out/LoadRedisPort.java @@ -0,0 +1,5 @@ +package prography.cakeke.server.store.application.port.out; + +public interface LoadRedisPort { + String getByKey(String key); +} diff --git a/src/main/java/prography/cakeke/server/store/application/port/out/SaveRedisPort.java b/src/main/java/prography/cakeke/server/store/application/port/out/SaveRedisPort.java new file mode 100644 index 0000000..be6f3e8 --- /dev/null +++ b/src/main/java/prography/cakeke/server/store/application/port/out/SaveRedisPort.java @@ -0,0 +1,5 @@ +package prography.cakeke.server.store.application.port.out; + +public interface SaveRedisPort { + String save(String key, String value); +} diff --git a/src/main/java/prography/cakeke/server/store/application/service/StoreService.java b/src/main/java/prography/cakeke/server/store/application/service/StoreService.java index 80afc4b..7bef49c 100644 --- a/src/main/java/prography/cakeke/server/store/application/service/StoreService.java +++ b/src/main/java/prography/cakeke/server/store/application/service/StoreService.java @@ -12,7 +12,9 @@ import prography.cakeke.server.store.adapter.in.web.response.StoreNaverLocalSearchApiResponse; import prography.cakeke.server.store.application.port.in.StoreUseCase; import prography.cakeke.server.store.application.port.out.LoadNaverSearchApiPort; +import prography.cakeke.server.store.application.port.out.LoadRedisPort; import prography.cakeke.server.store.application.port.out.LoadStorePort; +import prography.cakeke.server.store.application.port.out.SaveRedisPort; import prography.cakeke.server.store.domain.District; import prography.cakeke.server.store.domain.Store; import prography.cakeke.server.store.domain.StoreTag; @@ -32,6 +34,8 @@ public class StoreService implements StoreUseCase { private final LoadNaverSearchApiPort loadNaverSearchApiPort; private final LoadStorePort loadStorePort; + private final SaveRedisPort saveRedisPort; + private final LoadRedisPort loadRedisPort; /** * 각 구별 가게의 개수를 반환합니다. @@ -113,8 +117,27 @@ public Store getStore(Long storeId) { */ @Override public StoreNaverLocalSearchApiResponse getNaverLocalApiByStore(Store store) { - final String storeName = store.getName(); - return loadNaverSearchApiPort.getNaverLocalSearchResponse(storeName); + /** + * 1. redis에서 검색해보고 없으면 naver에서 link 정보 가져와 redis에 저장하고 반환. + * 2. redis에 있으면 바로 반환. + */ + String redisResponse = loadRedisPort.getByKey(String.valueOf(store.getId())); + + // redis에 없으면 + if (redisResponse == null) { + StoreNaverLocalSearchApiResponse naverResponse = + loadNaverSearchApiPort.getNaverLocalSearchResponse(store.getName()); + saveRedisPort.save(String.valueOf(store.getId()), naverResponse.getLink()); + return naverResponse; + } + + // redis에 있으면 + return StoreNaverLocalSearchApiResponse.builder() + .link(redisResponse) + .address("") + .phoneNumber("") + .description("") + .build(); } /** From 52229df9fb15a2c7595c09b7866430eab87b7123 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Mon, 6 Nov 2023 15:55:37 +0900 Subject: [PATCH 5/7] =?UTF-8?q?refactor(store):=20application.yml=EC=9D=98?= =?UTF-8?q?=20redis=20=EA=B4=80=EB=A0=A8=20=EC=84=A4=EC=A0=95=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- src/test/resources/application.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 5f4d4e9..0fb2da4 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,7 +15,7 @@ spring: ddl-auto: update data: redis: - host: ENC(pCIBlNunKRquFLxqCT3VgUicVCF6Z1si) + host: ENC(Vu1yuZNRQp9ZpKbWf9/RPQ==) port: 6379 management: diff --git a/src/test/resources/application.yml b/src/test/resources/application.yml index d2d0408..907b310 100644 --- a/src/test/resources/application.yml +++ b/src/test/resources/application.yml @@ -16,6 +16,10 @@ spring: database: postgresql hibernate: ddl-auto: create-drop + data: + redis: + host: ENC(pCIBlNunKRquFLxqCT3VgUicVCF6Z1si) + port: 6379 management: endpoints: From d692c215a375c5301a19ee78516d6eac8541a442 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Mon, 6 Nov 2023 16:25:30 +0900 Subject: [PATCH 6/7] =?UTF-8?q?fix(store):=20=EB=84=A4=EC=9D=B4=EB=B2=84?= =?UTF-8?q?=20=EB=A1=9C=EC=BB=AC=20API=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=A1=9C=EC=A7=81=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- src/test/java/prography/cakeke/server/common/BaseMock.java | 2 +- .../server/store/application/service/StoreServiceTest.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0fb2da4..ab8b090 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,7 +15,7 @@ spring: ddl-auto: update data: redis: - host: ENC(Vu1yuZNRQp9ZpKbWf9/RPQ==) + host: ENC(k9JRvKt85GZzSZSHbXBXrA==) port: 6379 management: diff --git a/src/test/java/prography/cakeke/server/common/BaseMock.java b/src/test/java/prography/cakeke/server/common/BaseMock.java index e5f5efd..3cae4b4 100644 --- a/src/test/java/prography/cakeke/server/common/BaseMock.java +++ b/src/test/java/prography/cakeke/server/common/BaseMock.java @@ -25,7 +25,7 @@ public class BaseMock { protected final StoreType testStoreType = StoreType.CHARACTER; protected final String testNaverStoreName = "끌레르 봉봉"; - protected final String testNaverStoreAddress = "서울특별시 강남구 논현로114길 8 1층 103호 끌레르봉봉"; + protected final String testNaverStoreLink = "http://pf.kakao.com/_busxnC"; protected Store buildStore(String storeName) { return Store.builder() diff --git a/src/test/java/prography/cakeke/server/store/application/service/StoreServiceTest.java b/src/test/java/prography/cakeke/server/store/application/service/StoreServiceTest.java index 0666361..c840e50 100644 --- a/src/test/java/prography/cakeke/server/store/application/service/StoreServiceTest.java +++ b/src/test/java/prography/cakeke/server/store/application/service/StoreServiceTest.java @@ -144,7 +144,7 @@ public void getNaverLocalApiTestSuccess() { StoreNaverLocalSearchApiResponse testStoreNaverLocalSearchApiResponse = storeService.getNaverLocalApiByStore(testStore); - assertThat(testStoreNaverLocalSearchApiResponse.getAddress()).isEqualTo(testNaverStoreAddress); + assertThat(testStoreNaverLocalSearchApiResponse.getLink()).isEqualTo(testNaverStoreLink); } @Test From 4af803eae430e7120501fb501eb4b3ac30f12f85 Mon Sep 17 00:00:00 2001 From: govl6113 Date: Mon, 6 Nov 2023 19:50:25 +0900 Subject: [PATCH 7/7] =?UTF-8?q?feat:=20redis=20test=20container=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +-- .../server/config/RedisTestContainers.java | 26 +++++++++++++++++++ src/test/resources/docker-compose.yml | 8 ++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/test/java/prography/cakeke/server/config/RedisTestContainers.java create mode 100644 src/test/resources/docker-compose.yml diff --git a/build.gradle b/build.gradle index 09e79da..391208d 100644 --- a/build.gradle +++ b/build.gradle @@ -26,9 +26,6 @@ dependencies { runtimeOnly 'com.h2database:h2' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' - implementation('it.ozimov:embedded-redis:0.7.3') { - exclude group: 'org.slf4j', module: 'slf4j-simple' - } // sql implementation group: 'org.postgresql', name: 'postgresql', version: '42.3.1' @@ -41,6 +38,7 @@ dependencies { // test testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.testcontainers:testcontainers:1.17.2' // Swagger implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.4' diff --git a/src/test/java/prography/cakeke/server/config/RedisTestContainers.java b/src/test/java/prography/cakeke/server/config/RedisTestContainers.java new file mode 100644 index 0000000..5292888 --- /dev/null +++ b/src/test/java/prography/cakeke/server/config/RedisTestContainers.java @@ -0,0 +1,26 @@ +package prography.cakeke.server.config; + +import org.junit.jupiter.api.DisplayName; +import org.springframework.context.annotation.Configuration; +import org.testcontainers.containers.GenericContainer; +import org.testcontainers.utility.DockerImageName; + +@DisplayName("Redis Test Containers") +@Configuration +public class RedisTestContainers { + + private static final String REDIS_DOCKER_IMAGE = "redis:5.0.3-alpine"; + + static { // (1) + GenericContainer REDIS_CONTAINER = + new GenericContainer<>(DockerImageName.parse(REDIS_DOCKER_IMAGE)) + .withExposedPorts(6379) + .withReuse(true); + + REDIS_CONTAINER.start(); // (2) + + // (3) + System.setProperty("spring.data.redis.host", REDIS_CONTAINER.getHost()); + System.setProperty("spring.data.redis.port", REDIS_CONTAINER.getMappedPort(6379).toString()); + } +} diff --git a/src/test/resources/docker-compose.yml b/src/test/resources/docker-compose.yml new file mode 100644 index 0000000..a9ca786 --- /dev/null +++ b/src/test/resources/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3" + +services: + redis: + image: redis:7 + command: redis-server --port 6379 + ports: + - "6380:6379"