Skip to content

Commit 1f25551

Browse files
committed
feat : cocktail recommend
1 parent e9c00a6 commit 1f25551

File tree

6 files changed

+111
-3
lines changed

6 files changed

+111
-3
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.back.domain.cocktail.controller;
2+
3+
import com.back.domain.cocktail.dto.CocktailRecommendResponseDto;
4+
import com.back.domain.cocktail.service.RecommendService;
5+
import com.back.global.rsData.RsData;
6+
import io.swagger.v3.oas.annotations.Operation;
7+
import io.swagger.v3.oas.annotations.tags.Tag;
8+
import lombok.RequiredArgsConstructor;
9+
import org.springframework.web.bind.annotation.GetMapping;
10+
import org.springframework.web.bind.annotation.RequestMapping;
11+
import org.springframework.web.bind.annotation.RequestParam;
12+
import org.springframework.web.bind.annotation.RestController;
13+
14+
import java.util.List;
15+
16+
@RestController
17+
@RequestMapping("/cocktails/recommend")
18+
@Tag(name = "ApiCocktailRecommendController", description = "API 칵테일 추천 컨트롤러")
19+
@RequiredArgsConstructor
20+
public class CocktailRecommendController {
21+
22+
private final RecommendService recommendService;
23+
24+
// 상세페이지 추천 (DTO로 반환)
25+
@Operation(summary = "상세페이지 유사 칵테일 추천", description = "현재 칵테일과 유사한 칵테일 최대 3개를 반환합니다.")
26+
@GetMapping("/related")
27+
public RsData<List<CocktailRecommendResponseDto>> recommendRelated(@RequestParam Long cocktailId) {
28+
return RsData.successOf(recommendService.recommendRelatedCocktails(cocktailId, 3));
29+
}
30+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.back.domain.cocktail.dto;
2+
3+
public record CocktailRecommendResponseDto(
4+
Long id, // 상세페이지 이동용 ID
5+
String cocktailNameKo, // 한글 이름
6+
String cocktailName, // 영문 이름
7+
String cocktailImgUrl, // 이미지 URL (썸네일)
8+
String alcoholStrength, // 도수 (라이트/미디엄/스트롱 등)
9+
String alcoholBaseType // 베이스 주종 (진, 럼, 보드카 등)
10+
) {
11+
}
12+

src/main/java/com/back/domain/cocktail/repository/CocktailRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,12 @@ Page<Cocktail> searchWithFilters(@Param("keyword") String keyword,
3636
@Param("types") List<CocktailType> types,
3737
@Param("bases") List<AlcoholBaseType> bases,
3838
Pageable pageable);
39+
//유사칵테일 추천관련
40+
List<Cocktail> findByAlcoholStrengthAndIdNot(AlcoholStrength strength, Long excludeId);
41+
42+
//유사칵테일 추천관련
43+
List<Cocktail> findByCocktailTypeAndIdNot(CocktailType type, Long excludeId);
44+
45+
//유사칵테일 추천관련
46+
List<Cocktail> findByAlcoholBaseTypeAndIdNot(AlcoholBaseType baseType, Long excludeId);
3947
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.back.domain.cocktail.service;
2+
3+
import com.back.domain.cocktail.dto.CocktailRecommendResponseDto;
4+
import com.back.domain.cocktail.entity.Cocktail;
5+
import com.back.domain.cocktail.repository.CocktailRepository;
6+
import lombok.RequiredArgsConstructor;
7+
import org.springframework.stereotype.Service;
8+
9+
import java.util.ArrayList;
10+
import java.util.LinkedHashSet;
11+
import java.util.List;
12+
import java.util.Set;
13+
14+
@Service
15+
@RequiredArgsConstructor
16+
public class RecommendService {
17+
18+
private final CocktailRepository cocktailRepository;
19+
20+
public List<CocktailRecommendResponseDto> recommendRelatedCocktails(Long cocktailId, int maxSize) {
21+
Cocktail current = cocktailRepository.findById(cocktailId)
22+
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 칵테일입니다."));
23+
24+
// 3가지 조건으로 유사 칵테일 조회
25+
List<Cocktail> byAlcoholStrength = cocktailRepository.findByAlcoholStrengthAndIdNot(current.getAlcoholStrength(), current.getId());
26+
List<Cocktail> byCocktailType = cocktailRepository.findByCocktailTypeAndIdNot(current.getCocktailType(), current.getId());
27+
List<Cocktail> byAlcoholBase = cocktailRepository.findByAlcoholBaseTypeAndIdNot(current.getAlcoholBaseType(), current.getId());
28+
29+
// 합치고 중복 제거
30+
Set<Cocktail> combined = new LinkedHashSet<>();
31+
combined.addAll(byAlcoholStrength);
32+
combined.addAll(byCocktailType);
33+
combined.addAll(byAlcoholBase);
34+
35+
List<Cocktail> combinedList = new ArrayList<>(combined);
36+
if (combinedList.size() > maxSize) {
37+
combinedList = combinedList.subList(0, maxSize);
38+
}
39+
40+
// DTO로 변환
41+
return combinedList.stream()
42+
.map(c -> new CocktailRecommendResponseDto(
43+
c.getId(),
44+
c.getCocktailNameKo(),
45+
c.getCocktailName(),
46+
c.getCocktailImgUrl(),
47+
c.getAlcoholStrength().name(),
48+
c.getAlcoholBaseType().name()
49+
))
50+
.toList();
51+
}
52+
}
53+

src/main/java/com/back/global/globalExceptionHandler/GlobalExceptionHandler.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,9 @@ public ResponseEntity<RsData<Void>> handleIOException(IOException e) {
156156
.body(RsData.of(500, "서버 내부 오류가 발생했습니다.", null));
157157
}
158158

159+
@ExceptionHandler(IllegalArgumentException.class)
160+
public ResponseEntity<RsData<Void>> handleIllegalArgumentException(IllegalArgumentException ex) {
161+
return ResponseEntity.status(HttpStatus.NOT_FOUND)
162+
.body(RsData.of(404, ex.getMessage()));
163+
}
159164
}

src/main/resources/data-h2.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- 테이블 생성
22
CREATE TABLE IF NOT EXISTS cocktail (
3-
id BIGINT AUTO_INCREMENT PRIMARY KEY,
4-
cocktail_name VARCHAR(255),
3+
id BIGINT AUTO_INCREMENT PRIMARY KEY,
4+
cocktail_name VARCHAR(255),
55
cocktail_name_ko VARCHAR(255),
66
alcohol_strength VARCHAR(50),
77
cocktail_story CLOB,
@@ -14,7 +14,7 @@ CREATE TABLE IF NOT EXISTS cocktail (
1414

1515
-- CSV 파일에서 데이터 읽어오기
1616
INSERT INTO cocktail (
17-
cocktail_name, cocktail_name_ko, alcohol_strength,
17+
cocktail_name,cocktail_name_ko, alcohol_strength,
1818
cocktail_story, cocktail_type, alcohol_base_type,
1919
ingredient, recipe, cocktail_img_url
2020
)

0 commit comments

Comments
 (0)