diff --git a/.gitignore b/.gitignore index a6323b24..791b46b9 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ db_dev.mv.db db_dev.trace.db ### Environment Variables ### -.env \ No newline at end of file +.env + diff --git a/src/main/java/com/back/domain/cocktail/dto/CocktailRequestDto.java b/src/main/java/com/back/domain/cocktail/dto/CocktailRequestDto.java index ad38cd89..e2e0c683 100644 --- a/src/main/java/com/back/domain/cocktail/dto/CocktailRequestDto.java +++ b/src/main/java/com/back/domain/cocktail/dto/CocktailRequestDto.java @@ -1,6 +1,8 @@ package com.back.domain.cocktail.dto; -import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.Getter; @@ -16,12 +18,12 @@ public class CocktailRequestDto { private String cocktailName; @NotNull - private Cocktail.AlcoholStrength alcoholStrength; + private AlcoholStrength alcoholStrength; private String cocktailStory; - private Cocktail.CocktailType cocktailType; + private CocktailType cocktailType; + private AlcoholBaseType alcoholBaseType; private String ingredient; private String recipe; - private String imageUrl; - + private String cocktailImgUrl; } diff --git a/src/main/java/com/back/domain/cocktail/dto/CocktailResponseDto.java b/src/main/java/com/back/domain/cocktail/dto/CocktailResponseDto.java index db4712b5..3fb8b929 100644 --- a/src/main/java/com/back/domain/cocktail/dto/CocktailResponseDto.java +++ b/src/main/java/com/back/domain/cocktail/dto/CocktailResponseDto.java @@ -1,6 +1,8 @@ package com.back.domain.cocktail.dto; -import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -14,12 +16,13 @@ public class CocktailResponseDto { private long cocktailId; private String cocktailName; - private Cocktail.AlcoholStrength alcoholStrength; + private AlcoholStrength alcoholStrength; private String cocktailStory; - private Cocktail.CocktailType cocktailType; + private CocktailType cocktailType; + private AlcoholBaseType alcoholBaseType; private String ingredient; private String recipe; - private String imageUrl; + private String cocktailImgUrl; private LocalDateTime createdAt; private LocalDateTime updatedAt; diff --git a/src/main/java/com/back/domain/cocktail/dto/CocktailSummaryDto.java b/src/main/java/com/back/domain/cocktail/dto/CocktailSummaryDto.java new file mode 100644 index 00000000..436e9052 --- /dev/null +++ b/src/main/java/com/back/domain/cocktail/dto/CocktailSummaryDto.java @@ -0,0 +1,16 @@ +package com.back.domain.cocktail.dto; + +import lombok.Getter; + +@Getter +public class CocktailSummaryDto { + private Long cocktailId; + private String cocktailName; + private String cocktailImgUrl; + + public CocktailSummaryDto(Long id, String name, String imageUrl) { + this.cocktailId = id; + this.cocktailName = name; + this.cocktailImgUrl = imageUrl; + } +} diff --git a/src/main/java/com/back/domain/cocktail/entity/Cocktail.java b/src/main/java/com/back/domain/cocktail/entity/Cocktail.java index 8a7a5126..d1761922 100644 --- a/src/main/java/com/back/domain/cocktail/entity/Cocktail.java +++ b/src/main/java/com/back/domain/cocktail/entity/Cocktail.java @@ -1,9 +1,10 @@ package com.back.domain.cocktail.entity; +import com.back.domain.cocktail.enums.AlcoholBaseType; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.enums.CocktailType; import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import java.time.LocalDateTime; @@ -13,6 +14,9 @@ @Getter @Setter @NoArgsConstructor +@AllArgsConstructor +@Builder +@ToString @Entity public class Cocktail { @Id @@ -24,52 +28,19 @@ public class Cocktail { @Enumerated(EnumType.STRING) private AlcoholStrength alcoholStrength; // 칵테일 알콜 도수 - public enum AlcoholStrength { - NON_ALCOHOLIC("논알콜 (0%)"), - WEAK("약한 도수 (1~5%)"), - LIGHT("가벼운 도수 (6~15%)"), - MEDIUM("중간 도수 (16~25%)"), - STRONG("센 도수 (26~35%)"), - VERY_STRONG("매우 센 도수 (36%~)"); - - private final String description; - - AlcoholStrength(String description) { - this.description = description; - } - - public String getDescription() { - return description; - } - } - private String cocktailStory; // 칵테일 유래 등 이야기 @Enumerated(EnumType.STRING) private CocktailType cocktailType; // 칵테일 컵에 따른 분류 - public enum CocktailType { - SHORT("숏"), - LONG("롱"), - SHOOTER("슈터"), - CLASSIC("클래식"); - - private final String description; - - CocktailType(String description) { - this.description = description; - } - - public String getDescription() { - return description; - } - } + @Enumerated(EnumType.STRING) + private AlcoholBaseType alcoholBaseType; // 칵테일 베이스에 따른 분류 private String ingredient; private String recipe; - private String imageUrl; + private String cocktailImgUrl; private LocalDateTime createdAt; diff --git a/src/main/java/com/back/domain/cocktail/enums/AlcoholBaseType.java b/src/main/java/com/back/domain/cocktail/enums/AlcoholBaseType.java new file mode 100644 index 00000000..6e6d173c --- /dev/null +++ b/src/main/java/com/back/domain/cocktail/enums/AlcoholBaseType.java @@ -0,0 +1,22 @@ +package com.back.domain.cocktail.enums; + +public enum AlcoholBaseType { + GIN("진"), + BRANDY("브랜디"), + RUM("럼"), + VODKA("보드카"), + LIQUEUR("리큐르"), + WHISKY("위스키"), + TEQUILA("데낄라"), + WINE("와인"), + OTHER("기타"); + + private final String description; + + AlcoholBaseType(String description) { + this.description = description; + } + public String getDescription() { + return description; + } +} diff --git a/src/main/java/com/back/domain/cocktail/enums/AlcoholStrength.java b/src/main/java/com/back/domain/cocktail/enums/AlcoholStrength.java new file mode 100644 index 00000000..d580b50b --- /dev/null +++ b/src/main/java/com/back/domain/cocktail/enums/AlcoholStrength.java @@ -0,0 +1,21 @@ +package com.back.domain.cocktail.enums; + +public enum AlcoholStrength { + NON_ALCOHOLIC("논알콜 (0%)"), + WEAK("약한 도수 (1~5%)"), + LIGHT("가벼운 도수 (6~15%)"), + MEDIUM("중간 도수 (16~25%)"), + STRONG("센 도수 (26~35%)"), + VERY_STRONG("매우 센 도수 (36%~)"); + + private final String description; + + AlcoholStrength(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + +} diff --git a/src/main/java/com/back/domain/cocktail/enums/CocktailType.java b/src/main/java/com/back/domain/cocktail/enums/CocktailType.java new file mode 100644 index 00000000..ebf9b1f2 --- /dev/null +++ b/src/main/java/com/back/domain/cocktail/enums/CocktailType.java @@ -0,0 +1,18 @@ +package com.back.domain.cocktail.enums; + +public enum CocktailType { + SHORT("숏"), + LONG("롱"), + SHOOTER("슈터"), + CLASSIC("클래식"); + + private final String description; + + CocktailType(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/main/java/com/back/domain/cocktail/repository/CocktailRepository.java b/src/main/java/com/back/domain/cocktail/repository/CocktailRepository.java index df7177a0..9aa69286 100644 --- a/src/main/java/com/back/domain/cocktail/repository/CocktailRepository.java +++ b/src/main/java/com/back/domain/cocktail/repository/CocktailRepository.java @@ -1,9 +1,20 @@ package com.back.domain.cocktail.repository; import com.back.domain.cocktail.entity.Cocktail; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface CocktailRepository extends JpaRepository { + + // 첫 요청 → 최신순(내림차순)으로 정렬해서 가져오기 + List findAllByOrderByCocktailIdDesc(Pageable pageable); + + // 무한스크롤 → lastId보다 작은 ID들 가져오기 + List findByCocktailIdLessThanOrderByCocktailIdDesc(Long lastId, Pageable pageable); + + List findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase(String cocktailName, String ingredient); } diff --git a/src/main/java/com/back/domain/cocktail/service/CocktailService.java b/src/main/java/com/back/domain/cocktail/service/CocktailService.java new file mode 100644 index 00000000..61d4ca9f --- /dev/null +++ b/src/main/java/com/back/domain/cocktail/service/CocktailService.java @@ -0,0 +1,57 @@ +package com.back.domain.cocktail.service; + +import com.back.domain.cocktail.dto.CocktailSummaryDto; +import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.repository.CocktailRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class CocktailService { + + private final CocktailRepository cocktailRepository; + + private static final int DEFAULT_SIZE = 20; + + @Transactional(readOnly = true) + public Cocktail getCocktailById(Long id) { + return cocktailRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("User not found. id=" + id)); + } + + // 칵테일 무한스크롤 조회 + @Transactional(readOnly = true) + public List getCocktails(Long lastId, Integer size) { // 무한스크롤 조회, 클라이언트 쪽에서 lastId와 size 정보를 받음.(스크롤 이벤트) + int fetchSize = (size != null) ? size : DEFAULT_SIZE; + + List cocktails; + if (lastId == null) { + // 첫 요청 → 최신 데이터부터 + cocktails = cocktailRepository.findAllByOrderByCocktailIdDesc(PageRequest.of(0, fetchSize)); + } else { + // 무한스크롤 → 마지막 ID보다 작은 데이터 조회 + cocktails = cocktailRepository.findByCocktailIdLessThanOrderByCocktailIdDesc(lastId, PageRequest.of(0, fetchSize)); + } + + return cocktails.stream() + .map(c -> new CocktailSummaryDto(c.getCocktailId(), c.getCocktailName(), c.getCocktailImgUrl())) + .collect(Collectors.toList()); + } + + // 칵테일 검색기능 + public List cocktailSearch(String keyword) { + // cockTailName, ingredient이 하나만 있을 수도 있고 둘 다 있을 수도 있음 + if (keyword == null || keyword.trim().isEmpty()) { + // 아무 검색어 없으면 전체 반환 처리 + return cocktailRepository.findAll(); + } else { + // 이름 또는 재료 둘 중 하나라도 매칭되면 결과 반환 + return cocktailRepository.findByCocktailNameContainingIgnoreCaseOrIngredientContainingIgnoreCase(keyword, keyword); + } + } +} diff --git a/src/main/java/com/back/domain/mybar/dto/MyBarItemResponseDto.java b/src/main/java/com/back/domain/mybar/dto/MyBarItemResponseDto.java index 124af8af..ab8dc85c 100644 --- a/src/main/java/com/back/domain/mybar/dto/MyBarItemResponseDto.java +++ b/src/main/java/com/back/domain/mybar/dto/MyBarItemResponseDto.java @@ -20,7 +20,7 @@ public static MyBarItemResponseDto from(MyBar m) { .id(m.getId()) .cocktailId(m.getCocktail().getCocktailId()) .cocktailName(m.getCocktail().getCocktailName()) - .imageUrl(m.getCocktail().getImageUrl()) + .imageUrl(m.getCocktail().getCocktailImgUrl()) .createdAt(m.getCreatedAt()) .build(); } diff --git a/src/main/java/com/back/global/init/DevInitData.java b/src/main/java/com/back/global/init/DevInitData.java index e2061d1a..fd7e71c4 100644 --- a/src/main/java/com/back/global/init/DevInitData.java +++ b/src/main/java/com/back/global/init/DevInitData.java @@ -1,5 +1,9 @@ package com.back.global.init; +import com.back.domain.cocktail.entity.Cocktail; +import com.back.domain.cocktail.enums.AlcoholStrength; +import com.back.domain.cocktail.repository.CocktailRepository; +import com.back.domain.cocktail.service.CocktailService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationRunner; @@ -7,11 +11,16 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Profile; +import org.springframework.transaction.annotation.Transactional; @Configuration @Profile("dev") @RequiredArgsConstructor public class DevInitData { + + private final CocktailRepository cocktailRepository; + private final CocktailService cocktailService; + @Autowired @Lazy private DevInitData self; @@ -20,16 +29,28 @@ public class DevInitData { @Bean ApplicationRunner devInitDataApplicationRunner() { return args -> { -// self.memberInit(); - + self.cocktailInit(); // 테스트용 데이터 삽입 }; } -// @Transactional -// public void memberInit() { -// if (memberService.count() > 0) { -// return; -// } -// } + @Transactional + public void cocktailInit() { + if (cocktailRepository.count() > 0) { + return; + } + for (int i = 1; i <= 20; i++) { // 20개의 테스트 칵테일 생성 + cocktailRepository.save(Cocktail.builder() + .cocktailName("Cocktail " + i) + .cocktailImgUrl("http://example.com/img" + i + ".jpg") + .ingredient("Ingredient "+ i) + .alcoholStrength(AlcoholStrength.NON_ALCOHOLIC) + .build()); + } + System.out.println("DevInitData: 테스트 칵테일 20개 삽입"); + System.out.println(cocktailService.getCocktailById(2l)); + System.out.println(cocktailService.cocktailSearch("cocktail 3")); + System.out.println(cocktailService.cocktailSearch("Ingredient 4")); + } } +