diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandController.java b/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandController.java index 35faf05..da2e18e 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandController.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandController.java @@ -1,14 +1,12 @@ package CaffeineCoder.recipic.domain.brand.api; - import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.LinkedHashMap; - @RestController @RequestMapping("/api/brand") public class BrandController { @@ -19,51 +17,68 @@ public BrandController(BrandService brandService) { this.brandService = brandService; } - // /ingredients 엔드포인트를 GET 방식으로 변경 - @GetMapping("/ingredients") - public ResponseEntity> getIngredientsByBrandName(@RequestParam("brandName") String brandName) { - // @RequestBody 대신 @RequestParam을 사용하여 쿼리 매개변수로 brandName을 받음 - List> ingredients = brandService.getIngredientsByBrandName(brandName); + // BaseIngredient 추가 API (brandId 사용) + @PostMapping("/add-baseingredient") + public ResponseEntity> addBaseIngredientToBrand(@RequestBody Map request) { + Integer brandId = (Integer) request.get("brandId"); + String ingredientName = (String) request.get("ingredientName"); + String size = (String) request.get("size"); + + boolean success = brandService.addBaseIngredientToBrand(brandId, ingredientName, size); Map response = new LinkedHashMap<>(); - response.put("isSuccess", true); - response.put("response", ingredients); + response.put("isSuccess", success); + response.put("message", success ? "Base Ingredient added successfully" : "Failed to add Base Ingredient"); return ResponseEntity.ok(response); } + + // Ingredient 추가 API (BaseIngredient에 연결) @PostMapping("/add-ingredient") - public ResponseEntity> addIngredientToBrand(@RequestBody Map request) { - String brandName = (String) request.get("brandName"); + public ResponseEntity> addIngredient(@RequestBody Map request) { + Integer baseIngredientId = (Integer) request.get("baseIngredientId"); // BaseIngredient의 ID를 받음 String ingredientName = (String) request.get("ingredientName"); - - // quantity는 클라이언트에서 Long 타입으로 보내야함 - Long quantity = request.get("quantity") instanceof Integer - ? Long.valueOf((Integer) request.get("quantity")) - : (Long) request.get("quantity"); - + Long quantity = Long.parseLong(request.get("quantity").toString()); String unit = (String) request.get("unit"); Integer cost = (Integer) request.get("cost"); + Double calorie = Double.parseDouble(request.get("calorie").toString()); - // calorie는 Double로 변환 - Double calorie = request.get("calorie") instanceof Integer - ? Double.valueOf((Integer) request.get("calorie")) - : (Double) request.get("calorie"); - - boolean success = brandService.addIngredientToBrand(brandName, ingredientName, quantity, unit, cost, calorie); + // baseIngredientId를 추가해서 호출 + boolean success = brandService.addIngredient(baseIngredientId, ingredientName, quantity, unit, cost, calorie); Map response = new LinkedHashMap<>(); response.put("isSuccess", success); - if (success) { - response.put("message", "Ingredient added successfully."); - } else { - response.put("message", "Failed to add ingredient."); - } + response.put("message", success ? "Ingredient added successfully" : "Failed to add Ingredient"); + + return ResponseEntity.ok(response); + } + + // 브랜드 이름으로 BaseIngredient 조회 API + @GetMapping("/baseingredients") + public ResponseEntity> getBaseIngredientsByBrandName(@RequestParam("brandName") String brandName) { + List> baseIngredients = brandService.getBaseIngredientsByBrandName(brandName); + + Map response = new LinkedHashMap<>(); + response.put("isSuccess", true); + response.put("response", baseIngredients); + + return ResponseEntity.ok(response); + } + + // 특정 BaseIngredient에 매핑된 Ingredient 조회 API + @GetMapping("/baseingredient/{baseIngredientId}/ingredients") + public ResponseEntity> getIngredientsByBaseIngredientId(@PathVariable Integer baseIngredientId) { + List> ingredients = brandService.getIngredientsByBaseIngredientId(baseIngredientId); + + Map response = new LinkedHashMap<>(); + response.put("isSuccess", true); + response.put("response", ingredients); return ResponseEntity.ok(response); } - //모든 브랜드 가져오기 + // 모든 브랜드 가져오기 @GetMapping("/list") public ResponseEntity> getAllBrands() { List> brands = brandService.getAllBrands(); diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandService.java b/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandService.java index 8c2d41a..1886d3f 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandService.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/api/BrandService.java @@ -1,13 +1,7 @@ package CaffeineCoder.recipic.domain.brand.api; -import CaffeineCoder.recipic.domain.brand.dto.IngredientDTO; -import CaffeineCoder.recipic.domain.brand.domain.Brand; -import CaffeineCoder.recipic.domain.brand.domain.BrandIngredient; -import CaffeineCoder.recipic.domain.brand.domain.Ingredient; -import CaffeineCoder.recipic.domain.brand.repository.BrandIngredientRepository; -import CaffeineCoder.recipic.domain.brand.repository.BrandRepository; -import CaffeineCoder.recipic.domain.brand.repository.IngredientRepository; -import jakarta.persistence.criteria.CriteriaBuilder; +import CaffeineCoder.recipic.domain.brand.domain.*; +import CaffeineCoder.recipic.domain.brand.repository.*; import org.springframework.stereotype.Service; import java.util.LinkedHashMap; @@ -20,47 +14,38 @@ public class BrandService { private final BrandRepository brandRepository; - private final BrandIngredientRepository brandIngredientRepository; + private final BaseIngredientRepository baseIngredientRepository; private final IngredientRepository ingredientRepository; + private final BaseIngredientSizeRepository baseIngredientSizeRepository; - public BrandService(BrandRepository brandRepository, BrandIngredientRepository brandIngredientRepository, IngredientRepository ingredientRepository) { + public BrandService(BrandRepository brandRepository, BaseIngredientRepository baseIngredientRepository, + IngredientRepository ingredientRepository, BaseIngredientSizeRepository baseIngredientSizeRepository) { this.brandRepository = brandRepository; - this.brandIngredientRepository = brandIngredientRepository; + this.baseIngredientRepository = baseIngredientRepository; this.ingredientRepository = ingredientRepository; + this.baseIngredientSizeRepository = baseIngredientSizeRepository; } - public List> getIngredientsByBrandName(String brandName) { - Brand brand = brandRepository.findByBrandName(brandName) - .orElseThrow(() -> new RuntimeException("Brand not found")); + // BaseIngredient 추가 (brandId 사용) + public boolean addBaseIngredientToBrand(Integer brandId, String ingredientName, String size) { + Brand brand = brandRepository.findById(brandId) + .orElseThrow(() -> new RuntimeException("Brand not found with ID: " + brandId)); - return brandIngredientRepository.findByBrand(brand) - .stream() - .map(brandIngredient -> { - Ingredient ingredient = brandIngredient.getIngredient(); - - IngredientDTO dto = new IngredientDTO.Builder() - .ingredientId(ingredient.getIngredientId()) - .name(ingredient.getIngredientName()) - .quantity(ingredient.getQuantity()) - .unit(ingredient.getUnit()) - .cost(ingredient.getCost()) - .calorie(ingredient.getCalorie()) - .build(); - - return dto.toMap(); - }) - .collect(Collectors.toList()); - } + // BaseIngredient 생성 및 저장 + BaseIngredient baseIngredient = new BaseIngredient(ingredientName, brand); + baseIngredientRepository.save(baseIngredient); - public boolean addIngredientToBrand(String brandName, String ingredientName, Long quantity, String unit, Integer cost, Double calorie) { + // BaseIngredientSize도 생성 및 저장 + BaseIngredientSize baseIngredientSize = new BaseIngredientSize(size, baseIngredient); + baseIngredientSizeRepository.save(baseIngredientSize); - Optional optionalBrand = brandRepository.findByBrandName(brandName); - if (optionalBrand.isEmpty()) { - return false; - } - Brand brand = optionalBrand.get(); + return true; + } - // 새로운 Ingredient 객체 생성 + // Ingredient 추가 (BaseIngredient와 연결) + public boolean addIngredient(Integer baseIngredientId, String ingredientName, Long quantity, String unit, Integer cost, Double calorie) { + BaseIngredient baseIngredient = baseIngredientRepository.findById(baseIngredientId) + .orElseThrow(() -> new RuntimeException("BaseIngredient not found with ID: " + baseIngredientId)); Ingredient ingredient = Ingredient.builder() .ingredientName(ingredientName) @@ -68,21 +53,50 @@ public boolean addIngredientToBrand(String brandName, String ingredientName, Lon .unit(unit) .cost(cost) .calorie(calorie) + .baseIngredient(baseIngredient) .build(); - // Ingredient 저장 ingredientRepository.save(ingredient); + return true; + } - // BrandIngredient 객체 생성 - BrandIngredient brandIngredient = new BrandIngredient(); - brandIngredient.setIngredient(ingredient); - brandIngredient.setBrand(brand); - brandIngredientRepository.save(brandIngredient); + // 브랜드 이름으로 BaseIngredient 가져오기 + public List> getBaseIngredientsByBrandName(String brandName) { + Brand brand = brandRepository.findByBrandName(brandName) + .orElseThrow(() -> new RuntimeException("Brand not found")); - return true; + return baseIngredientRepository.findByBrand(brand) + .stream() + .map(baseIngredient -> { + Map baseIngredientMap = new LinkedHashMap<>(); + baseIngredientMap.put("ingredientId", baseIngredient.getBaseIngredientId()); + baseIngredientMap.put("name", baseIngredient.getIngredientName()); + return baseIngredientMap; + }) + .collect(Collectors.toList()); } - //모든 브랜드 가져오기 + // BaseIngredient에 매핑된 Ingredient 조회 + public List> getIngredientsByBaseIngredientId(Integer baseIngredientId) { + BaseIngredient baseIngredient = baseIngredientRepository.findById(baseIngredientId) + .orElseThrow(() -> new RuntimeException("BaseIngredient not found with ID: " + baseIngredientId)); + + // BaseIngredient에 매핑된 Ingredient들을 가져와 Map으로 변환 + return baseIngredient.getIngredients().stream() + .map(ingredient -> { + Map ingredientMap = new LinkedHashMap<>(); + ingredientMap.put("ingredientId", ingredient.getIngredientId()); + ingredientMap.put("name", ingredient.getIngredientName()); + ingredientMap.put("quantity", ingredient.getQuantity()); + ingredientMap.put("unit", ingredient.getUnit()); + ingredientMap.put("cost", ingredient.getCost()); + ingredientMap.put("calorie", ingredient.getCalorie()); + return ingredientMap; + }) + .collect(Collectors.toList()); + } + + // 모든 브랜드 가져오기 public List> getAllBrands() { return brandRepository.findAll().stream() .map(brand -> { @@ -93,8 +107,4 @@ public List> getAllBrands() { }) .collect(Collectors.toList()); } - - public String getBrandNameByBrandId(Integer brandId) { - return brandRepository.findBrandNameByBrandId(brandId); - } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredient.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredient.java new file mode 100644 index 0000000..a880a26 --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredient.java @@ -0,0 +1,37 @@ +package CaffeineCoder.recipic.domain.brand.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Entity +@Getter +@NoArgsConstructor +public class BaseIngredient { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "baseingredient_id") + private Integer baseIngredientId; + + @Column(name = "ingredient_name", nullable = false) + private String ingredientName; + + @OneToMany(mappedBy = "baseIngredient", cascade = CascadeType.ALL, orphanRemoval = true) + private List baseIngredientSizes; + + @ManyToOne + @JoinColumn(name = "brand_id", nullable = false) + private Brand brand; + + @OneToMany(mappedBy = "baseIngredient", cascade = CascadeType.ALL, orphanRemoval = true) + private List ingredients; // Ingredient와 연결 + + public BaseIngredient(String ingredientName, Brand brand) { + this.ingredientName = ingredientName; + this.brand = brand; + } +} + diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredientSize.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredientSize.java new file mode 100644 index 0000000..a7a423a --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BaseIngredientSize.java @@ -0,0 +1,30 @@ +package CaffeineCoder.recipic.domain.brand.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor +public class BaseIngredientSize { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "baseingredient_size_id") + private Integer baseIngredientSizeId; + + @Column(name = "size", nullable = false) + private String size; + + @ManyToOne + @JoinColumn(name = "baseingredient_id", nullable = false) + private BaseIngredient baseIngredient; + + public BaseIngredientSize(String size, BaseIngredient baseIngredient) { + this.size = size; + this.baseIngredient = baseIngredient; + } +} + + diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Brand.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Brand.java index ddb04cb..8604d4a 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Brand.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Brand.java @@ -16,13 +16,14 @@ public class Brand { @Column(name = "brand_id") private Integer brandId; - @Column(name = "brand_name", nullable = false) + @Column(name = "brand_name", nullable = false, unique = true) private String brandName; @OneToMany(mappedBy = "brand", cascade = CascadeType.ALL, orphanRemoval = true) - private List brandIngredients; + private List baseIngredients; - public Integer getBrandId() { - return brandId; + public Brand(Integer brandId, String brandName) { + this.brandId = brandId; + this.brandName = brandName; } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredient.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredient.java index d73c1b4..e012c6c 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredient.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredient.java @@ -18,21 +18,13 @@ public class BrandIngredient { private Brand brand; @ManyToOne - @MapsId("ingredientId") - @JoinColumn(name = "ingredient_id") - private Ingredient ingredient; + @MapsId("baseIngredientId") + @JoinColumn(name = "baseingredient_id") + private BaseIngredient baseIngredient; - public void setIngredient(Ingredient ingredient) { - this.ingredient = ingredient; - if (this.brand != null) { - this.id = new BrandIngredientId(this.brand.getBrandId(), ingredient.getIngredientId()); - } - } - - public void setBrand(Brand brand) { + public BrandIngredient(Brand brand, BaseIngredient baseIngredient) { this.brand = brand; - if (this.ingredient != null) { - this.id = new BrandIngredientId(brand.getBrandId(), this.ingredient.getIngredientId()); - } + this.baseIngredient = baseIngredient; + this.id = new BrandIngredientId(brand.getBrandId(), baseIngredient.getBaseIngredientId()); } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredientId.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredientId.java index 3beb5df..25086c8 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredientId.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/BrandIngredientId.java @@ -16,12 +16,12 @@ public class BrandIngredientId implements Serializable { @Column(name = "brand_id") private Integer brandId; - @Column(name = "ingredient_id") - private Integer ingredientId; + @Column(name = "baseingredient_id") + private Integer baseIngredientId; - public BrandIngredientId(Integer brandId, Integer ingredientId) { + public BrandIngredientId(Integer brandId, Integer baseIngredientId) { this.brandId = brandId; - this.ingredientId = ingredientId; + this.baseIngredientId = baseIngredientId; } @Override @@ -30,11 +30,11 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; BrandIngredientId that = (BrandIngredientId) o; return Objects.equals(brandId, that.brandId) && - Objects.equals(ingredientId, that.ingredientId); + Objects.equals(baseIngredientId, that.baseIngredientId); } @Override public int hashCode() { - return Objects.hash(brandId, ingredientId); + return Objects.hash(brandId, baseIngredientId); } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Ingredient.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Ingredient.java index 0366ae6..aae165a 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Ingredient.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/Ingredient.java @@ -3,9 +3,11 @@ import jakarta.persistence.*; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; @Entity @Getter +@NoArgsConstructor public class Ingredient { @Id @@ -13,31 +15,33 @@ public class Ingredient { @Column(name = "ingredient_id") private Integer ingredientId; - @Column(name = "ingredient_name") - private String ingredientName; // 재료 이름 + @Column(name = "ingredient_name", nullable = false) + private String ingredientName; - @Column(name = "quantity") - private Long quantity; // 양 + @Column(name = "quantity", nullable = false) + private Long quantity; - @Column(name = "unit") - private String unit; // 단위 + @Column(name = "unit", nullable = false) + private String unit; @Column(name = "cost") - private Integer cost; // 비용 + private Integer cost; @Column(name = "calorie") - private Double calorie; // 칼로리 + private Double calorie; + + // BaseIngredient와 관계 설정 (ManyToOne) + @ManyToOne + @JoinColumn(name = "baseingredient_id", nullable = false) + private BaseIngredient baseIngredient; @Builder - public Ingredient(String ingredientName, Long quantity, String unit, Integer cost, Double calorie) { + public Ingredient(String ingredientName, Long quantity, String unit, Integer cost, Double calorie, BaseIngredient baseIngredient) { this.ingredientName = ingredientName; this.quantity = quantity; this.unit = unit; this.cost = cost; this.calorie = calorie; - } - - // 기본 생성자 추가 - protected Ingredient() { + this.baseIngredient = baseIngredient; } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/domain/RecipeBaseIngredient.java b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/RecipeBaseIngredient.java new file mode 100644 index 0000000..706a58e --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/domain/RecipeBaseIngredient.java @@ -0,0 +1,38 @@ +package CaffeineCoder.recipic.domain.brand.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import CaffeineCoder.recipic.domain.recipe.domain.Recipe; + +@Entity +@Getter +@NoArgsConstructor +public class RecipeBaseIngredient { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "recipe_baseingredient_id") + private Integer recipeBaseIngredientId; + + @ManyToOne + @JoinColumn(name = "recipe_id", nullable = false) + private Recipe recipe; + + @ManyToOne + @JoinColumn(name = "baseingredient_id", nullable = false) + private BaseIngredient baseIngredient; + + public RecipeBaseIngredient(Recipe recipe, BaseIngredient baseIngredient) { + this.recipe = recipe; + this.baseIngredient = baseIngredient; + } + + public void setRecipe(Recipe recipe) { + this.recipe = recipe; + } + + public void setBaseIngredient(BaseIngredient baseIngredient) { + this.baseIngredient = baseIngredient; + } +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientRepository.java b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientRepository.java new file mode 100644 index 0000000..ff13e4d --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientRepository.java @@ -0,0 +1,17 @@ +package CaffeineCoder.recipic.domain.brand.repository; + +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredient; +import CaffeineCoder.recipic.domain.brand.domain.Brand; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface BaseIngredientRepository extends JpaRepository { + + // BaseIngredient 이름으로 찾기 + Optional findByIngredientName(String ingredientName); + List findByBrand(Brand brand); +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientSizeRepository.java b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientSizeRepository.java new file mode 100644 index 0000000..3d5da99 --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BaseIngredientSizeRepository.java @@ -0,0 +1,9 @@ +package CaffeineCoder.recipic.domain.brand.repository; + +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredientSize; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface BaseIngredientSizeRepository extends JpaRepository { +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandIngredientRepository.java b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandIngredientRepository.java index c7fac28..1b2860d 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandIngredientRepository.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandIngredientRepository.java @@ -12,4 +12,3 @@ public interface BrandIngredientRepository extends JpaRepository { List findByBrand(Brand brand); } - diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandRepository.java b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandRepository.java index 7bb2c4c..94e6c96 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandRepository.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/BrandRepository.java @@ -1,16 +1,18 @@ package CaffeineCoder.recipic.domain.brand.repository; +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredient; import CaffeineCoder.recipic.domain.brand.domain.Brand; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; - @Repository -public interface BrandRepository extends JpaRepository { +public interface BrandRepository extends JpaRepository { + Optional findByBrandName(String brandName); @Query("SELECT b.brandId FROM Brand b WHERE b.brandName = :name") @@ -19,4 +21,7 @@ public interface BrandRepository extends JpaRepository { @Query("SELECT b.brandName FROM Brand b WHERE b.brandId = :brandId") String findBrandNameByBrandId(@Param("brandId") Integer brandId); + @Query("SELECT bi FROM BaseIngredient bi JOIN bi.brand b WHERE b.brandName = :brandName") + List findBaseIngredientsByBrandName(@Param("brandName") String brandName); + } diff --git a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/IngredientRepository.java b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/IngredientRepository.java index befa044..08bd95b 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/brand/repository/IngredientRepository.java +++ b/src/main/java/CaffeineCoder/recipic/domain/brand/repository/IngredientRepository.java @@ -2,22 +2,16 @@ import CaffeineCoder.recipic.domain.brand.domain.Ingredient; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; -import org.springframework.transaction.annotation.Transactional; import java.util.Optional; @Repository public interface IngredientRepository extends JpaRepository { - @Query("SELECT i.ingredientId FROM Ingredient i WHERE i.ingredientName = :name") - Optional findByName(@Param("name") String name); - - @Modifying - @Transactional - @Query("DELETE FROM RecipeIngredient ri WHERE ri.recipe.recipeId = :recipeId") - void deleteByRecipeId(@Param("recipeId") Integer recipeId); + // Ingredient 이름으로 찾기 + @Query("SELECT i FROM Ingredient i WHERE i.ingredientName = :name") + Optional findByIngredientName(@Param("name") String name); } diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/api/RecipeController.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/api/RecipeController.java index 4586b34..94b7f6c 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/api/RecipeController.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/api/RecipeController.java @@ -21,7 +21,6 @@ public class RecipeController { private final RecipeService recipeService; public RecipeController(RecipeService recipeService) { - this.recipeService = recipeService; } @@ -30,14 +29,13 @@ public ResponseEntity> registerRecipe( @RequestPart(value="recipe") RecipeRequestDto recipeRequestDto, @RequestPart(value="thumbnailImage") MultipartFile thumbnailImage ) { - recipeService.registerRecipe(recipeRequestDto,thumbnailImage); + recipeService.registerRecipe(recipeRequestDto, thumbnailImage); return ResponseEntity.ok(Map.of("isSuccess", true)); } - @DeleteMapping("/remove") - public ResponseEntity> deleteRecipe(@RequestBody Map request) { - Integer recipeId = request.get("recipeId"); + @GetMapping("/remove") + public ResponseEntity> deleteRecipe(@RequestParam Integer recipeId) { boolean isSuccess = recipeService.deleteRecipe(recipeId); Map response = new HashMap<>(); @@ -69,7 +67,4 @@ public ApiResponse getScraps( @RequestParam(value = "size", defaultValue = "10") int size) { return ApiUtils.success(recipeService.getQueriedRecipes(keyword, page, size)); } - - - -} \ No newline at end of file +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeRankService.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeRankService.java index 4ca36cc..53307ed 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeRankService.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeRankService.java @@ -7,7 +7,6 @@ import CaffeineCoder.recipic.domain.recipe.dto.RecipeResponseDto; import CaffeineCoder.recipic.domain.scrap.dao.ScrapRepository; import CaffeineCoder.recipic.domain.user.application.UserService; -import CaffeineCoder.recipic.domain.user.dao.UserRepository; import CaffeineCoder.recipic.domain.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.PageRequest; @@ -23,28 +22,21 @@ public class RecipeRankService { private final ScrapRepository scrapRepository; private final CommentRepository commentRepository; private final UserService userService; - private final BrandService brandService; - public List getTop5NormalRecipes() { - List topRecipeIds = scrapRepository.findTop5NormalRecipesByScrapCount(PageRequest.of(0, 5)); List topRecipes = new ArrayList<>(); - - for(int i=0; i new RuntimeException("Recipe not found")); - int scrapCount = scrapRepository.countByRecipeId(recipe.getRecipeId()); - int commentCount = commentRepository.countByRecipeId(recipe.getRecipeId()); - + for (int recipeId : topRecipeIds) { + Recipe recipe = recipeRepository.findById(recipeId).orElseThrow(() -> new RuntimeException("Recipe not found")); User user = userService.findUser(recipe.getUserId()); - String brandName = brandService.getBrandNameByBrandId(recipe.getBrandId()); + int scrapCount = scrapRepository.countByRecipeId(recipeId); + String brandName = recipe.getBrandName(); - topRecipes.add(RecipeResponseDto.fromEntity(recipe,user,brandName, scrapCount,commentCount)); + topRecipes.add(RecipeResponseDto.fromEntity(recipe, user, brandName, scrapCount, 0)); } - return topRecipes; } @@ -54,18 +46,17 @@ public List getTop5CelebrityRecipes() { List topRecipes = new ArrayList<>(); - for(int i=0; i new RuntimeException("Recipe not found")); + for (int recipeId : topRecipeIds) { + Recipe recipe = recipeRepository.findById(recipeId).orElseThrow(() -> new RuntimeException("Recipe not found")); int scrapCount = scrapRepository.countByRecipeId(recipe.getRecipeId()); int commentCount = commentRepository.countByRecipeId(recipe.getRecipeId()); User user = userService.findUser(recipe.getUserId()); - String brandName = brandService.getBrandNameByBrandId(recipe.getBrandId()); + String brandName = recipe.getBrandName(); - topRecipes.add(RecipeResponseDto.fromEntity(recipe,user,brandName, scrapCount,commentCount)); + topRecipes.add(RecipeResponseDto.fromEntity(recipe, user, brandName, scrapCount, commentCount)); } return topRecipes; } - } diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeService.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeService.java index f2b832f..a124991 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeService.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/application/RecipeService.java @@ -1,18 +1,17 @@ package CaffeineCoder.recipic.domain.recipe.application; import CaffeineCoder.recipic.domain.brand.api.BrandService; +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredient; +import CaffeineCoder.recipic.domain.brand.domain.Brand; +import CaffeineCoder.recipic.domain.brand.domain.Ingredient; +import CaffeineCoder.recipic.domain.brand.repository.BaseIngredientRepository; import CaffeineCoder.recipic.domain.brand.repository.BrandRepository; import CaffeineCoder.recipic.domain.brand.repository.IngredientRepository; -import CaffeineCoder.recipic.domain.comment.dao.CommentLikeRepository; import CaffeineCoder.recipic.domain.comment.dao.CommentRepository; -import CaffeineCoder.recipic.domain.comment.domain.Comment; -import CaffeineCoder.recipic.domain.comment.dto.CommentDto; import CaffeineCoder.recipic.domain.jwtSecurity.util.SecurityUtil; import CaffeineCoder.recipic.domain.recipe.dao.RecipeIngredientRepository; import CaffeineCoder.recipic.domain.recipe.dao.RecipeRepository; import CaffeineCoder.recipic.domain.recipe.domain.Recipe; -import CaffeineCoder.recipic.domain.brand.domain.Ingredient; - import CaffeineCoder.recipic.domain.recipe.domain.RecipeIngredient; import CaffeineCoder.recipic.domain.recipe.domain.RecipeIngredientId; import CaffeineCoder.recipic.domain.recipe.dto.*; @@ -21,12 +20,10 @@ import CaffeineCoder.recipic.domain.user.application.UserService; import CaffeineCoder.recipic.domain.user.dao.UserRepository; import CaffeineCoder.recipic.domain.user.domain.User; -import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; @@ -37,22 +34,21 @@ import java.io.IOException; import java.sql.Timestamp; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; - @Service @RequiredArgsConstructor public class RecipeService { + private final RecipeRepository recipeRepository; private final RecipeIngredientRepository recipeIngredientRepository; private final BrandRepository brandRepository; private final IngredientRepository ingredientRepository; + private final BaseIngredientRepository baseIngredientRepository; private final ScrapRepository scrapRepository; private final CommentRepository commentRepository; - private final CommentLikeRepository commentLikeRepository; private final UserRepository userRepository; private final BrandService brandService; private final ScrapService scrapService; @@ -62,16 +58,14 @@ public class RecipeService { @Value("${spring.cloud.gcp.storage.bucket}") private String bucketName; + @Transactional public void registerRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thumbnailImage) { - - Long userId = SecurityUtil.getCurrentMemberId(); - // brandName으로 brandId 찾기 - Integer brandId = brandRepository.findBrandIdByBrandName(recipeRequestDto.getBrandName()) - .orElseThrow(() -> new RuntimeException("Brand not found: " + recipeRequestDto.getBrandName())); + Brand brand = brandRepository.findById(recipeRequestDto.getBrandId()) + .orElseThrow(() -> new RuntimeException("Brand not found")); - String uuid = null; // 유저가 이미지를 없애도록 수정한 경우 + String uuid = null; try { if (!thumbnailImage.isEmpty()) { @@ -81,11 +75,9 @@ public void registerRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thum e.printStackTrace(); } - - Recipe recipe = Recipe.builder() .userId(userId) - .brandId(brandId) // brandName 대신 brandId 설정 + .brand(brand) .title(recipeRequestDto.getTitle()) .description(recipeRequestDto.getDescription()) .imageUrl(uuid) @@ -98,20 +90,34 @@ public void registerRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thum List recipeIngredients = recipeRequestDto.getSelectedRecipes().stream() .map(selectedRecipe -> { - // ingredientName으로 ingredientId 찾기 - Integer ingredientId = ingredientRepository.findByName(selectedRecipe.getIngredientName()) - .orElseThrow(() -> new RuntimeException("Ingredient not found: " + selectedRecipe.getIngredientName())); - - RecipeIngredientId recipeIngredientId = new RecipeIngredientId( - ingredientId, - savedRecipe.getRecipeId() - ); - - return RecipeIngredient.builder() + RecipeIngredient.RecipeIngredientBuilder recipeIngredientBuilder = RecipeIngredient.builder(); + RecipeIngredientId recipeIngredientId; + + if (selectedRecipe.isBaseIngredient()) { + BaseIngredient baseIngredient = baseIngredientRepository.findByIngredientName(selectedRecipe.getIngredientName()) + .orElseThrow(() -> new RuntimeException("Base Ingredient not found: " + selectedRecipe.getIngredientName())); + + recipeIngredientId = new RecipeIngredientId( + savedRecipe.getRecipeId(), + null, + baseIngredient.getBaseIngredientId() + ); + recipeIngredientBuilder.baseIngredient(baseIngredient); + } else { + Ingredient ingredient = ingredientRepository.findByIngredientName(selectedRecipe.getIngredientName()) + .orElseThrow(() -> new RuntimeException("Ingredient not found: " + selectedRecipe.getIngredientName())); + + recipeIngredientId = new RecipeIngredientId( + savedRecipe.getRecipeId(), + ingredient.getIngredientId(), + null + ); + recipeIngredientBuilder.ingredient(ingredient); + } + + return recipeIngredientBuilder .id(recipeIngredientId) .recipe(savedRecipe) - .ingredient(ingredientRepository.findById(ingredientId) - .orElseThrow(() -> new RuntimeException("Ingredient not found: " + ingredientId))) .count(selectedRecipe.getCount()) .build(); }) @@ -120,59 +126,50 @@ public void registerRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thum recipeIngredientRepository.saveAll(recipeIngredients); } - public RecipeDetailResponseDto getRecipeDetail(Integer recipeId) { Recipe recipe = recipeRepository.findById(recipeId) .orElseThrow(() -> new RuntimeException("Recipe not found")); boolean isScrapped = false; - - // 현재 인증된 사용자가 있는지 확인 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.isAuthenticated() && !(authentication instanceof AnonymousAuthenticationToken)) { - Long currentMemberId = SecurityUtil.getCurrentMemberId(); - if (currentMemberId != null) { isScrapped = scrapService.isScrapped(currentMemberId, recipeId); } } - // Fetch scrap count int scrapCount = scrapRepository.countByRecipeId(recipeId); List ingredients = recipeIngredientRepository.findByRecipeId(recipeId); - List includeIngredients = ingredients.stream() .map(ingredient -> { - // Get the ingredientId - Integer ingredientId = ingredient.getIngredient().getIngredientId(); - - // Find Ingredient using ingredientId from the repository - Ingredient foundIngredient = ingredientRepository.findById(ingredientId) - .orElse(null); // 해당 재료가 없을 경우 null 처리 - - // Build IncludeIngredientDto with Ingredient object and count - return IncludeIngredientDto.builder() - .ingredient(foundIngredient) // Ingredient 객체 자체를 포함 - .count(ingredient.getCount()) // 해당 재료의 수량 포함 - .build(); + if (ingredient.getIngredient() != null) { + Ingredient foundIngredient = ingredient.getIngredient(); + return IncludeIngredientDto.builder() + .ingredient(foundIngredient) + .count(ingredient.getCount()) + .build(); + } else { + BaseIngredient foundBaseIngredient = ingredient.getBaseIngredient(); + return IncludeIngredientDto.builder() + .baseIngredient(foundBaseIngredient) + .count(ingredient.getCount()) + .build(); + } }) .collect(Collectors.toList()); + User user = userRepository.findById(recipe.getUserId()) + .orElseThrow(() -> new RuntimeException("User not found")); - - Optional OptionalUser = userRepository.findById(recipe.getUserId()); - User user = OptionalUser.orElseThrow(() -> new RuntimeException("User not found")); - - String brandName = brandService.getBrandNameByBrandId(recipe.getBrandId()); - + String brandName = recipe.getBrandName(); return RecipeDetailResponseDto.builder() .recipeId(recipe.getRecipeId()) .userNickName(user.getNickName()) - .userProfileImageUrl(user.getProfileImageUrl()) // Set the profile image URL here + .userProfileImageUrl(user.getProfileImageUrl()) .brandName(brandName) .title(recipe.getTitle()) .description(recipe.getDescription()) @@ -186,167 +183,41 @@ public RecipeDetailResponseDto getRecipeDetail(Integer recipeId) { .build(); } - - - - public List getQueriedRecipes(String keyword, int page, int size) { - if(keyword.equals("-1")){ - return getAllRecipes(page, size); - } - - Optional brandId= brandRepository.findBrandIdByBrandName(keyword); - - if(brandId.isEmpty()){ - return Collections.emptyList(); - } - - Page recipeDtoPage = recipeRepository.findRecipesByBrandId(brandId.get(), PageRequest.of(page, size,Sort.by(Sort.Direction.DESC, "createdAt"))); - - List recipeDtos = recipeDtoPage.getContent(); - - List recipeResponseDtos = recipeDtos.stream() - .map(this::getRecipeDtoToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - - } - - - public List getAllRecipes(int page, int size) { - - Page recipePage = recipeRepository.findAll(PageRequest.of(page, size,Sort.by(Sort.Direction.DESC, "createdAt"))); - - List recipes = recipePage.getContent(); - - - - List recipeResponseDtos = recipes.stream() - .map(this::getRecipeToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - } - - public List getUserQueriedRecipes(String keyword, int page, int size, Long userId) { - if(keyword.equals("-1")){ - return getAllUserRecipes(page, size, userId); - } - - Optional brandId= brandRepository.findBrandIdByBrandName(keyword); - - if(brandId.isEmpty()){ - return Collections.emptyList(); - } - - Page recipeDtoPage = recipeRepository.findRecipesByBrandIdAndUserId(brandId.get(), userId, PageRequest.of(page, size,Sort.by(Sort.Direction.DESC, "createdAt"))); - - List recipeDtos = recipeDtoPage.getContent(); - - List recipeResponseDtos = recipeDtos.stream() - .map(this::getRecipeDtoToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - - } - - public List getAllUserRecipes(int page, int size, Long userId) { - Page recipeDtoPage = recipeRepository.findRecipesByUserId(userId, PageRequest.of(page, size,Sort.by(Sort.Direction.DESC, "createdAt"))); - - List recipeDtos = recipeDtoPage.getContent(); - - List recipeResponseDtos = recipeDtos.stream() - .map(this::getRecipeDtoToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - } - - public List getUserQueriedScrapedRecipes(String keyword, int page, int size, List recipeIds) { - if(keyword.equals("-1")){ - return getUserAllScrapedRecipes(page, size, recipeIds); - } - - Optional brandId= brandRepository.findBrandIdByBrandName(keyword); - - if(brandId.isEmpty()){ - return Collections.emptyList(); - } - - Pageable pageable = PageRequest.of(page, size); - Page recipeDtoPages = recipeRepository.findRecipesByBrandIdAndRecipeIds( - brandId.get(), recipeIds, pageable); - - List recipeDtos = recipeDtoPages.getContent(); - - List recipeResponseDtos = recipeDtos.stream() - .map(this::getRecipeDtoToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - } - - public List getUserAllScrapedRecipes(int page, int size, List recipeIds) { - Pageable pageable = PageRequest.of(page, size); - Page recipeDtoPages = recipeRepository.findRecipesByRecipeIds(recipeIds, pageable); - - List recipeDtos = recipeDtoPages.getContent(); - - List recipeResponseDtos = recipeDtos.stream() - .map(this::getRecipeDtoToRecipeResponseDto) - .collect(Collectors.toList()); - - return recipeResponseDtos; - } - - @Transactional public boolean deleteRecipe(Integer recipeId) { - // 현재 인증된 사용자의 ID Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - Long userId = Long.parseLong(authentication.getName()); + Long userId = SecurityUtil.getCurrentMemberId(); - // 해당 ID의 레시피 찾기 Recipe recipe = recipeRepository.findById(recipeId) .orElseThrow(() -> new IllegalArgumentException("Recipe not found")); - // 레시피 작성자와 현재 사용자가 같은지 확인 if (!recipe.getUserId().equals(userId)) { throw new IllegalArgumentException("You are not authorized to delete this recipe"); } - // 레시피와 관련된 스크랩과 댓글 삭제 scrapRepository.deleteByRecipeId(recipeId); commentRepository.deleteByRecipeId(recipeId); - // 레시피 삭제 recipeRepository.deleteById(recipeId); return true; } - @Transactional public boolean updateRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thumbnailImage) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - Long userId = Long.parseLong(authentication.getName()); + Long userId = SecurityUtil.getCurrentMemberId(); - // 수정할 레시피를 찾기 - Recipe recipe = recipeRepository.findById(Integer.valueOf(recipeRequestDto.getRecipeId())) + Recipe recipe = recipeRepository.findById(recipeRequestDto.getRecipeId()) .orElseThrow(() -> new IllegalArgumentException("Recipe not found")); - // 레시피 작성자와 현재 사용자가 같은지 확인 if (!recipe.getUserId().equals(userId)) { throw new IllegalArgumentException("You are not authorized to update this recipe"); } - // brandName으로 brandId 찾기 - Integer brandId = brandRepository.findBrandIdByBrandName(recipeRequestDto.getBrandName()) - .orElseThrow(() -> new RuntimeException("Brand not found: " + recipeRequestDto.getBrandName())); + Brand brand = brandRepository.findById(recipeRequestDto.getBrandId()) + .orElseThrow(() -> new IllegalArgumentException("Brand not found")); - // 레시피 수정 - - String uuid = null; // 유저가 이미지를 없애도록 수정한 경우 + String uuid = null; try { if (!thumbnailImage.isEmpty()) { @@ -356,7 +227,7 @@ public boolean updateRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thu e.printStackTrace(); } - if(uuid == null){ + if (uuid == null) { uuid = recipe.getImageUrl(); } @@ -364,34 +235,47 @@ public boolean updateRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thu recipeRequestDto.getTitle(), recipeRequestDto.getDescription(), uuid, - brandId, // brandId 설정 + brand, recipeRequestDto.getIsCelebrity() ); - // 레시피 저장 recipeRepository.save(recipe); - // 기존 재료 삭제 후 재추가 recipeIngredientRepository.deleteByRecipeId(recipe.getRecipeId()); List recipeIngredients = recipeRequestDto.getSelectedRecipes().stream() .map(selectedRecipe -> { - // ingredientName으로 ingredientId 찾기 - Integer ingredientId = ingredientRepository.findByName(selectedRecipe.getIngredientName()) - .orElseThrow(() -> new RuntimeException("Ingredient not found: " + selectedRecipe.getIngredientName())); - - RecipeIngredientId recipeIngredientId = new RecipeIngredientId( - ingredientId, - recipe.getRecipeId() - ); - - return RecipeIngredient.builder() - .id(recipeIngredientId) - .recipe(recipe) - .ingredient(ingredientRepository.findById(ingredientId) - .orElseThrow(() -> new RuntimeException("Ingredient not found: " + ingredientId))) - .count(selectedRecipe.getCount()) - .build(); + RecipeIngredientId recipeIngredientId; + + if (selectedRecipe.isBaseIngredient()) { + BaseIngredient baseIngredient = baseIngredientRepository.findByIngredientName(selectedRecipe.getIngredientName()) + .orElseThrow(() -> new RuntimeException("Base Ingredient not found: " + selectedRecipe.getIngredientName())); + recipeIngredientId = new RecipeIngredientId( + recipe.getRecipeId(), + null, + baseIngredient.getBaseIngredientId() + ); + return RecipeIngredient.builder() + .id(recipeIngredientId) + .recipe(recipe) + .baseIngredient(baseIngredient) + .count(selectedRecipe.getCount()) + .build(); + } else { + Ingredient ingredient = ingredientRepository.findByIngredientName(selectedRecipe.getIngredientName()) + .orElseThrow(() -> new RuntimeException("Ingredient not found: " + selectedRecipe.getIngredientName())); + recipeIngredientId = new RecipeIngredientId( + recipe.getRecipeId(), + ingredient.getIngredientId(), + null + ); + return RecipeIngredient.builder() + .id(recipeIngredientId) + .recipe(recipe) + .ingredient(ingredient) + .count(selectedRecipe.getCount()) + .build(); + } }) .collect(Collectors.toList()); @@ -399,28 +283,83 @@ public boolean updateRecipe(RecipeRequestDto recipeRequestDto, MultipartFile thu return true; } + + public List getQueriedRecipes(String keyword, int page, int size) { + if (keyword.equals("-1")) { + return getAllRecipes(page, size); + } + + Page recipeDtoPage = recipeRepository.findRecipesByBrandName(keyword, PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"))); + List recipeDtos = recipeDtoPage.getContent(); + + return recipeDtos.stream() + .map(this::getRecipeDtoToRecipeResponseDto) + .collect(Collectors.toList()); + } + + @Transactional(readOnly = true) + public List getUserQueriedRecipes(String keyword, int page, int size, Long userId) { + if (keyword.equals("-1")) { + return getAllUserRecipes(page, size, userId); + } + + Page recipeDtoPage = recipeRepository.findRecipesByBrandNameAndUserId(keyword, userId, PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"))); + return recipeDtoPage.getContent().stream() + .map(this::getRecipeDtoToRecipeResponseDto) + .collect(Collectors.toList()); + } + + @Transactional(readOnly = true) + public List getUserQueriedScrapedRecipes(String keyword, int page, int size, List recipeIds) { + if (keyword.equals("-1")) { + return getUserAllScrapedRecipes(page, size, recipeIds); + } + + Page recipeDtoPage = recipeRepository.findRecipesByBrandNameAndRecipeIds(keyword, recipeIds, PageRequest.of(page, size)); + return recipeDtoPage.getContent().stream() + .map(this::getRecipeDtoToRecipeResponseDto) + .collect(Collectors.toList()); + } + + private List getAllRecipes(int page, int size) { + Page recipePage = recipeRepository.findAll(PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"))); + return recipePage.getContent().stream() + .map(this::getRecipeToRecipeResponseDto) + .collect(Collectors.toList()); + } + + private List getAllUserRecipes(int page, int size, Long userId) { + Page recipeDtoPage = recipeRepository.findRecipesByUserId(userId, PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "createdAt"))); + return recipeDtoPage.getContent().stream() + .map(this::getRecipeDtoToRecipeResponseDto) + .collect(Collectors.toList()); + } + + private List getUserAllScrapedRecipes(int page, int size, List recipeIds) { + Page recipeDtoPages = recipeRepository.findRecipesByRecipeIds(recipeIds, PageRequest.of(page, size)); + List recipeDtos = recipeDtoPages.getContent(); + + return recipeDtos.stream() + .map(this::getRecipeDtoToRecipeResponseDto) + .collect(Collectors.toList()); + } + private RecipeResponseDto getRecipeDtoToRecipeResponseDto(RecipeDto recipeDto) { int scrapCount = scrapRepository.countByRecipeId(recipeDto.recipeId()); int commentCount = commentRepository.countByRecipeId(recipeDto.recipeId()); User user = userService.findUser(recipeDto.userId()); - - String brandName = brandService.getBrandNameByBrandId(recipeDto.brandId()); + String brandName = recipeDto.brandName(); return RecipeResponseDto.fromDto(recipeDto, user, brandName, scrapCount, commentCount); } private RecipeResponseDto getRecipeToRecipeResponseDto(Recipe recipe) { RecipeDto recipeDto = RecipeDto.fromEntity(recipe); - int scrapCount = scrapRepository.countByRecipeId(recipeDto.recipeId()); int commentCount = commentRepository.countByRecipeId(recipeDto.recipeId()); User user = userService.findUser(recipeDto.userId()); - - String brandName = brandService.getBrandNameByBrandId(recipeDto.brandId()); + String brandName = recipeDto.brandName(); return RecipeResponseDto.fromDto(recipeDto, user, brandName, scrapCount, commentCount); } - - - } diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeBaseIngredientRepository.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeBaseIngredientRepository.java new file mode 100644 index 0000000..b8b8d35 --- /dev/null +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeBaseIngredientRepository.java @@ -0,0 +1,9 @@ +package CaffeineCoder.recipic.domain.recipe.dao; + +import CaffeineCoder.recipic.domain.brand.domain.RecipeBaseIngredient; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface RecipeBaseIngredientRepository extends JpaRepository { +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeIngredientRepository.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeIngredientRepository.java index 2a4ffe5..1dda47b 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeIngredientRepository.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeIngredientRepository.java @@ -14,6 +14,7 @@ @Repository public interface RecipeIngredientRepository extends JpaRepository { + @Query("SELECT ri FROM RecipeIngredient ri WHERE ri.recipe.recipeId = :recipeId") List findByRecipeId(@Param("recipeId") Integer recipeId); diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeRepository.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeRepository.java index b5bccbd..3f9c9f2 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeRepository.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dao/RecipeRepository.java @@ -2,7 +2,6 @@ import CaffeineCoder.recipic.domain.recipe.domain.Recipe; import CaffeineCoder.recipic.domain.recipe.dto.RecipeDto; -import CaffeineCoder.recipic.domain.recipe.dto.RecipeResponseDto; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; @@ -14,84 +13,84 @@ @Repository public interface RecipeRepository extends JpaRepository { + @Query("SELECT new CaffeineCoder.recipic.domain.recipe.dto.RecipeDto(" + "r.recipeId, " + "r.userId, " + - "r.brandId, " + + "b.brandName, " + // Brand 엔티티에서 brandName을 가져옴 "r.title, " + "r.description, " + "r.imageUrl, " + "r.isCelebrity, " + "r.createdAt, " + "r.status) " + - "FROM Recipe r " + - "WHERE r.brandId = :brandId") - Page findRecipesByBrandId(@Param("brandId") Integer brandId, Pageable pageable); + "FROM Recipe r JOIN r.brand b " + // Recipe와 Brand를 조인 + "WHERE r.userId = :userId") + Page findRecipesByUserId( + @Param("userId") Long userId, + Pageable pageable); @Query("SELECT new CaffeineCoder.recipic.domain.recipe.dto.RecipeDto(" + "r.recipeId, " + "r.userId, " + - "r.brandId, " + + "b.brandName, " + // Brand 엔티티에서 brandName을 가져옴 "r.title, " + "r.description, " + "r.imageUrl, " + "r.isCelebrity, " + "r.createdAt, " + "r.status) " + - "FROM Recipe r " + - "WHERE r.brandId = :brandId AND r.userId = :userId") - Page findRecipesByBrandIdAndUserId(@Param("brandId") Integer brandId, - @Param("userId") Long userId, - Pageable pageable); + "FROM Recipe r JOIN Brand b ON r.brand.brandId = b.brandId " + // Recipe와 Brand를 명시적으로 조인 + "WHERE b.brandName = :brandName") + Page findRecipesByBrandName(@Param("brandName") String brandName, Pageable pageable); @Query("SELECT new CaffeineCoder.recipic.domain.recipe.dto.RecipeDto(" + "r.recipeId, " + "r.userId, " + - "r.brandId, " + + "b.brandName, " + // Brand 엔티티에서 brandName을 가져옴 "r.title, " + "r.description, " + "r.imageUrl, " + "r.isCelebrity, " + "r.createdAt, " + "r.status) " + - "FROM Recipe r " + - "WHERE r.userId = :userId") - Page findRecipesByUserId(@Param("userId") Long userId, Pageable pageable); + "FROM Recipe r JOIN r.brand b " + // Recipe와 Brand를 조인 + "WHERE b.brandName = :brandName AND r.userId = :userId") + Page findRecipesByBrandNameAndUserId( + @Param("brandName") String brandName, + @Param("userId") Long userId, + Pageable pageable); @Query("SELECT new CaffeineCoder.recipic.domain.recipe.dto.RecipeDto(" + "r.recipeId, " + "r.userId, " + - "r.brandId, " + + "b.brandName, " + // Brand 엔티티에서 brandName을 가져옴 "r.title, " + "r.description, " + "r.imageUrl, " + "r.isCelebrity, " + "r.createdAt, " + "r.status) " + - "FROM Recipe r " + - "WHERE r.brandId = :brandId AND r.recipeId IN :recipeIds") - Page findRecipesByBrandIdAndRecipeIds( - @Param("brandId") Integer brandId, + "FROM Recipe r JOIN r.brand b " + // Recipe와 Brand를 조인 + "WHERE b.brandName = :brandName AND r.recipeId IN :recipeIds") + Page findRecipesByBrandNameAndRecipeIds( + @Param("brandName") String brandName, @Param("recipeIds") List recipeIds, Pageable pageable); @Query("SELECT new CaffeineCoder.recipic.domain.recipe.dto.RecipeDto(" + "r.recipeId, " + "r.userId, " + - "r.brandId, " + + "b.brandName, " + // Brand 엔티티에서 brandName을 가져옴 "r.title, " + "r.description, " + "r.imageUrl, " + "r.isCelebrity, " + "r.createdAt, " + "r.status) " + - "FROM Recipe r " + + "FROM Recipe r JOIN r.brand b " + // Recipe와 Brand를 조인 "WHERE r.recipeId IN :recipeIds") Page findRecipesByRecipeIds( @Param("recipeIds") List recipeIds, Pageable pageable); - - } - - diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/Recipe.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/Recipe.java index ba0f2d3..6a6cd66 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/Recipe.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/Recipe.java @@ -1,5 +1,6 @@ package CaffeineCoder.recipic.domain.recipe.domain; +import CaffeineCoder.recipic.domain.brand.domain.Brand; import CaffeineCoder.recipic.domain.comment.domain.Comment; import CaffeineCoder.recipic.domain.scrap.domain.Scrap; import jakarta.persistence.*; @@ -25,8 +26,9 @@ public class Recipe { @Column(name = "user_id") private Long userId; - @Column(name = "brand_id") - private Integer brandId; + @ManyToOne + @JoinColumn(name = "brand_id") + private Brand brand; @Column(name = "title") private String title; @@ -40,7 +42,7 @@ public class Recipe { @Column(name = "is_celebrity") private Boolean isCelebrity; - @Column(name = "created_at") + @Column(name = "created_at", updatable = false) private Timestamp createdAt; @Column(name = "status") @@ -57,9 +59,9 @@ public class Recipe { private List scraps; @Builder - public Recipe(Long userId, Integer brandId, String title, String description, String imageUrl, Boolean isCelebrity, Timestamp createdAt, Integer status) { + public Recipe(Long userId, Brand brand, String title, String description, String imageUrl, Boolean isCelebrity, Timestamp createdAt, Integer status) { this.userId = userId; - this.brandId = brandId; + this.brand = brand; this.title = title; this.description = description; this.imageUrl = imageUrl; @@ -68,12 +70,26 @@ public Recipe(Long userId, Integer brandId, String title, String description, St this.status = status; } + @PrePersist + protected void onCreate() { + if (this.createdAt == null) { + this.createdAt = new Timestamp(System.currentTimeMillis()); + } + } + // 게시글 수정 메소드 - public void updateRecipe(String title, String description, String imageUrl, Integer brandId, Boolean isCelebrity) { + public void updateRecipe(String title, String description, String imageUrl, Brand brand, Boolean isCelebrity) { this.title = title; this.description = description; this.imageUrl = imageUrl; - this.brandId = brandId; + this.brand = brand; this.isCelebrity = isCelebrity; } + + + + // Brand의 이름을 반환하는 메서드 + public String getBrandName() { + return this.brand != null ? this.brand.getBrandName() : null; + } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredient.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredient.java index 68f1e3c..872b770 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredient.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredient.java @@ -1,5 +1,6 @@ package CaffeineCoder.recipic.domain.recipe.domain; +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredient; import CaffeineCoder.recipic.domain.brand.domain.Ingredient; import jakarta.persistence.*; import lombok.Builder; @@ -19,19 +20,27 @@ public class RecipeIngredient { @JoinColumn(name = "recipe_id") private Recipe recipe; + // 사이드 재료 매핑 @ManyToOne @MapsId("ingredientId") - @JoinColumn(name = "ingredient_id") + @JoinColumn(name = "ingredient_id", referencedColumnName = "ingredient_id", insertable = false, updatable = false) private Ingredient ingredient; + // 베이스 재료 매핑 + @ManyToOne + @MapsId("baseIngredientId") + @JoinColumn(name = "baseingredient_id", referencedColumnName = "baseingredient_id", insertable = false, updatable = false) + private BaseIngredient baseIngredient; + @Column(name = "count") private Integer count; @Builder - public RecipeIngredient(RecipeIngredientId id, Recipe recipe, Ingredient ingredient, Integer count) { + public RecipeIngredient(RecipeIngredientId id, Recipe recipe, Ingredient ingredient, BaseIngredient baseIngredient, Integer count) { this.id = id; this.recipe = recipe; this.ingredient = ingredient; + this.baseIngredient = baseIngredient; this.count = count; } -} \ No newline at end of file +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredientId.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredientId.java index ae0a82b..e672c39 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredientId.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/domain/RecipeIngredientId.java @@ -13,15 +13,19 @@ @NoArgsConstructor public class RecipeIngredientId implements Serializable { - @Column(name = "ingredient_id") - private Integer ingredientId; - @Column(name = "recipe_id") private Integer recipeId; - public RecipeIngredientId(Integer ingredientId, Integer recipeId) { - this.ingredientId = ingredientId; + @Column(name = "ingredient_id", nullable = true) + private Integer ingredientId; + + @Column(name = "baseingredient_id", nullable = true) + private Integer baseIngredientId; + + public RecipeIngredientId(Integer recipeId, Integer ingredientId, Integer baseIngredientId) { this.recipeId = recipeId; + this.ingredientId = ingredientId; + this.baseIngredientId = baseIngredientId; } @Override @@ -29,12 +33,13 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; RecipeIngredientId that = (RecipeIngredientId) o; - return Objects.equals(ingredientId, that.ingredientId) && - Objects.equals(recipeId, that.recipeId); + return Objects.equals(recipeId, that.recipeId) && + Objects.equals(ingredientId, that.ingredientId) && + Objects.equals(baseIngredientId, that.baseIngredientId); } @Override public int hashCode() { - return Objects.hash(ingredientId, recipeId); + return Objects.hash(recipeId, ingredientId, baseIngredientId); } -} \ No newline at end of file +} diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/IncludeIngredientDto.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/IncludeIngredientDto.java index 6bd5bd1..e638416 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/IncludeIngredientDto.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/IncludeIngredientDto.java @@ -1,5 +1,6 @@ package CaffeineCoder.recipic.domain.recipe.dto; +import CaffeineCoder.recipic.domain.brand.domain.BaseIngredient; import CaffeineCoder.recipic.domain.brand.domain.Ingredient; import lombok.Builder; import lombok.Getter; @@ -7,14 +8,13 @@ @Getter public class IncludeIngredientDto { private Ingredient ingredient; + private BaseIngredient baseIngredient; private Integer count; @Builder - public IncludeIngredientDto(Ingredient ingredient, Integer count) { + public IncludeIngredientDto(Ingredient ingredient, BaseIngredient baseIngredient, Integer count) { this.ingredient = ingredient; + this.baseIngredient = baseIngredient; this.count = count; } - - // Getters and Setters } - diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeDto.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeDto.java index 236d246..6af3269 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeDto.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeDto.java @@ -5,26 +5,26 @@ import java.sql.Timestamp; public record RecipeDto( - Integer recipeId, - Long userId, - Integer brandId, - String title, - String description, - String imageUrl, - Boolean isCelebrity, - Timestamp createdAt, - Integer status + Integer recipeId, + Long userId, + String brandName, + String title, + String description, + String imageUrl, + Boolean isCelebrity, + Timestamp createdAt, + Integer status ) { - public static RecipeDto of(Integer recipeId, Long userId, Integer brandId, String title, String description, String imageUrl, Boolean isCelebrity, Timestamp createdAt, Integer status) { - return new RecipeDto(recipeId, userId, brandId, title, description, imageUrl, isCelebrity, createdAt, status); + public static RecipeDto of(Integer recipeId, Long userId, String brandName, String title, String description, String imageUrl, Boolean isCelebrity, Timestamp createdAt, Integer status) { + return new RecipeDto(recipeId, userId, brandName, title, description, imageUrl, isCelebrity, createdAt, status); } public static RecipeDto fromEntity(Recipe recipe) { return new RecipeDto( recipe.getRecipeId(), recipe.getUserId(), - recipe.getBrandId(), + recipe.getBrandName(), recipe.getTitle(), recipe.getDescription(), recipe.getImageUrl(), @@ -34,5 +34,3 @@ public static RecipeDto fromEntity(Recipe recipe) { ); } } - - diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeRequestDto.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeRequestDto.java index 7c93568..0a1776a 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeRequestDto.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeRequestDto.java @@ -15,11 +15,16 @@ public class RecipeRequestDto { private Integer recipeId; - private String brandName; + private Integer brandId; private String title; private List selectedRecipes; private String description; private Boolean isCelebrity; + private String thumbnailUrl; + + public String getThumbnailUrl() { + return thumbnailUrl; + } @Getter @NoArgsConstructor @@ -28,5 +33,10 @@ public class RecipeRequestDto { public static class SelectedRecipeDto { private String ingredientName; private Integer count; + private Boolean isBaseIngredient; + + public Boolean isBaseIngredient() { + return isBaseIngredient; + } } } diff --git a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeResponseDto.java b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeResponseDto.java index 15affe0..d25d70f 100644 --- a/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeResponseDto.java +++ b/src/main/java/CaffeineCoder/recipic/domain/recipe/dto/RecipeResponseDto.java @@ -24,12 +24,13 @@ public static RecipeResponseDto of(Integer recipeId, String userName,String user } //추후 댓글 개수도 추가 - public static RecipeResponseDto fromEntity(Recipe recipe, User user,String brandName, int scrapCount, int commentCount) { + public static RecipeResponseDto fromEntity(Recipe recipe, User user, String brandName, int scrapCount, int commentCount) { return new RecipeResponseDto( recipe.getRecipeId(), user.getNickName(), user.getProfileImageUrl(), recipe.getTitle(), + "https://storage.googleapis.com/recipick-image-bucket/"+recipe.getImageUrl(), brandName, recipe.getDescription(), @@ -40,7 +41,6 @@ public static RecipeResponseDto fromEntity(Recipe recipe, User user,String brand commentCount ); } - public static RecipeResponseDto fromDto(RecipeDto recipeDto,User user,String brandName, int scrapCount, int commentCount) { return new RecipeResponseDto( recipeDto.recipeId(),