22
33import java .util .ArrayList ;
44import java .util .Collections ;
5+ import java .util .HashSet ;
56import java .util .List ;
7+ import java .util .Set ;
68import java .util .stream .Collectors ;
79
810import org .springframework .stereotype .Service ;
@@ -32,7 +34,7 @@ public class CategoryService {
3234 private final CategoryConverter categoryConverter ;
3335 private final RedisCacheService redisCacheService ;
3436
35- // 모든 카테고리 조회 (상위 + 하위)
37+ // 모든 카테고리 조회 (상위 + 하위, 상품이 있는 카테고리만 )
3638 public List <CategoryResponse > getAllCategories () {
3739 // Redis 캐시 확인
3840 List <CategoryResponse > cached = redisCacheService .getList (
@@ -46,7 +48,24 @@ public List<CategoryResponse> getAllCategories() {
4648
4749 // Cache Miss → DB 조회
4850 List <Category > parentCategories = categoryRepository .findAllParentCategoriesWithSub ();
49- List <CategoryResponse > response = categoryConverter .toResponseList (parentCategories );
51+ Set <Long > activeCategoryIds = new HashSet <>(productRepository .findCategoryIdsWithOnSaleProducts ());
52+
53+ List <CategoryResponse > response = parentCategories .stream ()
54+ .map (parent -> {
55+ // 판매 중인 상품이 있는 하위 카테고리만 필터링
56+ List <SubCategoryResponse > filteredSubs = parent .getSubCategories ().stream ()
57+ .filter (sub -> activeCategoryIds .contains (sub .getId ()))
58+ .map (categoryConverter ::toSubCategoryResponse )
59+ .collect (Collectors .toList ());
60+
61+ if (filteredSubs .isEmpty ()) {
62+ return null ; // 하위 카테고리에 상품이 전부 없으면 상위 카테고리도 제외
63+ }
64+
65+ return categoryConverter .toResponse (parent , filteredSubs );
66+ })
67+ .filter (r -> r != null )
68+ .collect (Collectors .toList ());
5069
5170 // Redis 캐싱 (무한 TTL)
5271 redisCacheService .save (
@@ -64,27 +83,45 @@ public List<SubCategoryResponse> getSubCategories(Long parentCategoryId) {
6483 return categoryConverter .toSubCategoryResponseList (subCategories );
6584 }
6685
67- // 랜덤 카테고리 조회
86+ // 랜덤 카테고리 조회 (상품이 있는 카테고리만)
6887 public List <CategoryRandomResponse > getRandomCategories (int count ) {
6988 List <Category > allCategories = categoryRepository .findAllByOrderByDisplayOrder ();
70-
71- List <Category > shuffledCategories = new ArrayList <>(allCategories );
72- Collections .shuffle (shuffledCategories );
73-
74- return shuffledCategories .stream ()
75- .limit (count )
76- .map (category -> {
77- String thumbnailUrl = getTopProductThumbnail (category );
78- return categoryConverter .toRandomResponse (category , thumbnailUrl );
89+ Set <Long > activeCategoryIds = new HashSet <>(productRepository .findCategoryIdsWithOnSaleProducts ());
90+
91+ // 상품이 있는 카테고리만 사전 필터링 (상위 카테고리는 하위 중 하나라도 있으면 포함)
92+ List <Category > activeCategories = allCategories .stream ()
93+ .filter (category -> {
94+ if (category .getParentCategory () != null ) {
95+ // 하위 카테고리: 직접 확인
96+ return activeCategoryIds .contains (category .getId ());
97+ }
98+ // 상위 카테고리: 하위 카테고리 중 하나라도 상품이 있으면 포함
99+ return category .getSubCategories ().stream ()
100+ .anyMatch (sub -> activeCategoryIds .contains (sub .getId ()));
79101 })
80102 .collect (Collectors .toList ());
103+
104+ Collections .shuffle (activeCategories );
105+
106+ // 사전 필터링된 카테고리만 썸네일 조회 (DB 호출 최소화)
107+ List <CategoryRandomResponse > result = new ArrayList <>();
108+ for (Category category : activeCategories ) {
109+ if (result .size () >= count ) break ;
110+ String thumbnailUrl = getTopProductThumbnail (category );
111+ if (thumbnailUrl != null ) {
112+ result .add (categoryConverter .toRandomResponse (category , thumbnailUrl ));
113+ }
114+ }
115+ return result ;
81116 }
82117
83- // 추천 하위 카테고리 조회
118+ // 추천 하위 카테고리 조회 (상품이 있는 하위 카테고리만)
84119 public List <CategorySimpleResponse > getRecommendedSubCategories (int count ) {
85120 List <Category > subCategories = categoryRepository .findAllSubCategories ();
121+ Set <Long > activeCategoryIds = new HashSet <>(productRepository .findCategoryIdsWithOnSaleProducts ());
86122
87123 return subCategories .stream ()
124+ .filter (category -> activeCategoryIds .contains (category .getId ()))
88125 .limit (count )
89126 .map (categoryConverter ::toSimpleResponse )
90127 .collect (Collectors .toList ());
0 commit comments