Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,20 @@ public RsData<CocktailDetailResponseDto> getCocktailDetailById(@PathVariable lon
return RsData.successOf(cocktailDetailResponseDto);
}

// @param lastValue 다음 페이지에서 이 값보다 작은 항목만 가져오기 위해 사용
// @param lastId 마지막으로 가져온 칵테일 ID (첫 요청 null 가능)
// @param size 가져올 데이터 개수 (기본값 DEFAULT_SIZE)
// @return RsData 형태의 칵테일 요약 정보 리스트
@GetMapping
@Transactional
@Operation(summary = "칵테일 다건 조회")
public RsData<List<CocktailSummaryResponseDto>> getCocktails(
@RequestParam(value = "lastValue", required = false) Long lastValue,
@RequestParam(value = "lastId", required = false) Long lastId,
@RequestParam(value = "size", required = false) Integer size
@RequestParam(value = "size", required = false) Integer size,
@RequestParam(value = "sortBy", required = false, defaultValue = "recent") String sortBy
) {
List<CocktailSummaryResponseDto> cocktails = cocktailService.getCocktails(lastId, size);
List<CocktailSummaryResponseDto> cocktails = cocktailService.getCocktails(lastValue, lastId, size, sortBy);
return RsData.successOf(cocktails);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
package com.back.domain.cocktail.dto;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import com.back.domain.cocktail.entity.Cocktail;

@Getter
@Setter
@NoArgsConstructor
public class CocktailSearchResponseDto {
public record CocktailSearchResponseDto (

private long cocktailId;
private String cocktailName;
private String cocktailNameKo;
private String alcoholStrength;
private String cocktailType;
private String alcoholBaseType;
private String cocktailImgUrl;
private String cocktailStory;
Long cocktailId,
String cocktailName,
String cocktailNameKo,
String alcoholStrength,
String cocktailType,
String alcoholBaseType,
String cocktailImgUrl,
String cocktailStory,
String cocktailPreview
){
public static CocktailSearchResponseDto from(Cocktail cocktail){
String preview =cocktail.getCocktailStory().length() >80 ?
cocktail.getCocktailStory().substring(0,80)+"..."
: cocktail.getCocktailStory();

public CocktailSearchResponseDto(long cocktailId, String cocktailName, String cocktailNameKo,
String alcoholStrength, String cocktailType,
String alcoholBaseType, String cocktailImgUrl,
String cocktailStory) {
this.cocktailId = cocktailId;
this.cocktailName = cocktailName;
this.cocktailNameKo = cocktailNameKo;
this.alcoholStrength = alcoholStrength;
this.cocktailType = cocktailType;
this.alcoholBaseType = alcoholBaseType;
this.cocktailImgUrl = cocktailImgUrl;
this.cocktailStory = cocktailStory;
return new CocktailSearchResponseDto(
cocktail.getId(),
cocktail.getCocktailName(),
cocktail.getCocktailNameKo(),
cocktail.getAlcoholStrength().getDescription(),
cocktail.getCocktailType().getDescription(),
cocktail.getAlcoholBaseType().getDescription(),
cocktail.getCocktailImgUrl(),
cocktail.getCocktailStory(),
preview
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,54 @@
@Repository
public interface CocktailRepository extends JpaRepository<Cocktail, Long> {

// 첫 요청 → 최신순(내림차순)으로 정렬해서 가져오기
// 전체조회 : 최신순
List<Cocktail> findAllByOrderByIdDesc(Pageable pageable);

// 무한스크롤 → lastId보다 작은 ID들 가져오기
List<Cocktail> findByIdLessThanOrderByIdDesc(Long lastId, Pageable pageable);

List<Cocktail> findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase(String cocktailName, String ingredient);
// 전체 조회: keepsCount 기준 내림차순
@Query("""
SELECT c FROM Cocktail c
LEFT JOIN MyBar m ON m.cocktail = c AND m.status = 'ACTIVE'
GROUP BY c.id
ORDER BY COUNT(m) DESC, c.id DESC
""")
List<Cocktail> findAllOrderByKeepCountDesc(Pageable pageable);

// 무한스크롤 조회: lastKeepCount 이하
@Query("""
SELECT c FROM Cocktail c
LEFT JOIN MyBar m ON m.cocktail = c AND m.status = 'ACTIVE'
GROUP BY c.id
HAVING COUNT(m) < :lastKeepCount OR (COUNT(m) = :lastKeepCount AND c.id < :lastId)
ORDER BY COUNT(m) DESC, c.id DESC
""")
List<Cocktail> findByKeepCountLessThanOrderByKeepCountDesc(
@Param("lastKeepCount") Long lastKeepCount,
@Param("lastId") Long lastId,
Pageable pageable
);

// 댓글순
@Query("SELECT c FROM Cocktail c " +
"LEFT JOIN CocktailComment cm ON cm.cocktail = c " +
"GROUP BY c.id " +
"ORDER BY COUNT(cm) DESC, c.id DESC")
List<Cocktail> findAllOrderByCommentsCountDesc(Pageable pageable);

@Query("""
SELECT c FROM Cocktail c
LEFT JOIN CocktailComment cm ON cm.cocktail = c
GROUP BY c.id
HAVING COUNT(cm) < :lastCommentsCount OR (COUNT(cm) = :lastCommentsCount AND c.id < :lastId)
ORDER BY COUNT(cm) DESC, c.id DESC
""")
List<Cocktail> findByCommentsCountLessThanOrderByCommentsCountDesc(
@Param("lastCommentsCount") Long lastCommentsCount,
@Param("lastId") Long lastId,
Pageable pageable
);

//검색, 필터
@Query("SELECT c FROM Cocktail c " +
"WHERE (:keyword IS NULL OR :keyword = '' OR " +
" LOWER(c.cocktailName) LIKE LOWER(CONCAT('%', :keyword, '%')) OR " +
Expand Down
65 changes: 28 additions & 37 deletions src/main/java/com/back/domain/cocktail/service/CocktailService.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,37 +37,41 @@ public Cocktail getCocktailById(Long id) {
.orElseThrow(() -> new IllegalArgumentException("Cocktail not found. id=" + id));
}

// 칵테일 무한스크롤 조회
@Transactional(readOnly = true)
public List<CocktailSummaryResponseDto> getCocktails(Long lastId, Integer size) { // 무한스크롤 조회, 클라이언트 쪽에서 lastId와 size 정보를 받음.(스크롤 이벤트)
public List<CocktailSummaryResponseDto> getCocktails(Long lastValue, Long lastId, Integer size, String sortBy) {
int fetchSize = (size != null) ? size : DEFAULT_SIZE;

Pageable pageable = PageRequest.of(0, fetchSize);
List<Cocktail> cocktails;
if (lastId == null) {
// 첫 요청 → 최신 데이터부터
cocktails = cocktailRepository.findAllByOrderByIdDesc(PageRequest.of(0, fetchSize));
} else {
// 무한스크롤 → 마지막 ID보다 작은 데이터 조회
cocktails = cocktailRepository.findByIdLessThanOrderByIdDesc(lastId, PageRequest.of(0, fetchSize));

switch (sortBy != null ? sortBy.toLowerCase() : "") {
case "keeps":
cocktails = (lastValue == null)
? cocktailRepository.findAllOrderByKeepCountDesc(pageable)
: cocktailRepository.findByKeepCountLessThanOrderByKeepCountDesc(lastValue, lastId, pageable);
break;
case "comments":
cocktails = (lastValue == null)
? cocktailRepository.findAllOrderByCommentsCountDesc(pageable)
: cocktailRepository.findByCommentsCountLessThanOrderByCommentsCountDesc(lastValue, lastId, pageable);
break;
default:
cocktails = (lastValue == null)
? cocktailRepository.findAllByOrderByIdDesc(pageable)
: cocktailRepository.findByIdLessThanOrderByIdDesc(lastValue, pageable);
break;
}

return cocktails.stream()
.map(c -> new CocktailSummaryResponseDto(c.getId(), c.getCocktailName(), c.getCocktailNameKo(), c.getCocktailImgUrl(), c.getAlcoholStrength().getDescription()))
.map(c -> new CocktailSummaryResponseDto(
c.getId(),
c.getCocktailName(),
c.getCocktailNameKo(),
c.getCocktailImgUrl(),
c.getAlcoholStrength().getDescription()
))
.collect(Collectors.toList());
}

// 칵테일 검색기능
@Transactional(readOnly = true)
public List<Cocktail> cocktailSearch(String keyword) {
// cockTailName, ingredient이 하나만 있을 수도 있고 둘 다 있을 수도 있음
if (keyword == null || keyword.trim().isEmpty()) {
// 아무 검색어 없으면 전체 반환 처리
return cocktailRepository.findAll();
} else {
// 이름 또는 재료 둘 중 하나라도 매칭되면 결과 반환
return cocktailRepository.findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase(keyword, keyword);
}
}

// 칵테일 검색,필터기능
@Transactional(readOnly = true)
public List<CocktailSearchResponseDto> searchAndFilter(CocktailSearchRequestDto cocktailSearchRequestDto) {
Expand Down Expand Up @@ -105,25 +109,12 @@ public List<CocktailSearchResponseDto> searchAndFilter(CocktailSearchRequestDto

//Cocktail 엔티티 → CocktailResponseDto 응답 DTO로 바꿔주는 과정
List<CocktailSearchResponseDto> resultDtos = pageResult.stream()
.map(c -> new CocktailSearchResponseDto(
c.getId(),
c.getCocktailName(),
c.getCocktailNameKo(),
c.getAlcoholStrength().getDescription(),
c.getCocktailType().getDescription(),
c.getAlcoholBaseType().getDescription(),
c.getCocktailImgUrl(),
c.getCocktailStory()
))
.map(CocktailSearchResponseDto::from)
.collect(Collectors.toList());

return resultDtos;
}

// private <T> List<T> nullIfEmpty(List<T> list) {
// return CollectionUtils.isEmpty(list) ? null : list;
// }

// 칵테일 상세조회
@Transactional(readOnly = true)
public CocktailDetailResponseDto getCocktailDetailById(Long cocktailId) {
Expand Down