From bd9c2751974b4d9037a94094faba4fbd7ea05123 Mon Sep 17 00:00:00 2001 From: joyewon0705 <77885098+joyewon0705@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:01:58 +0900 Subject: [PATCH 1/4] =?UTF-8?q?Chore:=20Redis=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 7 ++++ .../global/config/EmbeddedRedisConfig.java | 42 +++++++++++++++++++ .../com/back/global/config/RedisConfig.java | 36 ++++++++++++++++ src/main/resources/application-dev.yml | 5 +++ src/main/resources/application-test.yml | 5 +++ 5 files changed, 95 insertions(+) create mode 100644 src/main/java/com/back/global/config/EmbeddedRedisConfig.java create mode 100644 src/main/java/com/back/global/config/RedisConfig.java diff --git a/build.gradle.kts b/build.gradle.kts index 8029184d..decb275a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -63,6 +63,13 @@ dependencies { testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") + + // Redis + implementation("org.springframework.boot:spring-boot-starter-data-redis") + implementation("it.ozimov:embedded-redis:0.7.3") { + exclude(group = "org.slf4j", module = "slf4j-simple") + } + } tasks.withType { diff --git a/src/main/java/com/back/global/config/EmbeddedRedisConfig.java b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java new file mode 100644 index 00000000..64d53d8c --- /dev/null +++ b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java @@ -0,0 +1,42 @@ +package com.back.global.config; + +import jakarta.annotation.PostConstruct; +import jakarta.annotation.PreDestroy; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import redis.embedded.RedisServer; +import redis.embedded.RedisServerBuilder; + +import java.io.IOException; + +/** + * Embedded Redis 설정 클래스 + * - 개발 및 테스트 환경에서만 활성화 (dev, test 프로파일) + * - 애플리케이션 시작 시 내장 Redis 서버 시작 + * - 애플리케이션 종료 시 내장 Redis 서버 중지 + */ +@Configuration +@Profile({"dev", "test"}) +public class EmbeddedRedisConfig { + + private RedisServer redisServer; + + public EmbeddedRedisConfig() throws IOException { + this.redisServer = new RedisServerBuilder() + .port(6379) + .setting("maxheap 256M") + .build(); + } + + @PostConstruct + public void startRedis() { + redisServer.start(); + } + + @PreDestroy + public void stopRedis() { + if (redisServer != null) { + redisServer.stop(); + } + } +} diff --git a/src/main/java/com/back/global/config/RedisConfig.java b/src/main/java/com/back/global/config/RedisConfig.java new file mode 100644 index 00000000..6f8ea292 --- /dev/null +++ b/src/main/java/com/back/global/config/RedisConfig.java @@ -0,0 +1,36 @@ +package com.back.global.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * Redis 설정 클래스 + */ +@Configuration +public class RedisConfig { + + /** + * RedisTemplate 설정 + * - Key: String + * - Value: JSON (Jackson) + */ + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + // Key: String + template.setKeySerializer(new StringRedisSerializer()); + template.setHashKeySerializer(new StringRedisSerializer()); + + // Value: JSON + template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); + template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class)); + + return template; + } +} diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index f79524c8..34da7aa3 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -5,6 +5,11 @@ spring: username: sa password: + data: + redis: + host: localhost + port: 6379 + config: import: optional:file:.env[.properties] diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 6cc589f9..912b47b4 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -5,6 +5,11 @@ spring: username: sa password: + data: + redis: + host: localhost + port: 6379 + jwt: secret: test-jwt-secret-key-12345678901234567890 access-token-expiration: ${JWT_ACCESS_TOKEN_EXPIRATION:1800} # 30분 (초 단위) From 00343e2a783ef4acfd7a86a3737fe92eb3ba7528 Mon Sep 17 00:00:00 2001 From: joyewon0705 <77885098+joyewon0705@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:02:15 +0900 Subject: [PATCH 2/4] =?UTF-8?q?Test:=20Redis=20=EC=97=B0=EA=B2=B0=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/back/RedisConnectionTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/test/java/com/back/RedisConnectionTest.java diff --git a/src/test/java/com/back/RedisConnectionTest.java b/src/test/java/com/back/RedisConnectionTest.java new file mode 100644 index 00000000..94d05e50 --- /dev/null +++ b/src/test/java/com/back/RedisConnectionTest.java @@ -0,0 +1,31 @@ +package com.back; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.test.context.ActiveProfiles; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@ActiveProfiles("test") +class RedisConnectionTest { + + @Autowired + private StringRedisTemplate redisTemplate; + + @Test + void redisShouldStoreAndGetValue() { + // given + String key = "test:key"; + String value = "hello"; + + // when + redisTemplate.opsForValue().set(key, value); + String result = redisTemplate.opsForValue().get(key); + + // then + assertThat(result).isEqualTo(value); + } +} From 67f67cc4e9bbbd1d65a8edb97a64d86adff84c0e Mon Sep 17 00:00:00 2001 From: joyewon0705 <77885098+joyewon0705@users.noreply.github.com> Date: Wed, 24 Sep 2025 16:41:08 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Ref:=20=EB=82=B4=EC=9E=A5=20Redis=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/config/EmbeddedRedisConfig.java | 27 ++++++++++++++----- src/main/resources/application-test.yml | 5 ---- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/back/global/config/EmbeddedRedisConfig.java b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java index 64d53d8c..9eeff535 100644 --- a/src/main/java/com/back/global/config/EmbeddedRedisConfig.java +++ b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java @@ -8,6 +8,7 @@ import redis.embedded.RedisServerBuilder; import java.io.IOException; +import java.net.ServerSocket; /** * Embedded Redis 설정 클래스 @@ -20,17 +21,19 @@ public class EmbeddedRedisConfig { private RedisServer redisServer; + private int port; - public EmbeddedRedisConfig() throws IOException { - this.redisServer = new RedisServerBuilder() - .port(6379) + @PostConstruct + public void startRedis() throws IOException { + port = findAvailablePort(); + redisServer = new RedisServerBuilder() + .port(port) .setting("maxheap 256M") .build(); - } - - @PostConstruct - public void startRedis() { redisServer.start(); + + // 동적으로 찾은 포트를 Spring 환경 변수에 반영 + System.setProperty("spring.data.redis.port", String.valueOf(port)); } @PreDestroy @@ -39,4 +42,14 @@ public void stopRedis() { redisServer.stop(); } } + + // 사용 가능한 포트를 찾는 유틸리티 메서드 + private int findAvailablePort() { + try (ServerSocket socket = new ServerSocket(0)) { + socket.setReuseAddress(true); + return socket.getLocalPort(); + } catch (IOException e) { + throw new IllegalStateException("No available port found", e); + } + } } diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 912b47b4..6cc589f9 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -5,11 +5,6 @@ spring: username: sa password: - data: - redis: - host: localhost - port: 6379 - jwt: secret: test-jwt-secret-key-12345678901234567890 access-token-expiration: ${JWT_ACCESS_TOKEN_EXPIRATION:1800} # 30분 (초 단위) From 9f8736142a2a12a3626244119efc7c795fd0b5ea Mon Sep 17 00:00:00 2001 From: joyewon0705 <77885098+joyewon0705@users.noreply.github.com> Date: Wed, 24 Sep 2025 17:00:24 +0900 Subject: [PATCH 4/4] =?UTF-8?q?Ref:=20=EB=82=B4=EC=9E=A5=20Redis=20?= =?UTF-8?q?=EC=9D=98=EC=A1=B4=EC=84=B1=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 5 +--- .../global/config/EmbeddedRedisConfig.java | 29 ++++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index decb275a..7b0f4824 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -66,10 +66,7 @@ dependencies { // Redis implementation("org.springframework.boot:spring-boot-starter-data-redis") - implementation("it.ozimov:embedded-redis:0.7.3") { - exclude(group = "org.slf4j", module = "slf4j-simple") - } - + implementation("com.github.codemonstur:embedded-redis:1.4.3") } tasks.withType { diff --git a/src/main/java/com/back/global/config/EmbeddedRedisConfig.java b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java index 9eeff535..c569a4b8 100644 --- a/src/main/java/com/back/global/config/EmbeddedRedisConfig.java +++ b/src/main/java/com/back/global/config/EmbeddedRedisConfig.java @@ -5,7 +5,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; import redis.embedded.RedisServer; -import redis.embedded.RedisServerBuilder; import java.io.IOException; import java.net.ServerSocket; @@ -24,26 +23,28 @@ public class EmbeddedRedisConfig { private int port; @PostConstruct - public void startRedis() throws IOException { - port = findAvailablePort(); - redisServer = new RedisServerBuilder() - .port(port) - .setting("maxheap 256M") - .build(); - redisServer.start(); - - // 동적으로 찾은 포트를 Spring 환경 변수에 반영 - System.setProperty("spring.data.redis.port", String.valueOf(port)); + public void startRedis() { + try { + this.port = findAvailablePort(); + this.redisServer = new RedisServer(port); + this.redisServer.start(); + System.setProperty("spring.data.redis.port", String.valueOf(port)); + } catch (IOException e) { + throw new IllegalStateException("Failed to start embedded Redis", e); + } } @PreDestroy public void stopRedis() { - if (redisServer != null) { - redisServer.stop(); + try { + if (redisServer != null && redisServer.isActive()) { + redisServer.stop(); + } + } catch (IOException e) { + throw new IllegalStateException("Failed to stop embedded Redis", e); } } - // 사용 가능한 포트를 찾는 유틸리티 메서드 private int findAvailablePort() { try (ServerSocket socket = new ServerSocket(0)) { socket.setReuseAddress(true);