11package com .back .domain .cocktail .service ;
22
3+ import com .back .domain .cocktail .dto .CocktailDetailDto ;
4+ import com .back .domain .cocktail .dto .CocktailFilterRequestDto ;
5+ import com .back .domain .cocktail .dto .CocktailResponseDto ;
36import com .back .domain .cocktail .dto .CocktailSummaryDto ;
47import com .back .domain .cocktail .entity .Cocktail ;
8+ import com .back .domain .cocktail .enums .AlcoholBaseType ;
9+ import com .back .domain .cocktail .enums .AlcoholStrength ;
10+ import com .back .domain .cocktail .enums .CocktailType ;
511import com .back .domain .cocktail .repository .CocktailRepository ;
612import lombok .RequiredArgsConstructor ;
13+ import org .springframework .data .domain .Page ;
714import org .springframework .data .domain .PageRequest ;
15+ import org .springframework .data .domain .Pageable ;
816import org .springframework .stereotype .Service ;
917import org .springframework .transaction .annotation .Transactional ;
18+ import org .springframework .util .CollectionUtils ;
19+
1020import java .util .List ;
21+ import java .util .NoSuchElementException ;
1122import java .util .stream .Collectors ;
1223
1324@ Service
@@ -20,38 +31,103 @@ public class CocktailService {
2031
2132 @ Transactional (readOnly = true )
2233 public Cocktail getCocktailById (Long id ) {
23- return cocktailRepository .findById (id )
24- .orElseThrow (() -> new IllegalArgumentException ("User not found. id=" + id ));
25- }
34+ return cocktailRepository .findById (id )
35+ .orElseThrow (() -> new IllegalArgumentException ("User not found. id=" + id ));
36+ }
2637
27- // 칵테일 무한스크롤 조회
28- @ Transactional (readOnly = true )
29- public List <CocktailSummaryDto > getCocktails (Long lastId , Integer size ) { // 무한스크롤 조회, 클라이언트 쪽에서 lastId와 size 정보를 받음.(스크롤 이벤트)
30- int fetchSize = (size != null ) ? size : DEFAULT_SIZE ;
31-
32- List <Cocktail > cocktails ;
33- if (lastId == null ) {
34- // 첫 요청 → 최신 데이터부터
35- cocktails = cocktailRepository .findAllByOrderByCocktailIdDesc (PageRequest .of (0 , fetchSize ));
36- } else {
37- // 무한스크롤 → 마지막 ID보다 작은 데이터 조회
38- cocktails = cocktailRepository .findByCocktailIdLessThanOrderByCocktailIdDesc (lastId , PageRequest .of (0 , fetchSize ));
38+ // 칵테일 무한스크롤 조회
39+ @ Transactional (readOnly = true )
40+ public List <CocktailSummaryDto > getCocktails (Long lastId , Integer size )
41+ { // 무한스크롤 조회, 클라이언트 쪽에서 lastId와 size 정보를 받음.(스크롤 이벤트)
42+ int fetchSize = (size != null ) ? size : DEFAULT_SIZE ;
43+
44+ List <Cocktail > cocktails ;
45+ if (lastId == null ) {
46+ // 첫 요청 → 최신 데이터부터
47+ cocktails = cocktailRepository .findAllByOrderByCocktailIdDesc (PageRequest .of (0 , fetchSize ));
48+ } else {
49+ // 무한스크롤 → 마지막 ID보다 작은 데이터 조회
50+ cocktails = cocktailRepository .findByCocktailIdLessThanOrderByCocktailIdDesc (lastId , PageRequest .of (0 , fetchSize ));
51+ }
52+ return cocktails .stream ()
53+ .map (c -> new CocktailSummaryDto (c .getCocktailId (), c .getCocktailName (), c .getCocktailImgUrl ()))
54+ .collect (Collectors .toList ());
3955 }
4056
41- return cocktails .stream ()
42- .map (c -> new CocktailSummaryDto (c .getCocktailId (), c .getCocktailName (), c .getCocktailImgUrl ()))
43- .collect (Collectors .toList ());
44- }
57+ // 칵테일 검색기능
58+ @ Transactional (readOnly = true )
59+ public List <Cocktail > cocktailSearch (String keyword ){
60+ // cockTailName, ingredient이 하나만 있을 수도 있고 둘 다 있을 수도 있음
61+ if (keyword == null || keyword .trim ().isEmpty ()) {
62+ // 아무 검색어 없으면 전체 반환 처리
63+ return cocktailRepository .findAll ();
64+ } else {
65+ // 이름 또는 재료 둘 중 하나라도 매칭되면 결과 반환
66+ return cocktailRepository .findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase (keyword , keyword );
67+ }
68+ }
69+
70+ // 칵테일 검색,필터기능
71+ @ Transactional (readOnly = true )
72+ public List <CocktailResponseDto > searchAndFilter (CocktailFilterRequestDto cocktailFilterRequestDto ){
73+ // 기본값 페이지/사이즈 정하기(PAGE 기본값 0, 사이즈 10)
74+ int page = cocktailFilterRequestDto .getPage () != null && cocktailFilterRequestDto .getPage () >= 0
75+ ? cocktailFilterRequestDto .getPage () : 0 ;
76+
77+ int size = cocktailFilterRequestDto .getSize () != null && cocktailFilterRequestDto .getSize () > 0
78+ ? cocktailFilterRequestDto .getSize () : DEFAULT_SIZE ;
79+
80+ // searchWithFilters에서 조회한 결과값을 pageResult에 저장.
81+ Pageable pageable = PageRequest .of (page , size );
82+
83+ // 빈 리스트(null 또는 [])는 null로 변환
84+ List <AlcoholStrength > strengths = CollectionUtils .isEmpty (cocktailFilterRequestDto .getAlcoholStrengths ())
85+ ? null
86+ : cocktailFilterRequestDto .getAlcoholStrengths ();
87+
88+ List <CocktailType > types = CollectionUtils .isEmpty (cocktailFilterRequestDto .getCocktailTypes ())
89+ ? null
90+ : cocktailFilterRequestDto .getCocktailTypes ();
91+
92+ List <AlcoholBaseType > bases = CollectionUtils .isEmpty (cocktailFilterRequestDto .getAlcoholBaseTypes ())
93+ ? null
94+ : cocktailFilterRequestDto .getAlcoholBaseTypes ();
95+
96+ // Repository 호출
97+ Page <Cocktail > pageResult = cocktailRepository .searchWithFilters (
98+ cocktailFilterRequestDto .getKeyword (),
99+ strengths , // List<AlcoholStrength>
100+ types , // List<CocktailType>
101+ bases , // List<AlcoholBaseType>
102+ pageable
103+ );
104+
105+ //Cocktail 엔티티 → CocktailResponseDto 응답 DTO로 바꿔주는 과정
106+ List <CocktailResponseDto > resultDtos = pageResult .stream ()
107+ .map (c -> new CocktailResponseDto (
108+ c .getCocktailId (),
109+ c .getCocktailName (),
110+ c .getAlcoholStrength (),
111+ c .getCocktailType (),
112+ c .getAlcoholBaseType (),
113+ c .getCocktailImgUrl (),
114+ c .getCocktailStory (),
115+ c .getCreatedAt ()
116+ ))
117+ .collect (Collectors .toList ());
118+
119+ return resultDtos ;
120+ }
121+
122+ // private <T> List<T> nullIfEmpty(List<T> list) {
123+ // return CollectionUtils.isEmpty(list) ? null : list;
124+ // }
45125
46- // 칵테일 검색기능
47- public List <Cocktail > cocktailSearch (String keyword ) {
48- // cockTailName, ingredient이 하나만 있을 수도 있고 둘 다 있을 수도 있음
49- if (keyword == null || keyword .trim ().isEmpty ()) {
50- // 아무 검색어 없으면 전체 반환 처리
51- return cocktailRepository .findAll ();
52- } else {
53- // 이름 또는 재료 둘 중 하나라도 매칭되면 결과 반환
54- return cocktailRepository .findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase (keyword , keyword );
126+ // 칵테일 상세조회
127+ @ Transactional (readOnly = true )
128+ public CocktailDetailDto getCocktailDetailById (Long cocktailId ){
129+ Cocktail cocktail = cocktailRepository .findById (cocktailId )
130+ .orElseThrow (() -> new NoSuchElementException ("칵테일을 찾을 수 없습니다. id: " + cocktailId ));
131+ return new CocktailDetailDto (cocktail );
55132 }
56133 }
57- }
0 commit comments