mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2026-06-12 23:19:10 +00:00
Content Service Redis 연동 및 테스트 완료
- RedisConfig.java: Production용 Redis 설정 추가 - RedisGateway.java: Redis 읽기/쓰기 Gateway 구현 - application-local.yml: Redis/Kafka auto-configuration 제외 설정 - test-backend.md: 7개 API 테스트 결과서 작성 (100% 성공) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
package com.kt.event.content.infra.config;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
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.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
/**
|
||||
* Redis 설정 (Production 환경용)
|
||||
* Local/Test 환경에서는 Mock Gateway 사용
|
||||
*/
|
||||
@Configuration
|
||||
@Profile({"!local", "!test"})
|
||||
public class RedisConfig {
|
||||
|
||||
@Value("${spring.data.redis.host}")
|
||||
private String host;
|
||||
|
||||
@Value("${spring.data.redis.port}")
|
||||
private int port;
|
||||
|
||||
@Bean
|
||||
public RedisConnectionFactory redisConnectionFactory() {
|
||||
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(host, port);
|
||||
return new LettuceConnectionFactory(config);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||||
template.setConnectionFactory(connectionFactory);
|
||||
|
||||
// String serializer for keys
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// JSON serializer for values
|
||||
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
|
||||
template.setValueSerializer(serializer);
|
||||
template.setHashValueSerializer(serializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package com.kt.event.content.infra.gateway;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.kt.event.content.biz.domain.GeneratedImage;
|
||||
import com.kt.event.content.biz.usecase.out.RedisAIDataReader;
|
||||
import com.kt.event.content.biz.usecase.out.RedisImageWriter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Redis Gateway 구현체 (Production 환경용)
|
||||
*
|
||||
* Local/Test 환경에서는 MockRedisGateway 사용
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@Profile({"!local", "!test"})
|
||||
@RequiredArgsConstructor
|
||||
public class RedisGateway implements RedisAIDataReader, RedisImageWriter {
|
||||
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private static final String AI_DATA_KEY_PREFIX = "ai:event:";
|
||||
private static final String IMAGE_URL_KEY_PREFIX = "image:url:";
|
||||
private static final Duration DEFAULT_TTL = Duration.ofHours(24);
|
||||
|
||||
@Override
|
||||
public Optional<Map<String, Object>> getAIRecommendation(Long eventDraftId) {
|
||||
try {
|
||||
String key = AI_DATA_KEY_PREFIX + eventDraftId;
|
||||
Object data = redisTemplate.opsForValue().get(key);
|
||||
|
||||
if (data == null) {
|
||||
log.warn("AI 이벤트 데이터를 찾을 수 없음: eventDraftId={}", eventDraftId);
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> aiData = objectMapper.convertValue(data, Map.class);
|
||||
return Optional.of(aiData);
|
||||
} catch (Exception e) {
|
||||
log.error("AI 이벤트 데이터 조회 실패: eventDraftId={}", eventDraftId, e);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheImages(Long eventDraftId, List<GeneratedImage> images, long ttlSeconds) {
|
||||
try {
|
||||
String key = IMAGE_URL_KEY_PREFIX + eventDraftId;
|
||||
|
||||
// 이미지 목록을 캐싱
|
||||
redisTemplate.opsForValue().set(key, images, Duration.ofSeconds(ttlSeconds));
|
||||
log.info("이미지 목록 캐싱 완료: eventDraftId={}, count={}, ttl={}초",
|
||||
eventDraftId, images.size(), ttlSeconds);
|
||||
} catch (Exception e) {
|
||||
log.error("이미지 목록 캐싱 실패: eventDraftId={}", eventDraftId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 이미지 URL 캐시 삭제
|
||||
*/
|
||||
public void deleteImageUrl(Long eventDraftId) {
|
||||
try {
|
||||
String key = IMAGE_URL_KEY_PREFIX + eventDraftId;
|
||||
redisTemplate.delete(key);
|
||||
log.info("이미지 URL 캐시 삭제: eventDraftId={}", eventDraftId);
|
||||
} catch (Exception e) {
|
||||
log.error("이미지 URL 캐시 삭제 실패: eventDraftId={}", eventDraftId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 이벤트 데이터 캐시 삭제
|
||||
*/
|
||||
public void deleteAIEventData(Long eventDraftId) {
|
||||
try {
|
||||
String key = AI_DATA_KEY_PREFIX + eventDraftId;
|
||||
redisTemplate.delete(key);
|
||||
log.info("AI 이벤트 데이터 캐시 삭제: eventDraftId={}", eventDraftId);
|
||||
} catch (Exception e) {
|
||||
log.error("AI 이벤트 데이터 캐시 삭제 실패: eventDraftId={}", eventDraftId, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ spring:
|
||||
path: /h2-console
|
||||
|
||||
jpa:
|
||||
database-platform: org.hibernate.dialect.H2Dialect
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
show-sql: true
|
||||
@@ -24,10 +25,20 @@ spring:
|
||||
# Redis 연결 비활성화 (Mock 사용)
|
||||
repositories:
|
||||
enabled: false
|
||||
host: localhost
|
||||
port: 6379
|
||||
|
||||
kafka:
|
||||
# Kafka 연결 비활성화 (Mock 사용)
|
||||
bootstrap-servers: localhost:9092
|
||||
consumer:
|
||||
enabled: false
|
||||
|
||||
autoconfigure:
|
||||
exclude:
|
||||
- org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
|
||||
- org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
|
||||
- org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration
|
||||
|
||||
server:
|
||||
port: 8084
|
||||
@@ -36,3 +47,4 @@ logging:
|
||||
level:
|
||||
com.kt.event: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
|
||||
|
||||
Reference in New Issue
Block a user