diff --git a/src/main/java/com/ongil/backend/domain/category/controller/CategoryController.java b/src/main/java/com/ongil/backend/domain/category/controller/CategoryController.java index 66cdcda..e459f49 100644 --- a/src/main/java/com/ongil/backend/domain/category/controller/CategoryController.java +++ b/src/main/java/com/ongil/backend/domain/category/controller/CategoryController.java @@ -60,4 +60,13 @@ public DataResponse> getRecommendedSubCategories( List categories = categoryService.getRecommendedSubCategories(count); return DataResponse.from(categories); } + + @Operation(summary = "오늘의 추천 카테고리 조회", description = "오늘의 추천 카테고리를 조회합니다. 매일 다른 카테고리가 추천됩니다.") + @GetMapping("/today-recommended") + public DataResponse> getTodayRecommendedCategories( + @RequestParam(defaultValue = "8") @Min(1) @Max(100) int count + ) { + List categories = categoryService.getTodayRecommendedCategories(count); + return DataResponse.from(categories); + } } diff --git a/src/main/java/com/ongil/backend/domain/category/service/CategoryService.java b/src/main/java/com/ongil/backend/domain/category/service/CategoryService.java index 638f41f..2d1c5f1 100644 --- a/src/main/java/com/ongil/backend/domain/category/service/CategoryService.java +++ b/src/main/java/com/ongil/backend/domain/category/service/CategoryService.java @@ -1,8 +1,10 @@ package com.ongil.backend.domain.category.service; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Random; import java.util.stream.Collectors; import org.springframework.stereotype.Service; @@ -90,6 +92,47 @@ public List getRecommendedSubCategories(int count) { .collect(Collectors.toList()); } + // 오늘의 추천 카테고리 조회 (매일 다른 카테고리) + public List getTodayRecommendedCategories(int count) { + LocalDate today = LocalDate.now(); + // Redis 캐시 키에 날짜 포함 + String cacheKey = CacheKeyConstants.TODAY_RECOMMENDED_CATEGORIES + ":" + today; + + // Redis 캐시 확인 + List cached = redisCacheService.getList( + cacheKey, + CategorySimpleResponse.class + ); + + if (cached != null && cached.size() >= count) { + return cached.stream() + .limit(count) + .collect(Collectors.toList()); + } + + // Cache Miss → DB 조회 후 날짜 기반 셔플 + List subCategories = categoryRepository.findAllSubCategories(); + + // 날짜를 시드로 사용하여 매일 다른 순서로 셔플 + List shuffledCategories = new ArrayList<>(subCategories); + long seed = today.toEpochDay(); // 날짜를 시드로 사용 + Collections.shuffle(shuffledCategories, new Random(seed)); + + List response = shuffledCategories.stream() + .limit(count) + .map(categoryConverter::toSimpleResponse) + .collect(Collectors.toList()); + + // Redis 캐싱 (하루 동안 유지) + redisCacheService.save( + cacheKey, + response, + CacheKeyConstants.DAILY_TTL_HOURS + ); + + return response; + } + private String getTopProductThumbnail(Category category) { Long targetCategoryId; diff --git a/src/main/java/com/ongil/backend/global/config/redis/CacheKeyConstants.java b/src/main/java/com/ongil/backend/global/config/redis/CacheKeyConstants.java index 544673a..3dbb3e5 100644 --- a/src/main/java/com/ongil/backend/global/config/redis/CacheKeyConstants.java +++ b/src/main/java/com/ongil/backend/global/config/redis/CacheKeyConstants.java @@ -5,7 +5,9 @@ public class CacheKeyConstants { // Brand/Category 캐시 관련 public static final String BRANDS_ALL = "BRANDS:ALL"; public static final String CATEGORIES_ALL = "CATEGORIES:ALL"; + public static final String TODAY_RECOMMENDED_CATEGORIES = "CATEGORIES:TODAY_RECOMMENDED"; public static final long MASTER_DATA_TTL_HOURS = 0; // 무한 TTL + public static final long DAILY_TTL_HOURS = 24; // 하루 TTL private CacheKeyConstants() { throw new IllegalStateException("Utility class");