diff --git a/refrigerator/.idea/modules.xml b/refrigerator/.idea/modules.xml index bdc72c3..738a4c5 100644 --- a/refrigerator/.idea/modules.xml +++ b/refrigerator/.idea/modules.xml @@ -3,6 +3,7 @@ + \ No newline at end of file diff --git a/refrigerator/.idea/modules/refrigerator.main.iml b/refrigerator/.idea/modules/refrigerator.main.iml index 397c268..1cbf656 100644 --- a/refrigerator/.idea/modules/refrigerator.main.iml +++ b/refrigerator/.idea/modules/refrigerator.main.iml @@ -4,9 +4,6 @@ - - - @@ -16,7 +13,9 @@ - + + + diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/Recipe.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/Recipe.java index 575058e..5c8068b 100644 --- a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/Recipe.java +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/Recipe.java @@ -56,6 +56,10 @@ public class Recipe { @JsonManagedReference private List recipeSource = new ArrayList<>() ; // 여러 Source가 들어갈 수 있으니까 list로 수정 + @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true,fetch = FetchType.LAZY) + @JsonManagedReference + private List recipeStep = new ArrayList<>(); + @JoinColumn(name = "recipe_category") @ManyToOne diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeSource.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeSource.java index c69c19b..8862847 100644 --- a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeSource.java +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeSource.java @@ -8,6 +8,7 @@ import lombok.Data; import java.time.LocalDateTime; +import java.util.List; @Data @Entity diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStep.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStep.java new file mode 100644 index 0000000..8d13e90 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStep.java @@ -0,0 +1,37 @@ +package moja.refrigerator.aggregate.recipe; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import jakarta.persistence.*; +import lombok.Data; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Entity +@Table(name = "tbl_recipe_step") +public class RecipeStep { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "recipe_step_pk") + private long recipeStepPk; + + @Column(name = "recipe_step_order") + private int recipeStepOrder; + + @Column(name = "recipe_step_content") + private String recipeStepContent; + + @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY) + @JsonManagedReference + @JoinColumn(name = "recipe_step_source_pk") + private RecipeStepSource recipeStepSource; + + @ManyToOne + @JoinColumn(name = "recipe_pk") + @JsonBackReference + private Recipe recipe; + +} diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStepSource.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStepSource.java new file mode 100644 index 0000000..fcd7090 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeStepSource.java @@ -0,0 +1,41 @@ +package moja.refrigerator.aggregate.recipe; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.persistence.*; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +@Entity +@Table(name="tbl_recipe_step_source") +public class RecipeStepSource { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "recipe_step_source_pk") + private long recipeStepSourcePk; + + @Column(name = "recipe_step_source_save") // 저장위치 + private String recipeStepSourceSave; + + @Column(name = "recipe_step_source_create_time") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + private LocalDateTime recipeStepSourceCreateTime = LocalDateTime.now(); + + @Column(name = "recipe_step_source_file_name",nullable = false) // 저장 파일 명 + private String recipeStepSourceFileName; + + @Column(name = "recipe_step_source_servername") // 서버 저장한 이름 추가. + private String recipeStepSourceServername; + + @JoinColumn(name = "recipe_step_source_type") // 자료타입 동영상 or 사진 + @ManyToOne + private RecipeSourceType recipeStepSourceType; + + @JsonBackReference + @OneToOne(fetch = FetchType.EAGER) + @JoinColumn(name="recipe_step_pk") + private RecipeStep recipeStep; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/user/Follow.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/Follow.java index 80eaa90..caaddfa 100644 --- a/refrigerator/src/main/java/moja/refrigerator/aggregate/user/Follow.java +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/Follow.java @@ -12,11 +12,11 @@ public class Follow { @Column(name = "follow_pk") private long followPk; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "follower") private User follower; - @ManyToOne + @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "following") private User following; } diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/user/User.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/User.java index 03eb039..524bcdc 100644 --- a/refrigerator/src/main/java/moja/refrigerator/aggregate/user/User.java +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/user/User.java @@ -5,6 +5,7 @@ import org.hibernate.annotations.CreationTimestamp; import java.time.LocalDate; +import java.util.List; @Entity @Table(name = "tbl_user") @@ -33,4 +34,10 @@ public class User { @Column(name = "user_role") private String userRole = "ROLE_USER"; + + @OneToMany(mappedBy = "follower", cascade = CascadeType.REMOVE) + private List following; + + @OneToMany(mappedBy = "following", cascade = CascadeType.REMOVE) + private List followers; } diff --git a/refrigerator/src/main/java/moja/refrigerator/config/WebConfig.java b/refrigerator/src/main/java/moja/refrigerator/config/WebConfig.java new file mode 100644 index 0000000..9b946ae --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/config/WebConfig.java @@ -0,0 +1,18 @@ +package moja.refrigerator.config; + +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +@Configuration +public class WebConfig implements WebMvcConfigurer { + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("http://localhost:5173") + .allowedMethods("GET", "POST", "PUT", "DELETE") + .allowedHeaders("*") + .allowCredentials(true) + .maxAge(3600); + } +} \ No newline at end of file diff --git a/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java b/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java index 03ecb0a..c619f98 100644 --- a/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java +++ b/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java @@ -27,12 +27,15 @@ public RecipeController(RecipeService recipeService) { } @PostMapping - public void createRecipe( + public Recipe createRecipe( @RequestPart RecipeCreateRequest request - , @RequestPart (required =false) List files + ,@RequestPart (name="recipeSources",required =false) List recipeSources + ,@RequestPart (name="recipeStepSources",required =false) List recipeStepSources ){ - recipeService.createRecipe(request - , files + + return recipeService.createRecipe(request + , recipeSources + , recipeStepSources ); } @@ -50,11 +53,12 @@ public void deleteRecipe(@RequestParam long recipePk){ } @PutMapping - public void updateRecipe( + public Recipe updateRecipe( @RequestPart RecipeUpdateRequest request - ,@RequestPart (required =false) List files + ,@RequestPart (name="recipeSources",required =false) List recipeSources + ,@RequestPart (name="recipeStepSources",required =false) List recipeStepSources ){ - recipeService.updateRecipe(request,files); + return recipeService.updateRecipe(request,recipeSources,recipeStepSources); } @GetMapping("/recommend") diff --git a/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java b/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java index c841068..5c716e1 100644 --- a/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java +++ b/refrigerator/src/main/java/moja/refrigerator/controller/user/UserController.java @@ -1,5 +1,7 @@ package moja.refrigerator.controller.user; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import moja.refrigerator.dto.user.request.PasswordResetRequest; import moja.refrigerator.dto.user.request.PasswordUpdateRequest; import moja.refrigerator.dto.user.request.UserCreateRequest; @@ -60,4 +62,11 @@ public ResponseEntity toggleFollow(@PathVariable Long userPk) { followService.toggleFollow(userPk); return ResponseEntity.ok().body("팔로우 상태가 변경되었습니다."); } + + // 회원 탈퇴 + @PostMapping("/delete") + public ResponseEntity delete(HttpServletRequest request, HttpServletResponse response) { + userService.deleteUser(request, response); + return ResponseEntity.status(HttpStatus.NO_CONTENT).build(); + } } diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/ingredient/response/IngredientResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/ingredient/response/IngredientResponse.java index bda5d0b..e5220a0 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/ingredient/response/IngredientResponse.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/ingredient/response/IngredientResponse.java @@ -13,6 +13,10 @@ public class IngredientResponse { private long remainExpirationDate; private int seasonDate; private String ingredientStorage; + private long ingredientManagementPk; + private boolean isBookmarked; + private String ingredientCategory; + private long ingredientBookmarkPk; // ModelMapper 를 위한 기본 생성자 생성 public IngredientResponse() {} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeCreateRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeCreateRequest.java index ef8640d..fe1ee5d 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeCreateRequest.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeCreateRequest.java @@ -1,9 +1,9 @@ package moja.refrigerator.dto.recipe.request; import lombok.Data; -import moja.refrigerator.aggregate.recipe.RecipeCategory; -import moja.refrigerator.aggregate.recipe.RecipeSource; -import moja.refrigerator.aggregate.user.User; +import moja.refrigerator.aggregate.recipe.RecipeStep; + +import java.util.List; @Data public class RecipeCreateRequest { @@ -11,12 +11,8 @@ public class RecipeCreateRequest { private int recipeCookingTime; private int recipeDifficulty; private String recipeContent; -// private long recipeSource; private int recipeCategoryPk; + private List recipeSteps; private long userPk; -// private long recipePk; // 자동 추가 -// private String recipeCreateTime; //자동 추가 -// private String recipeUpdateTime; //자동 추가 -// private long recipeViews; // 조회 시 올리는 것으로 } diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepRequest.java new file mode 100644 index 0000000..a7acb05 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepRequest.java @@ -0,0 +1,9 @@ +package moja.refrigerator.dto.recipe.request; + +import lombok.Data; + +@Data +public class RecipeStepRequest { + private int recipeStepOrder; // JSON에 있는 필드와 이름 동일해야 함 + private String recipeStepContent; // JSON의 recipeStepContent와 일치 +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepSourceRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepSourceRequest.java new file mode 100644 index 0000000..a306892 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepSourceRequest.java @@ -0,0 +1,18 @@ +package moja.refrigerator.dto.recipe.request; + +import lombok.Data; +import moja.refrigerator.aggregate.recipe.RecipeSourceType; + +import java.time.LocalDateTime; + +@Data +public class RecipeStepSourceRequest { + private long recipeStepSourcePk; + private String recipeStepSourceSave; + private LocalDateTime recipeStepSourceCreateTime; + private String recipeStepSourceFileName; + private String recipeStepSourceServername; + private RecipeSourceType recipeStepSourceType; + + +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepUpdateRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepUpdateRequest.java new file mode 100644 index 0000000..e56a406 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeStepUpdateRequest.java @@ -0,0 +1,11 @@ +package moja.refrigerator.dto.recipe.request; + +import lombok.Data; + +@Data +public class RecipeStepUpdateRequest { + private Long recipeStepPk; + private int recipeStepOrder; // JSON에 있는 필드와 이름 동일해야 함 + private String recipeStepContent; // JSON의 recipeStepContent와 일치 + private RecipeStepSourceRequest recipeStepSource; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeUpdateRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeUpdateRequest.java index dd7c2d9..da9bea1 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeUpdateRequest.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeUpdateRequest.java @@ -3,6 +3,8 @@ import lombok.Data; +import java.util.List; + @Data public class RecipeUpdateRequest { private long recipePk; @@ -13,5 +15,6 @@ public class RecipeUpdateRequest { private String recipeSource; private String recipeCategory; private String userPk; + private List recipeSteps; } diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeDetailResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeDetailResponse.java index 0fcf203..6570fc1 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeDetailResponse.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeDetailResponse.java @@ -4,6 +4,7 @@ import java.util.List; import lombok.Data; +import moja.refrigerator.aggregate.recipe.RecipeSource; import moja.refrigerator.dto.ingredient.response.IngredientResponse; @Data @@ -17,9 +18,10 @@ public class RecipeDetailResponse { private LocalDateTime recipeCreateTime;; private LocalDateTime recipeUpdateTime; - private String recipeSource; + private List recipeSource; private String userPk; private String recipeCategory; private List ingredients; + private List recipeStep; } diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeRecommendResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeRecommendResponse.java index efdb622..14be138 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeRecommendResponse.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeRecommendResponse.java @@ -14,4 +14,7 @@ public class RecipeRecommendResponse { private long remainExpirationDays; private String urgentIngredientName; private List ingredients; + + private List mainImages; // 메인 이미지들 + private List steps; } \ No newline at end of file diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeResponse.java index 5686857..c2038b0 100644 --- a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeResponse.java +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeResponse.java @@ -3,6 +3,7 @@ import lombok.Data; import moja.refrigerator.aggregate.recipe.RecipeCategory; import moja.refrigerator.aggregate.recipe.RecipeSource; +import moja.refrigerator.aggregate.recipe.RecipeStep; import moja.refrigerator.aggregate.user.User; import java.time.LocalDateTime; @@ -22,6 +23,8 @@ public class RecipeResponse { private LocalDateTime recipeUpdateTime; private List recipeSource; + + private List recipeStep; private User user; private RecipeCategory recipeCategory; diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeSourceInfo.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeSourceInfo.java new file mode 100644 index 0000000..18a37bb --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeSourceInfo.java @@ -0,0 +1,9 @@ +package moja.refrigerator.dto.recipe.response; + +import lombok.Data; + +@Data +public class RecipeSourceInfo { + private String filePath; + private String originalName; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepResponse.java new file mode 100644 index 0000000..1a52f2b --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepResponse.java @@ -0,0 +1,12 @@ +package moja.refrigerator.dto.recipe.response; + +import lombok.Data; + +@Data +public class RecipeStepResponse { + + private int recipeStepOrder; + private String recipeStepContent; + private RecipeStepSourceResponse recipeStepSource; + +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepSourceResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepSourceResponse.java new file mode 100644 index 0000000..5b51094 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepSourceResponse.java @@ -0,0 +1,16 @@ +package moja.refrigerator.dto.recipe.response; + +import lombok.Data; +import moja.refrigerator.aggregate.recipe.RecipeSourceType; + +import java.time.LocalDateTime; + +@Data +public class RecipeStepSourceResponse { + private long recipeStepSourcePk; + private String recipeStepSourceSave; + private LocalDateTime recipeStepSourceCreateTime; + private String recipeStepSourceFileName; + private String recipeStepSourceServername; + private RecipeSourceType recipeStepSourceType; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepWithImage.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepWithImage.java new file mode 100644 index 0000000..e5c380e --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeStepWithImage.java @@ -0,0 +1,13 @@ +package moja.refrigerator.dto.recipe.response; + +import lombok.Data; + +import java.util.List; + + +@Data +public class RecipeStepWithImage { + private int order; + private String content; + private List images; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepRepository.java b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepRepository.java new file mode 100644 index 0000000..ecfb529 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepRepository.java @@ -0,0 +1,8 @@ +package moja.refrigerator.repository.recipe; + +import moja.refrigerator.aggregate.recipe.RecipeStep; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RecipeStepRepository extends JpaRepository { + +} diff --git a/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepSourceRepository.java b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepSourceRepository.java new file mode 100644 index 0000000..867b71d --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeStepSourceRepository.java @@ -0,0 +1,8 @@ +package moja.refrigerator.repository.recipe; + +import moja.refrigerator.aggregate.recipe.RecipeIngredient; +import moja.refrigerator.aggregate.recipe.RecipeStepSource; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface RecipeStepSourceRepository extends JpaRepository { +} diff --git a/refrigerator/src/main/java/moja/refrigerator/service/ingredient/IngredientServiceImpl.java b/refrigerator/src/main/java/moja/refrigerator/service/ingredient/IngredientServiceImpl.java index 9842b63..19d7968 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/ingredient/IngredientServiceImpl.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/ingredient/IngredientServiceImpl.java @@ -65,6 +65,7 @@ public void createIngredient(IngredientCreateRequest request, Long userPk, Long @Transactional(readOnly = true) public List getIngredient(Long userPk) { List ingredients = ingredientMyRefrigeratorRepository.findByUserUserPk(userPk); + List ingredientBookmarks = ingredientBookmarkRepository.findAllByUser_UserPk(userPk); LocalDate currentDate = LocalDate.now(); AtomicInteger counter = new AtomicInteger(1); @@ -76,6 +77,17 @@ public List getIngredient(Long userPk) { response.setIngredientName(ingredient.getIngredientManagement().getIngredientName()); response.setSeasonDate(ingredient.getIngredientManagement().getSeasonDate()); response.setIngredientStorage(ingredient.getIngredientManagement().getIngredientStorage().getIngredientStorage()); + response.setIngredientCategory(ingredient.getIngredientManagement().getIngredientCategory().getIngredientCategory()); + boolean isBookmark = false; + for (IngredientBookmark ingredientBookmark : ingredientBookmarks) { + if (ingredientBookmark.getIngredientMyRefrigerator().getIngredientMyRefrigeratorPk() + == ingredient.getIngredientMyRefrigeratorPk()) { + isBookmark = true; + response.setIngredientBookmarkPk(ingredientBookmark.getIngredientBookmarkPk()); + break; + } + } + response.setBookmarked(isBookmark); // 현재 날짜 기준, 유통기한 남은 일수 계산 LocalDate expirationDate = LocalDate.parse(ingredient.getExpirationDate()); diff --git a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java index 81c69a5..4d6f885 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java @@ -15,15 +15,17 @@ import java.util.List; public interface RecipeService { - void createRecipe(RecipeCreateRequest request - ,List files + Recipe createRecipe(RecipeCreateRequest request + ,List recipeSources + ,List recipeStepSources ); List getAllRecipes(); RecipeDetailResponse getRecipe(long id); void deleteRecipe(long recipePk); - void updateRecipe( + Recipe updateRecipe( RecipeUpdateRequest request - ,List files + ,List recipeSources + ,List recipeStepSources ); List getRecommendedRecipes(Long userPk); RecipeRecommendResponse getRandomRecipe(); diff --git a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java index 42030fb..1ef91e0 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java @@ -7,9 +7,7 @@ import moja.refrigerator.aggregate.recipe.*; import moja.refrigerator.aggregate.user.User; import moja.refrigerator.dto.recipe.RecipeMatchResult; -import moja.refrigerator.dto.recipe.request.RecipeCreateRequest; -import moja.refrigerator.dto.recipe.request.RecipeLikeRequest; -import moja.refrigerator.dto.recipe.request.RecipeUpdateRequest; +import moja.refrigerator.dto.recipe.request.*; import moja.refrigerator.dto.recipe.response.*; import moja.refrigerator.repository.ingredient.IngredientMyRefrigeratorRepository; import moja.refrigerator.repository.recipe.*; @@ -28,6 +26,11 @@ import java.util.*; import java.util.stream.Collectors; +/** + * Implementation of the RecipeService interface, providing business logic for managing recipes. + * This class interacts with various repositories for CRUD operations related to recipes, ingredients, files, and user data, + * as well as Amazon S3 for file storage. + */ @Service public class RecipeServiceImpl implements RecipeService { @@ -42,6 +45,8 @@ public class RecipeServiceImpl implements RecipeService { private final RecipeIngredientRepository recipeIngredientRepository; private final ReplacableIngredientRepository replacableIngredientRepository; private final RecipeLikeDislikeRepository recipeLikeDislikeRepository; + private final RecipeStepRepository recipeStepRepository; + private final RecipeStepSourceRepository recipeStepSourceRepository; @Value("${cloud.aws.s3.bucket}") private String bucket; @@ -58,7 +63,9 @@ public RecipeServiceImpl( IngredientMyRefrigeratorRepository ingredientMyRefrigeratorRepository, RecipeIngredientRepository recipeIngredientRepository, ReplacableIngredientRepository replacableIngredientRepository, - RecipeLikeDislikeRepository recipeLikeDislikeRepository + RecipeLikeDislikeRepository recipeLikeDislikeRepository, + RecipeStepRepository recipeStepRepository, + RecipeStepSourceRepository recipeStepSourceRepository ) { this.recipeRepository = recipeRepository; this.userRepository = userRepository; @@ -71,6 +78,8 @@ public RecipeServiceImpl( this.recipeIngredientRepository = recipeIngredientRepository; this.replacableIngredientRepository = replacableIngredientRepository; this.recipeLikeDislikeRepository = recipeLikeDislikeRepository; + this.recipeStepRepository = recipeStepRepository; + this.recipeStepSourceRepository = recipeStepSourceRepository; } private boolean isImageFile(String fileName) { String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); @@ -81,10 +90,114 @@ private boolean isVideoFile(String fileName) { String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); return List.of("mp4", "avi", "mov", "wmv").contains(extension); } + // 파일 처리 전용 메서드 + private RecipeSource RecipeSourceSaveFile(MultipartFile file, Recipe recipe, String pathPrefix) { + try { + if (file == null || file.isEmpty()) { + return null; + } + String originalFileName = file.getOriginalFilename(); + if (originalFileName == null) { + throw new IllegalArgumentException("Empty file name is not allowed"); + } + + // 파일 이름 생성 및 저장 경로 설정 + UUID uuid = UUID.randomUUID(); + String serverFileName = uuid + "_" + originalFileName; + String fileUrl = "https://" + bucket + "/" + pathPrefix + serverFileName; + + // RecipeSource 생성 및 설정 + RecipeSource recipeSource = new RecipeSource(); + recipeSource.setRecipeSourceServername(serverFileName); + recipeSource.setRecipeSourceSave(fileUrl); + recipeSource.setRecipeSourceFileName(originalFileName); + + // 파일 타입 처리 + RecipeSourceType recipeSourceType; + if (isImageFile(originalFileName)) { + recipeSourceType = recipeSourceTypeRepository.findById(1) + .orElseThrow(() -> new IllegalArgumentException("Image type not found")); + } else if (isVideoFile(originalFileName)) { + recipeSourceType = recipeSourceTypeRepository.findById(2) + .orElseThrow(() -> new IllegalArgumentException("Video type not found")); + } else { + throw new IllegalArgumentException("Unsupported file type: " + originalFileName); + } + recipeSource.setRecipeSourceType(recipeSourceType); + recipeSource.setRecipe(recipe); + + + // AWS S3에 파일 업로드 + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(file.getContentType()); + metadata.setContentLength(file.getSize()); + amazonS3Client.putObject(bucket, pathPrefix + serverFileName, file.getInputStream(), metadata); + + // RecipeSource 저장 + recipeSourceRepository.save(recipeSource); + return recipeSource; + } catch (IOException e) { + throw new RuntimeException("File upload failed: " + e.getMessage(), e); + } + } + + private RecipeStepSource RecipeStepSourceSaveFile(MultipartFile file, RecipeStep recipeStep, String pathPrefix) { + try { + if (file == null || file.isEmpty()) { + return null; + } + String originalFileName = file.getOriginalFilename(); + if (originalFileName == null) { + throw new IllegalArgumentException("Empty file name is not allowed"); + } + + // 파일 이름 생성 및 저장 경로 설정 + UUID uuid = UUID.randomUUID(); + String serverFileName = uuid + "_" + originalFileName; + String fileUrl = "https://" + bucket + "/" + pathPrefix + serverFileName; + + // RecipeSource 생성 및 설정 + RecipeStepSource recipeSource = new RecipeStepSource(); + recipeSource.setRecipeStepSourceServername(serverFileName); + recipeSource.setRecipeStepSourceSave(fileUrl); + recipeSource.setRecipeStepSourceFileName(originalFileName); + + // 파일 타입 처리 + RecipeSourceType recipeSourceType; + if (isImageFile(originalFileName)) { + recipeSourceType = recipeSourceTypeRepository.findById(1) + .orElseThrow(() -> new IllegalArgumentException("Image type not found")); + } else if (isVideoFile(originalFileName)) { + recipeSourceType = recipeSourceTypeRepository.findById(2) + .orElseThrow(() -> new IllegalArgumentException("Video type not found")); + } else { + throw new IllegalArgumentException("Unsupported file type: " + originalFileName); + } + recipeSource.setRecipeStepSourceType(recipeSourceType); + recipeSource.setRecipeStep(recipeStep); + + // AWS S3에 파일 업로드 + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(file.getContentType()); + metadata.setContentLength(file.getSize()); + amazonS3Client.putObject(bucket, pathPrefix + serverFileName, file.getInputStream(), metadata); + + // RecipeSource 저장 + recipeStepSourceRepository.save(recipeSource); + return recipeSource; + + } catch (IOException e) { + throw new RuntimeException("File upload failed: " + e.getMessage(), e); + } + } + @Override @Transactional(propagation = Propagation.REQUIRED) - public void createRecipe(RecipeCreateRequest request, List files) { + public Recipe createRecipe(RecipeCreateRequest request + ,List recipeSources + ,List recipeStepSources + ) { Recipe recipe = new Recipe(); recipe.setRecipeName(request.getRecipeName()); recipe.setRecipeContent(request.getRecipeContent()); @@ -99,46 +212,38 @@ public void createRecipe(RecipeCreateRequest request, List files) .orElseThrow(IllegalArgumentException::new); recipe.setRecipeCategory(recipeCategory); - if(files != null && !files.isEmpty()) { - for(MultipartFile file : files) { - try { - String recipeSourceFileName = file.getOriginalFilename(); - UUID uuid = UUID.randomUUID(); - String recipeSourceServername = uuid + recipeSourceFileName; - String recipeSourceSave = "https://" + bucket + "/recipe/" + recipeSourceServername; - - RecipeSource recipeSource = new RecipeSource(); - recipeSource.setRecipeSourceServername(recipeSourceServername); - recipeSource.setRecipeSourceSave(recipeSourceSave); - recipeSource.setRecipeSourceFileName(recipeSourceFileName); - - RecipeSourceType recipeSourceType; - if(isImageFile(recipeSourceFileName)) { - recipeSourceType = recipeSourceTypeRepository.findById(1) - .orElseThrow(IllegalArgumentException::new); - } else if (isVideoFile(recipeSourceFileName)) { - recipeSourceType = recipeSourceTypeRepository.findById(2) - .orElseThrow(IllegalArgumentException::new); - } else { - throw new IllegalArgumentException("Unsupported file type"); - } + if(recipeSources != null && !recipeSources.isEmpty()) { + for(MultipartFile file : recipeSources) { + RecipeSource recipeSource = RecipeSourceSaveFile(file, recipe, "recipe/"); + recipe.getRecipeSource().add(recipeSource); + } + } - ObjectMetadata objectMetadata = new ObjectMetadata(); - objectMetadata.setContentType(file.getContentType()); - objectMetadata.setContentLength(file.getSize()); - amazonS3Client.putObject(bucket, recipeSourceServername, file.getInputStream(), objectMetadata); - recipeSource.setRecipeSourceType(recipeSourceType); - recipeSource.setRecipe(recipe); - recipeSourceRepository.save(recipeSource); - break; - } catch (IOException e) { - System.out.println(e.getMessage()); + List recipeSteps = request.getRecipeSteps(); + if(recipeSteps != null ) { + for (int i = 0; i < recipeSteps.size(); i++) { + RecipeStepRequest step = recipeSteps.get(i); + + // RecipeStep 저장 + RecipeStep newStep = new RecipeStep(); + newStep.setRecipeStepOrder(i + 1); + newStep.setRecipeStepContent(step.getRecipeStepContent()); + newStep.setRecipe(recipe); + + if (recipeStepSources != null && recipeStepSources.size() > i) { + System.out.println("------------------------------"); + MultipartFile file = recipeStepSources.get(i); + RecipeStepSource stepSource = RecipeStepSourceSaveFile(file, newStep, "recipe/step/"); + newStep.setRecipeStepSource(stepSource); // 파일 매핑 } + + recipe.getRecipeStep().add(newStep); } } recipeRepository.save(recipe); + return recipe; } @Override @@ -162,15 +267,29 @@ public void deleteRecipe(long recipePk) { List sources = recipe.getRecipeSource(); if(sources != null && !sources.isEmpty()) { for (RecipeSource recipeSource : sources) { - amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, recipeSource.getRecipeSourceServername())); + amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, "recipe/"+recipeSource.getRecipeSourceServername())); + } + } + List steps = recipe.getRecipeStep(); + if(steps != null && !steps.isEmpty()) { + for (RecipeStep recipeStep : steps) { + RecipeStepSource stepSource = recipeStep.getRecipeStepSource(); + if(stepSource != null) { + amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, "recipe/step/"+stepSource.getRecipeStepSourceServername())); + } } } recipeRepository.delete(recipe); } + + @Override @Transactional - public void updateRecipe(RecipeUpdateRequest request, List files) { + public Recipe updateRecipe(RecipeUpdateRequest request + ,List recipeSources + ,List recipeStepSources + ) { Recipe recipe = recipeRepository.findByRecipePk(request.getRecipePk()) .orElseThrow(() -> new IllegalArgumentException("Recipe not found")); @@ -183,7 +302,7 @@ public void updateRecipe(RecipeUpdateRequest request, List files) } List sources = recipe.getRecipeSource(); - List uploadedFileNames = files.stream() + List uploadedFileNames = recipeSources.stream() .map(MultipartFile::getOriginalFilename) .toList(); @@ -201,7 +320,7 @@ public void updateRecipe(RecipeUpdateRequest request, List files) .map(RecipeSource::getRecipeSourceFileName) .toList(); - List filesToAdd = files.stream() + List filesToAdd = recipeSources.stream() .filter(file -> !existingFileNames.contains(file.getOriginalFilename())) .toList(); @@ -240,7 +359,46 @@ public void updateRecipe(RecipeUpdateRequest request, List files) } } + //시간 문제로 레시피 step 전부 삭제 후 생성하는거로 대처 + List steps = recipe.getRecipeStep(); + if(steps != null && !steps.isEmpty()) { + for (RecipeStep step : steps) { + RecipeStepSource stepSource = step.getRecipeStepSource(); + if(stepSource != null) { + amazonS3Client.deleteObject(new DeleteObjectRequest(bucket, "recipe/step/"+stepSource.getRecipeStepSourceServername())); + + } + } + //기존 사진 소스 다 삭제 후 + recipe.getRecipeStep().clear(); + } + + List recipeSteps = request.getRecipeSteps(); + + if(recipeSteps != null ) { + for (int i = 0; i < recipeSteps.size(); i++) { + RecipeStepUpdateRequest step = recipeSteps.get(i); + + // RecipeStep 저장 + RecipeStep newStep = new RecipeStep(); + newStep.setRecipeStepOrder(i + 1); + newStep.setRecipeStepContent(step.getRecipeStepContent()); + newStep.setRecipe(recipe); + + if (recipeStepSources != null && recipeStepSources.size() > i) { + System.out.println("------------------------------22"); + MultipartFile file = recipeStepSources.get(i); + RecipeStepSource stepSource = RecipeStepSourceSaveFile(file, newStep, "recipe/step/"); + newStep.setRecipeStepSource(stepSource); // 파일 매핑 + } + + recipe.getRecipeStep().add(newStep); + } + } + recipeRepository.save(recipe); + + return recipe; } @@ -258,12 +416,52 @@ public List getRecommendedRecipes(Long userPk) { response.setMatchRate(result.getMatchRate()); response.setRemainExpirationDays(result.getRemainExpirationDays()); response.setUrgentIngredientName(result.getUrgentIngredientName()); + + Recipe recipe = result.getRecipe(); + + // 메인 레시피 이미지 설정 + List mainImages = recipe.getRecipeSource().stream() + .filter(source -> source.getRecipeSourceType().getRecipeSourceType().equals("MAIN")) + .map(this::convertToRecipeSourceInfo) + .collect(Collectors.toList()); + response.setMainImages(mainImages); + + // 스텝별 정보와 이미지 설정 + List steps = recipe.getRecipeStep().stream() + .map(step -> { + RecipeStepWithImage stepInfo = new RecipeStepWithImage(); + stepInfo.setOrder(step.getRecipeStepOrder()); + stepInfo.setContent(step.getRecipeStepContent()); + + // 스텝 이미지 처리 + if (step.getRecipeStepSource() != null) { + RecipeSourceInfo stepImage = new RecipeSourceInfo(); + stepImage.setFilePath(step.getRecipeStepSource().getRecipeStepSourceSave() + "/" + + step.getRecipeStepSource().getRecipeStepSourceServername()); + stepImage.setOriginalName(step.getRecipeStepSource().getRecipeStepSourceFileName()); + stepInfo.setImages(Collections.singletonList(stepImage)); + } else { + stepInfo.setImages(Collections.emptyList()); + } + + return stepInfo; + }) + .collect(Collectors.toList()); + response.setSteps(steps); + return response; }) .sorted(Comparator.comparingLong(RecipeRecommendResponse::getRemainExpirationDays)) .collect(Collectors.toList()); } + private RecipeSourceInfo convertToRecipeSourceInfo(RecipeSource source) { + RecipeSourceInfo info = new RecipeSourceInfo(); + info.setFilePath(source.getRecipeSourceSave() + "/" + source.getRecipeSourceServername()); + info.setOriginalName(source.getRecipeSourceFileName()); + return info; + } + private RecipeMatchResult checkRecipeMatch(Recipe recipe, List userIngredients) { List recipeIngredients = recipeIngredientRepository.findByRecipe(recipe); LocalDate currentDate = LocalDate.now(); diff --git a/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java b/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java index cfb1abd..c999a75 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/user/UserService.java @@ -1,5 +1,7 @@ package moja.refrigerator.service.user; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import moja.refrigerator.dto.user.request.PasswordResetRequest; import moja.refrigerator.dto.user.request.PasswordUpdateRequest; import moja.refrigerator.dto.user.request.UserCreateRequest; @@ -10,4 +12,5 @@ public interface UserService { void updateUser(UserUpdateRequest request); void resetPassword(PasswordResetRequest request); void updatePassword(PasswordUpdateRequest request); + void deleteUser(HttpServletRequest request, HttpServletResponse response); } diff --git a/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java b/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java index 7329781..7308101 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/user/UserServiceImpl.java @@ -1,5 +1,7 @@ package moja.refrigerator.service.user; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import moja.refrigerator.aggregate.user.User; import moja.refrigerator.dto.user.request.PasswordResetRequest; @@ -7,6 +9,7 @@ import moja.refrigerator.dto.user.request.UserCreateRequest; import moja.refrigerator.dto.user.request.UserUpdateRequest; import moja.refrigerator.exception.user.DuplicateUserException; +import moja.refrigerator.jwt.LogoutFilter; import moja.refrigerator.repository.user.UserRepository; import moja.refrigerator.service.email.EmailService; import org.modelmapper.ModelMapper; @@ -28,6 +31,7 @@ public class UserServiceImpl implements UserService { private final BCryptPasswordEncoder passwordEncoder; private final ModelMapper modelMapper; private final EmailService emailService; + private final LogoutFilter logoutFilter; @Override @Transactional @@ -114,6 +118,22 @@ public void updatePassword(PasswordUpdateRequest request) { user.setUserPw(passwordEncoder.encode(request.getNewPw())); } + @Override + @Transactional + public void deleteUser(HttpServletRequest request, HttpServletResponse response) { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + String userId = authentication.getName(); + + User user = userRepository.findByUserId(userId) + .orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다.")); + + // 유저 삭제 + userRepository.delete(user); + + // 로그아웃 처리 (토큰 블랙리스트에 추가) + logoutFilter.logout(request, response, authentication); + } + private void checkDuplicateUser(UserCreateRequest request) { List errors = new ArrayList<>(); if (userRepository.existsByUserId(request.getUserId())) {