From 5a7d838d9116bf9aa81485f3b6938d5da4e66c18 Mon Sep 17 00:00:00 2001 From: Hanvp Date: Fri, 23 Feb 2024 16:07:09 +0900 Subject: [PATCH] =?UTF-8?q?:white=5Fcheck=5Fmark:=20Refactor/321=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9A=B4?= =?UTF-8?q?=EC=98=81=20=EC=BD=94=EB=93=9C=EC=97=90=20=EC=A0=81=EC=9A=A9,?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 + .../server/converter/RecipeConverter.java | 333 ++---------------- .../server/domain/recipe/Recipe.java | 3 +- .../server/domain/recipe/TempRecipe.java | 9 +- .../server/service/RecipeService.java | 22 +- .../serviceImpl/RecipeServiceImpl.java | 247 ++----------- .../web/controller/RecipeRestController.java | 150 ++------ .../web/dto/requestDto/RecipeRequestDto.java | 40 +-- .../ZipdabangServerApplicationTests.java | 10 + .../server/converter/RecipeConverter.java | 319 +++++++++++++++++ .../server/domain/recipe/RecipeCategory.java | 28 ++ .../server/domain/test/TestComment.java | 0 .../server/domain/test/TestIngredient.java | 1 - .../server/domain/test/TestLikes.java | 0 .../server/domain/test/TestRecipe.java | 0 .../test/TestRecipeCategoryMapping.java | 0 .../server/domain/test/TestScrap.java | 0 .../server/domain/test/TestStep.java | 1 - .../RecipeCategoryRepository.java | 14 + .../TestIngredientRepository.java | 0 .../TestRecipeCategoryMappingRepository.java | 0 .../testRepository/TestRecipeRepository.java | 0 .../testRepository/TestStepRepository.java | 1 - .../TestRecipeRepositoryCustom.java | 1 - .../TestRecipeRepositoryImpl.java | 3 - .../server/service/RecipeService.java | 24 ++ .../serviceImpl/RecipeServiceImpl.java | 182 ++++++++++ .../web/controller/RecipeRestController.java | 17 + .../web/dto/requestDto/RecipeRequestDto.java | 56 +++ 29 files changed, 760 insertions(+), 703 deletions(-) create mode 100644 src/test/java/zipdabang/server/converter/RecipeConverter.java create mode 100644 src/test/java/zipdabang/server/domain/recipe/RecipeCategory.java rename src/{main => test}/java/zipdabang/server/domain/test/TestComment.java (100%) rename src/{main => test}/java/zipdabang/server/domain/test/TestIngredient.java (95%) rename src/{main => test}/java/zipdabang/server/domain/test/TestLikes.java (100%) rename src/{main => test}/java/zipdabang/server/domain/test/TestRecipe.java (100%) rename src/{main => test}/java/zipdabang/server/domain/test/TestRecipeCategoryMapping.java (100%) rename src/{main => test}/java/zipdabang/server/domain/test/TestScrap.java (100%) rename src/{main => test}/java/zipdabang/server/domain/test/TestStep.java (96%) create mode 100644 src/test/java/zipdabang/server/repository/recipeRepository/RecipeCategoryRepository.java rename src/{main => test}/java/zipdabang/server/repository/testRepository/TestIngredientRepository.java (100%) rename src/{main => test}/java/zipdabang/server/repository/testRepository/TestRecipeCategoryMappingRepository.java (100%) rename src/{main => test}/java/zipdabang/server/repository/testRepository/TestRecipeRepository.java (100%) rename src/{main => test}/java/zipdabang/server/repository/testRepository/TestStepRepository.java (92%) rename src/{main => test}/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java (92%) rename src/{main => test}/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java (93%) create mode 100644 src/test/java/zipdabang/server/service/RecipeService.java create mode 100644 src/test/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java create mode 100644 src/test/java/zipdabang/server/web/controller/RecipeRestController.java create mode 100644 src/test/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java diff --git a/build.gradle b/build.gradle index c975403..d29903e 100644 --- a/build.gradle +++ b/build.gradle @@ -47,6 +47,8 @@ dependencies { //FCM 의존성 implementation 'com.google.firebase:firebase-admin:9.1.1' implementation group: 'com.squareup.okhttp3', name: 'okhttp', version : '4.2.2' + testImplementation 'org.projectlombok:lombok:1.18.22' + testImplementation 'org.projectlombok:lombok:1.18.22' annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa" annotationProcessor "jakarta.annotation:jakarta.annotation-api" diff --git a/src/main/java/zipdabang/server/converter/RecipeConverter.java b/src/main/java/zipdabang/server/converter/RecipeConverter.java index 7c0c204..e9dfad5 100644 --- a/src/main/java/zipdabang/server/converter/RecipeConverter.java +++ b/src/main/java/zipdabang/server/converter/RecipeConverter.java @@ -2,10 +2,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.aspectj.weaver.ast.Test; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import zipdabang.server.apiPayload.code.CommonStatus; @@ -15,10 +12,6 @@ import zipdabang.server.domain.etc.Uuid; import zipdabang.server.domain.member.Member; import zipdabang.server.domain.recipe.*; -import zipdabang.server.domain.test.TestIngredient; -import zipdabang.server.domain.test.TestRecipe; -import zipdabang.server.domain.test.TestRecipeCategoryMapping; -import zipdabang.server.domain.test.TestStep; import zipdabang.server.service.RecipeService; import zipdabang.server.utils.converter.TimeConverter; import zipdabang.server.web.dto.requestDto.RecipeRequestDto; @@ -254,31 +247,19 @@ public static List toStep(RecipeRequestDto.CreateRecipeDto request, Recipe .collect(Collectors.toList()); } - public static List toTempStep(RecipeRequestDto.TempRecipeDto request, TempRecipe tempRecipe, List stepImages, List presentImageUrls) { + public static List toTempStep(RecipeRequestDto.SetRecipeWithImageUrlDto request, TempRecipe tempRecipe) { return request.getSteps().stream() - .map(step-> { - try { - return toTempStepDto(step, tempRecipe, stepImages, presentImageUrls); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) + .map(step-> toTempStepDto(step, tempRecipe)) .collect(Collectors.toList()); } - public static List toUpdateStep(RecipeRequestDto.UpdateRecipeDto request, Recipe recipe, List stepImages, List presentImageUrls) { + public static List toUpdateStep(RecipeRequestDto.SetRecipeWithImageUrlDto request, Recipe recipe) { return request.getSteps().stream() - .map(step-> { - try { - return toUpdateStepDto(step, recipe, stepImages, presentImageUrls); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) + .map(step-> toUpdateStepDto(step, recipe)) .collect(Collectors.toList()); } - private static Step toUpdateStepDto(RecipeRequestDto.UpdateStepDto step, Recipe recipe, List stepImages, List presentImageUrls) throws IOException { + private static Step toUpdateStepDto(RecipeRequestDto.StepWithImageUrlDto step, Recipe recipe) { Step updatedStep = Step.builder() .imageUrl(step.getStepUrl()) .stepNum(step.getStepNum()) @@ -286,31 +267,6 @@ private static Step toUpdateStepDto(RecipeRequestDto.UpdateStepDto step, Recipe .recipe(recipe) .build(); - - if(step.getStepUrl() == null) { - - if (stepImages != null) { - MultipartFile stepImage = null; - - for (int i = 0; i < stepImages.size(); i++) { - Integer imageNum = Integer.parseInt(stepImages.get(i).getOriginalFilename().substring(0, 1)) + 1; - if (imageNum == step.getStepNum()) { - stepImage = stepImages.get(i); - break; - } - } - - String imageUrl = null; - if (stepImage != null) { - imageUrl = uploadStepImage(stepImage); - updatedStep.setImage(imageUrl); - } - } - } - else{ - presentImageUrls.remove(step.getStepUrl()); - } - return updatedStep; } @@ -352,10 +308,11 @@ private static RecipeResponseDto.TempRecipeDto toTempRecipeInfo(TempRecipe tempR .build(); } - public static List toRecipeCategory(List categoryIds, Recipe recipe) { - return categoryIds.stream() + + public static CompletableFuture> toRecipeCategory(List categoryIds, Recipe recipe) { + return CompletableFuture.completedFuture(categoryIds.stream() .map(recipeCategoryId -> toRecipeCategoryMappingDto(recipeCategoryId, recipe)) - .collect(Collectors.toList()); + .collect(Collectors.toList())); } public static List toIngredient(RecipeRequestDto.CreateRecipeDto request, Recipe recipe) { @@ -364,13 +321,13 @@ public static List toIngredient(RecipeRequestDto.CreateRecipeDto req .collect(Collectors.toList()); } - public static List toUpdateIngredient(RecipeRequestDto.UpdateRecipeDto request, Recipe recipe) { + public static List toUpdateIngredient(RecipeRequestDto.SetRecipeWithImageUrlDto request, Recipe recipe) { return request.getIngredients().stream() .map(ingredient -> toIngredientDto(ingredient, recipe)) .collect(Collectors.toList()); } - public static List toTempIngredient(RecipeRequestDto.TempRecipeDto request, TempRecipe tempRecipe) { + public static List toTempIngredient(RecipeRequestDto.SetRecipeWithImageUrlDto request, TempRecipe tempRecipe) { return request.getIngredients().stream() .map(ingredient -> toTempIngredientDto(ingredient, tempRecipe)) .collect(Collectors.toList()); @@ -470,7 +427,7 @@ public static Recipe toRecipe(RecipeRequestDto.CreateRecipeDto request, Multipar return recipe; } - public static TempRecipe toTempRecipe(RecipeRequestDto.TempRecipeDto request, MultipartFile thumbnail, Member member) throws IOException { + public static TempRecipe toTempRecipe(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member) { TempRecipe tempRecipe = TempRecipe.builder() .name(request.getName()) @@ -478,14 +435,9 @@ public static TempRecipe toTempRecipe(RecipeRequestDto.TempRecipeDto request, Mu .recipeTip(request.getRecipeTip()) .time(request.getTime()) .member(member) + .thumbnailUrl(request.getThumbnailUrl()) .build(); - - String imageUrl = null; - if(thumbnail != null) - imageUrl = uploadThumbnail(thumbnail); - tempRecipe.setThumbnail(imageUrl); - return tempRecipe; } @@ -531,39 +483,15 @@ private static Step toStepDto(RecipeRequestDto.StepDto step, Recipe recipe, List return createdStep; } - private static TempStep toTempStepDto(RecipeRequestDto.TempStepDto step, TempRecipe tempRecipe, List stepImages, List presentImageUrls) throws IOException { + private static TempStep toTempStepDto(RecipeRequestDto.StepWithImageUrlDto step, TempRecipe tempRecipe) { TempStep createdTempStep = TempStep.builder() .imageUrl(step.getStepUrl()) .stepNum(step.getStepNum()) .description(step.getDescription()) .tempRecipe(tempRecipe) + .imageUrl(step.getStepUrl()) .build(); - - if(step.getStepUrl() == null) { - - if (stepImages != null) { - MultipartFile stepImage = null; - - for (int i = 0; i < stepImages.size(); i++) { - Integer imageNum = Integer.parseInt(stepImages.get(i).getOriginalFilename().substring(0, 1)) + 1; - if (imageNum == step.getStepNum()) { - stepImage = stepImages.get(i); - break; - } - } - - String imageUrl = null; - if (stepImage != null) { - imageUrl = uploadStepImage(stepImage); - createdTempStep.setImage(imageUrl); - } - } - } - else{ - presentImageUrls.remove(step.getStepUrl()); - } - return createdTempStep; } @@ -577,6 +505,7 @@ private static String uploadStepImage(MultipartFile stepImage) throws IOExceptio private static Ingredient toIngredientDto(RecipeRequestDto.NewIngredientDto ingredient, Recipe recipe) { + return Ingredient.builder() .name(ingredient.getIngredientName()) .quantity(ingredient.getQuantity()) @@ -702,94 +631,31 @@ public static ReportedComment toCommentReport(Report report, Comment comment, Me .build(); } - /** - * 부하 테스트용 - */ -// @Value("${cloud.aws.s3.user-default-image}") -// String userDefaultImage; - private static final ExecutorService ioExecutor = Executors.newFixedThreadPool(Math.min(Runtime.getRuntime().availableProcessors(), 8)); - public static RecipeResponseDto.RecipeStatusDto toTestRecipeStatusDto(TestRecipe recipe) { - return RecipeResponseDto.RecipeStatusDto.builder() - .recipeId(recipe.getId()) - .calledAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) - .build(); - } - - public static String uploadTestThumbnail(MultipartFile thumbnail) throws IOException { - Uuid uuid = staticAmazonS3Manager.createUUID(); - String keyName = staticAmazonS3Manager.generateTestThumbnailKeyName(uuid); - String fileUrl = staticAmazonS3Manager.uploadFile(keyName, thumbnail); - log.info("S3에 업로드 한 test thumbnail 파일의 url : {}", fileUrl); - return fileUrl; - } - - public static String uploadTestStep(MultipartFile stepImage) throws IOException { - Uuid uuid = staticAmazonS3Manager.createUUID(); - String keyName = staticAmazonS3Manager.generateTestStepKeyName(uuid); - String fileUrl = staticAmazonS3Manager.uploadFile(keyName, stepImage); - log.info("S3에 업로드 한 test step 파일의 url : {}", fileUrl); - return fileUrl; - } - - public static TestRecipe toTestRecipe(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail) throws IOException { - - CompletableFuture buildRecipe = new CompletableFuture<>(); - CompletableFuture setThumbnail = new CompletableFuture<>(); - - buildRecipe.complete(TestRecipe.builder() - .isBarista(false) - .name(request.getName()) - .intro(request.getIntro()) - .recipeTip(request.getRecipeTip()) - .time(request.getTime()) - .build()); - - if(thumbnail != null) - setThumbnail.complete(uploadTestThumbnail(thumbnail)); - else - throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); + private static final ExecutorService ioExecutor = Executors.newFixedThreadPool(Math.min(Runtime.getRuntime().availableProcessors(), 8)); - return buildRecipe.thenCombine(setThumbnail, (recipe, imageUrl) -> { - recipe.setThumbnail(imageUrl); - return recipe; - }).join(); - } - public static TestRecipe toTestRecipeWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request){ + public static Recipe toRecipeWithImageUrl(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member){ - return TestRecipe.builder() + return Recipe.builder() .isBarista(false) .name(request.getName()) .intro(request.getIntro()) .thumbnailUrl(request.getThumbnailUrl()) .recipeTip(request.getRecipeTip()) .time(request.getTime()) + .member(member) .build(); } - - public static CompletableFuture> toTestRecipeCategory(List categoryIds, TestRecipe recipe) { - return CompletableFuture.completedFuture(categoryIds.stream().parallel() - .map(recipeCategoryId -> toTestRecipeCategoryMappingDto(recipeCategoryId, recipe)) - .collect(Collectors.toList())); - } - - private static TestRecipeCategoryMapping toTestRecipeCategoryMappingDto(Long categoryId, TestRecipe recipe) { - return TestRecipeCategoryMapping.builder() - .category(staticRecipeService.getRecipeCategory(categoryId)) - .recipe(recipe) - .build(); - } - - public static CompletableFuture> toTestStep(RecipeRequestDto.CreateRecipeDto request, TestRecipe recipe, List stepImages) { + public static CompletableFuture> toStepWithImageUrl(RecipeRequestDto.SetRecipeWithImageUrlDto request, Recipe recipe) { return CompletableFuture.supplyAsync(() -> request.getSteps().stream().parallel() .map(step-> { if (step.getDescription() == null) throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); try { - return toTestStepDto(step, recipe, stepImages); + return toStepWithImageUrlDto(step, recipe); } catch (IOException e) { throw new RuntimeException(e); } @@ -798,53 +664,9 @@ public static CompletableFuture> toTestStep(RecipeRequestDto.Crea ); } - public static CompletableFuture> toTestStepWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request, TestRecipe recipe) { - return CompletableFuture.supplyAsync(() -> request.getSteps().stream().parallel() - .map(step-> { - if (step.getDescription() == null) - throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); - try { - return toTestStepWithImageUrlDto(step, recipe); - } catch (IOException e) { - throw new RuntimeException(e); - } - }) - .collect(Collectors.toList()), ioExecutor - ); - } - - private static TestStep toTestStepDto(RecipeRequestDto.StepDto step, TestRecipe recipe, List stepImages) throws IOException { - - CompletableFuture buildStep = new CompletableFuture<>(); - CompletableFuture setStep = new CompletableFuture<>(); - - buildStep.complete(TestStep.builder() - .stepNum(step.getStepNum()) - .description(step.getDescription()) - .recipe(recipe) - .build()); + private static Step toStepWithImageUrlDto(RecipeRequestDto.StepWithImageUrlDto step, Recipe recipe) throws IOException { - for (int i = 0; i <= stepImages.size(); i++) { - Integer imageNum = Integer.parseInt(stepImages.get(i).getOriginalFilename().substring(0,1)) + 1; - if (imageNum == step.getStepNum()){ - MultipartFile stepImage = stepImages.get(i); - setStep.complete(uploadTestStep(stepImage)); - break; - } - else if(i == stepImages.size()) - throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); - } - - return buildStep.thenCombine(setStep, (createStep, imageUrl) -> { - createStep.setImage(imageUrl); - return createStep; - }).join(); - - } - - private static TestStep toTestStepWithImageUrlDto(RecipeRequestDto.StepWithImageUrlDto step, TestRecipe recipe) throws IOException { - - return TestStep.builder() + return Step.builder() .stepNum(step.getStepNum()) .description(step.getDescription()) .imageUrl(step.getStepUrl()) @@ -852,112 +674,9 @@ private static TestStep toTestStepWithImageUrlDto(RecipeRequestDto.StepWithImage .build(); } - public static CompletableFuture> toTestIngredient(RecipeRequestDto.CreateRecipeDto request, TestRecipe recipe) { + public static CompletableFuture> toIngredientWithImageUrl(RecipeRequestDto.SetRecipeWithImageUrlDto request, Recipe recipe) { return CompletableFuture.completedFuture(request.getIngredients().stream().parallel() - .map(ingredient -> toTestIngredientDto(ingredient, recipe)) - .collect(Collectors.toList())); - } - - public static CompletableFuture> toTestIngredientWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request, TestRecipe recipe) { - return CompletableFuture.completedFuture(request.getIngredients().stream().parallel() - .map(ingredient -> toTestIngredientDto(ingredient, recipe)) + .map(ingredient -> toIngredientDto(ingredient, recipe)) .collect(Collectors.toList())); } - - private static TestIngredient toTestIngredientDto(RecipeRequestDto.NewIngredientDto ingredient, TestRecipe recipe) { - - return TestIngredient.builder() - .name(ingredient.getIngredientName()) - .quantity(ingredient.getQuantity()) - .recipe(recipe) - .build(); - } - - public static RecipeResponseDto.RecipeInfoDto toTestRecipeInfoDto(TestRecipe recipe) { - return RecipeResponseDto.RecipeInfoDto.builder() - .recipeInfo(toResponseTestRecipeDto(recipe)) - .ownerId(0L) - .isOwner(false) - .steps(toResponseTestStepDto(recipe)) - .ingredients(toResponseTestIngredientDto(recipe)) - .build(); - } - - public static RecipeResponseDto.RecipeDto toResponseTestRecipeDto(TestRecipe recipe){ - - return RecipeResponseDto.RecipeDto.builder() - .recipeId(recipe.getId()) - .categoryId(getTestCategoryIds(recipe)) - .recipeName(recipe.getName()) - .ownerImage("") - .nickname("test") - .thumbnailUrl(recipe.getThumbnailUrl()+"?size=thumbnail") - .time(recipe.getTime()) - .intro(recipe.getIntro()) - .recipeTip(recipe.getRecipeTip()) - .createdAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) - .updatedAt(staticTimeConverter.ConvertTime(recipe.getUpdatedAt())) - .likes(recipe.getTotalLike()) - .comments(0L) - .scraps(recipe.getTotalScrap()) - .isLiked(false) - .isScrapped(false) - .build(); - } - - public static List getTestCategoryIds(TestRecipe recipe){ - return recipe.getCategoryMappingList().stream() - .map(categoryMapping -> categoryMapping.getCategory().getId()) - .collect(Collectors.toList()); - } - - public static List toResponseTestStepDto(TestRecipe recipe) { - - return recipe.getStepList().stream() - .map(step-> RecipeResponseDto.StepDto.builder() - .stepNum(step.getStepNum()) - .description(step.getDescription()) - .image(step.getImageUrl()+"?size=step") - .build()) - .collect(Collectors.toList()); - } - - public static List toResponseTestIngredientDto(TestRecipe recipe) { - return recipe.getIngredientList().stream() - .map(ingredient -> RecipeResponseDto.IngredientDto.builder() - .IngredientName(ingredient.getName()) - .quantity(ingredient.getQuantity()) - .build()) - .collect(Collectors.toList()); - } - - public static RecipeResponseDto.RecipePageListDto toPagingTestRecipeDtoList(Page recipes) { - return RecipeResponseDto.RecipePageListDto.builder() - .recipeList(recipes.toList().stream() - .map(recipe -> toResponseTestRecipeSimpleDto(recipe)) - .collect(Collectors.toList())) - .totalElements(recipes.getTotalElements()) - .currentPageElements(recipes.getNumberOfElements()) - .totalPage(recipes.getTotalPages()) - .isFirst(recipes.isFirst()) - .isLast(recipes.isLast()) - .build(); - } - - private static RecipeResponseDto.RecipeSimpleDto toResponseTestRecipeSimpleDto(TestRecipe recipe) { - return RecipeResponseDto.RecipeSimpleDto.builder() - .recipeId(recipe.getId()) - .categoryId(getTestCategoryIds(recipe)) - .recipeName(recipe.getName()) - .nickname("test") - .thumbnailUrl(recipe.getThumbnailUrl()+"?size=preview") - .createdAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) - .updatedAt(staticTimeConverter.ConvertTime(recipe.getUpdatedAt())) - .comments(0L) - .likes(recipe.getTotalLike()) - .scraps(recipe.getTotalScrap()) - .isLiked(false) - .isScrapped(false) - .build(); - } } diff --git a/src/main/java/zipdabang/server/domain/recipe/Recipe.java b/src/main/java/zipdabang/server/domain/recipe/Recipe.java index e801f1f..77a5f8f 100644 --- a/src/main/java/zipdabang/server/domain/recipe/Recipe.java +++ b/src/main/java/zipdabang/server/domain/recipe/Recipe.java @@ -132,11 +132,12 @@ public Recipe updateView(){ return this; } - public Recipe updateInfo(RecipeRequestDto.UpdateRecipeDto request) { + public Recipe updateInfo(RecipeRequestDto.SetRecipeWithImageUrlDto request) { this.name = request.getName(); this.intro = request.getIntro(); this.recipeTip = request.getRecipeTip(); this.time = request.getTime(); + this.thumbnailUrl = request.getThumbnailUrl(); return this; } diff --git a/src/main/java/zipdabang/server/domain/recipe/TempRecipe.java b/src/main/java/zipdabang/server/domain/recipe/TempRecipe.java index 0531472..1432e66 100644 --- a/src/main/java/zipdabang/server/domain/recipe/TempRecipe.java +++ b/src/main/java/zipdabang/server/domain/recipe/TempRecipe.java @@ -55,17 +55,12 @@ public class TempRecipe extends BaseEntity { private List ingredientList; - public TempRecipe setThumbnail(String imageUrl) { - log.info("setThumbnail 호출됨"); - this.thumbnailUrl = imageUrl; - return this; - } - - public TempRecipe updateInfo(RecipeRequestDto.TempRecipeDto request) { + public TempRecipe updateInfo(RecipeRequestDto.SetRecipeWithImageUrlDto request) { this.name = request.getName(); this.intro = request.getIntro(); this.recipeTip = request.getRecipeTip(); this.time = request.getTime(); + this.thumbnailUrl =request.getThumbnailUrl(); return this; } diff --git a/src/main/java/zipdabang/server/service/RecipeService.java b/src/main/java/zipdabang/server/service/RecipeService.java index bb78f4c..8fd6f28 100644 --- a/src/main/java/zipdabang/server/service/RecipeService.java +++ b/src/main/java/zipdabang/server/service/RecipeService.java @@ -4,7 +4,6 @@ import org.springframework.web.multipart.MultipartFile; import zipdabang.server.domain.member.Member; import zipdabang.server.domain.recipe.*; -import zipdabang.server.domain.test.TestRecipe; import zipdabang.server.web.dto.requestDto.RecipeRequestDto; import zipdabang.server.web.dto.responseDto.RecipeResponseDto; @@ -39,9 +38,6 @@ public interface RecipeService { List> searchRecipePreview(String keyword, Member member); - - boolean checkRecipeCategoryExist(Long categoryId); - Boolean deleteRecipe(Long recipeId, Member member); Comment createComment(String content, Long recipeId, Member member); @@ -56,9 +52,9 @@ public interface RecipeService { Long reportRecipe(Long recipeId, Long reportId, Member member); - TempRecipe tempCreate(RecipeRequestDto.TempRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException; + TempRecipe tempCreate(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member); - TempRecipe tempUpdate(Long tempId, RecipeRequestDto.TempRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException; + TempRecipe tempUpdate(Long tempId, RecipeRequestDto.SetRecipeWithImageUrlDto request); List getTop5RecipePerCategory(Long categoryId); @@ -79,8 +75,6 @@ public interface RecipeService { Page getTempRecipeList(Integer pageIndex, Member member); - Recipe update(Long recipeId, RecipeRequestDto.UpdateRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException; - List getMyRecipePreview(Member member); Page getMyRecipeList(Integer pageIndex, Member member); @@ -97,19 +91,13 @@ public interface RecipeService { Long searchRecipeCounting(Long categoryId, String keyword, Member member); - Long getrecipeListByCategoryCounting(Long categoryId, Member member); + Long getRecipeListByCategoryCounting(Long categoryId, Member member); Long getWrittenByRecipeCounting(String writtenby, Member member); Long getCommentCount(Recipe recipe, Member member); - TestRecipe testCreate(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail, List stepImages) throws IOException; - - TestRecipe getTestRecipe(Long recipeId); - - Page testRecipeListByCategory(Long categoryId, Integer pageIndex, String order); - - Boolean deleteTestRecipe(); + Recipe createWithImageUrl(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member); - TestRecipe testCreateWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request); + Recipe update(Long recipeId, RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member); } diff --git a/src/main/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java b/src/main/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java index 46332c1..74dfa9f 100644 --- a/src/main/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java +++ b/src/main/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java @@ -21,8 +21,6 @@ import zipdabang.server.domain.inform.PushAlarm; import zipdabang.server.domain.member.*; import zipdabang.server.domain.recipe.*; -import zipdabang.server.domain.test.QTestRecipe; -import zipdabang.server.domain.test.TestRecipe; import zipdabang.server.firebase.fcm.service.FirebaseService; import zipdabang.server.repository.AlarmRepository.AlarmCategoryRepository; import zipdabang.server.repository.AlarmRepository.PushAlarmRepository; @@ -33,11 +31,6 @@ import zipdabang.server.repository.recipeRepositories.recipeRepositoryCustom.CommentRepositoryCustom; import zipdabang.server.repository.recipeRepositories.recipeRepositoryCustom.RecipeRepositoryCustom; import zipdabang.server.repository.recipeRepositories.recipeRepositoryCustom.TempRecipeRepositoryCustom; -import zipdabang.server.repository.testRepository.TestIngredientRepository; -import zipdabang.server.repository.testRepository.TestRecipeCategoryMappingRepository; -import zipdabang.server.repository.testRepository.TestRecipeRepository; -import zipdabang.server.repository.testRepository.TestStepRepository; -import zipdabang.server.repository.testRepository.testRecipeRepositoryCustom.TestRecipeRepositoryCustom; import zipdabang.server.service.RecipeService; import zipdabang.server.web.dto.requestDto.RecipeRequestDto; import zipdabang.server.web.dto.responseDto.RecipeResponseDto; @@ -46,7 +39,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Slf4j @@ -99,7 +91,7 @@ public Recipe create(RecipeRequestDto.CreateRecipeDto request, MultipartFile thu Recipe buildRecipe = RecipeConverter.toRecipe(request, thumbnail, member); Recipe recipe = recipeRepository.save(buildRecipe); - RecipeConverter.toRecipeCategory(request.getCategoryId(),recipe).stream() + RecipeConverter.toRecipeCategory(request.getCategoryId(),recipe).join().stream() .map(categoryMapping -> recipeCategoryMappingRepository.save(categoryMapping)) .collect(Collectors.toList()) .stream() @@ -123,7 +115,34 @@ public Recipe create(RecipeRequestDto.CreateRecipeDto request, MultipartFile thu @Override @Transactional(readOnly = false) - public Recipe update(Long recipeId, RecipeRequestDto.UpdateRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException { + public Recipe createWithImageUrl(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member){ + Recipe buildRecipe = RecipeConverter.toRecipeWithImageUrl(request, member); + recipeRepository.save(buildRecipe); + + RecipeConverter.toRecipeCategory(request.getCategoryId(),buildRecipe).join().stream() + .map(categoryMapping -> recipeCategoryMappingRepository.save(categoryMapping)) + .collect(Collectors.toList()) + .stream() + .map(categoryMapping -> categoryMapping.setRecipe(buildRecipe)); + + RecipeConverter.toStepWithImageUrl(request, buildRecipe).join().stream() + .map(step -> stepRepository.save(step)) + .collect(Collectors.toList()) + .stream() + .map(step -> step.setRecipe(buildRecipe)); + + RecipeConverter.toIngredientWithImageUrl(request, buildRecipe).join().stream() + .map(ingredient -> ingredientRepository.save(ingredient)) + .collect(Collectors.toList()) + .stream() + .map(ingredient -> ingredient.setRecipe(buildRecipe)); + + return buildRecipe; + } + + @Override + @Transactional(readOnly = false) + public Recipe update(Long recipeId, RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member) { log.info("service: ", request.toString()); Recipe recipe = recipeRepository.findById(recipeId).orElseThrow(() -> new RecipeException(CommonStatus.NO_RECIPE_EXIST)); @@ -133,34 +152,21 @@ public Recipe update(Long recipeId, RecipeRequestDto.UpdateRecipeDto request, Mu recipeCategoryMappingRepository.deleteAllByRecipe(recipe); - RecipeConverter.toRecipeCategory(request.getCategoryId(),recipe).stream() + RecipeConverter.toRecipeCategory(request.getCategoryId(),recipe).join().stream() .map(categoryMapping -> recipeCategoryMappingRepository.save(categoryMapping)) .collect(Collectors.toList()) .stream() .map(categoryMapping -> categoryMapping.setRecipe(recipe)); //recipe - String deleteThumbnailUrl = null; - String newThumbnailUrl = null; - if (thumbnail != null) { - deleteThumbnailUrl = recipe.getThumbnailUrl(); - newThumbnailUrl = RecipeConverter.uploadThumbnail(thumbnail); - recipe.setThumbnail(newThumbnailUrl); - } - recipe.updateInfo(request); //step - List presentImageUrls = stepRepository.findAllByRecipeId(recipeId).stream() - .filter(steps -> steps.getImageUrl() != null) - .map(tempStep -> tempStep.getImageUrl()) - .collect(Collectors.toList()); - stepRepository.deleteAllByRecipe(recipe); - RecipeConverter.toUpdateStep(request, recipe, stepImages, presentImageUrls).stream() + RecipeConverter.toUpdateStep(request, recipe).stream() .map(step -> stepRepository.save(step)) .collect(Collectors.toList()) .stream() @@ -177,30 +183,19 @@ public Recipe update(Long recipeId, RecipeRequestDto.UpdateRecipeDto request, Mu .map(ingredient -> ingredient.setRecipe(recipe)); - //s3 삭제는 맨 마지막에 - if (deleteThumbnailUrl != null) - amazonS3Manager.deleteFile(RecipeConverter.toKeyName(deleteThumbnailUrl).substring(1)); - - if(!presentImageUrls.isEmpty()) - presentImageUrls.forEach(imageUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(imageUrl).substring(1))); - - return recipe; } @Override @Transactional(readOnly = false) - public TempRecipe tempCreate(RecipeRequestDto.TempRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException { - + public TempRecipe tempCreate(RecipeRequestDto.SetRecipeWithImageUrlDto request, Member member){ log.info("service: ", request.toString()); - TempRecipe buildTempRecipe = RecipeConverter.toTempRecipe(request, thumbnail, member); + TempRecipe buildTempRecipe = RecipeConverter.toTempRecipe(request, member); TempRecipe tempRecipe = tempRecipeRepository.save(buildTempRecipe); - List presentImageUrls = new ArrayList<>(); - if (request.getStepCount() > 0) { - RecipeConverter.toTempStep(request, tempRecipe, stepImages, presentImageUrls).stream() + RecipeConverter.toTempStep(request, tempRecipe).stream() .map(step -> tempStepRepository.save(step)) .collect(Collectors.toList()) .stream() @@ -220,41 +215,20 @@ public TempRecipe tempCreate(RecipeRequestDto.TempRecipeDto request, MultipartFi @Override @Transactional(readOnly = false) - public TempRecipe tempUpdate(Long tempId, RecipeRequestDto.TempRecipeDto request, MultipartFile thumbnail, List stepImages, Member member) throws IOException { + public TempRecipe tempUpdate(Long tempId, RecipeRequestDto.SetRecipeWithImageUrlDto request) { log.info("service: ", request.toString()); TempRecipe tempRecipe = tempRecipeRepository.findById(tempId).orElseThrow(() -> new RecipeException(CommonStatus.NO_TEMP_RECIPE_EXIST)); //recipe - String deleteThumbnailUrl = null; - String newThumbnailUrl = null; - if (thumbnail != null) { - if (tempRecipe.getThumbnailUrl() != null) - deleteThumbnailUrl = tempRecipe.getThumbnailUrl(); - newThumbnailUrl = RecipeConverter.uploadThumbnail(thumbnail); - } - else{ - if (request.getThumbnailUrl() == null && tempRecipe.getThumbnailUrl() != null) - deleteThumbnailUrl = tempRecipe.getThumbnailUrl(); - else if (request.getThumbnailUrl() != null) - newThumbnailUrl = request.getThumbnailUrl(); - } - - tempRecipe.setThumbnail(newThumbnailUrl); tempRecipe.updateInfo(request); - //step - List presentImageUrls = tempStepRepository.findAllByTempRecipe(tempRecipe).stream() - .filter(steps -> steps.getImageUrl() != null) - .map(tempStep -> tempStep.getImageUrl()) - .collect(Collectors.toList()); - tempStepRepository.deleteAllByTempRecipe(tempRecipe); if(request.getStepCount() > 0) { - RecipeConverter.toTempStep(request, tempRecipe, stepImages, presentImageUrls).stream() + RecipeConverter.toTempStep(request, tempRecipe).stream() .map(step -> tempStepRepository.save(step)) .collect(Collectors.toList()) .stream() @@ -275,12 +249,6 @@ else if (request.getThumbnailUrl() != null) tempIngredientRepository.deleteAllByTempRecipe(tempRecipe); } - //s3 삭제는 맨 마지막에 - if (deleteThumbnailUrl != null) - amazonS3Manager.deleteFile(RecipeConverter.toKeyName(deleteThumbnailUrl).substring(1)); - if(!presentImageUrls.isEmpty()) - presentImageUrls.forEach(imageUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(imageUrl).substring(1))); - return tempRecipe; } @@ -334,7 +302,7 @@ public Recipe createFromTempRecipe(Long tempId, RecipeRequestDto.RecipeCategoryL Recipe recipe = recipeRepository.save(RecipeConverter.toRecipeFromTemp(tempRecipe, tempSteps, tempIngredients, member)); - RecipeConverter.toRecipeCategory(categoryList.getCategoryId(),recipe).stream() + RecipeConverter.toRecipeCategory(categoryList.getCategoryId(),recipe).join().stream() .map(categoryMapping -> recipeCategoryMappingRepository.save(categoryMapping)) .collect(Collectors.toList()) .stream() @@ -583,7 +551,7 @@ public Page recipeListByCategory(Long categoryId, Integer pageIndex, Mem } @Override - public Long getrecipeListByCategoryCounting(Long categoryId, Member member) { + public Long getRecipeListByCategoryCounting(Long categoryId, Member member) { List recipeCategory = recipeCategoryRepository.findAllById(categoryId); @@ -596,11 +564,6 @@ public Long getrecipeListByCategoryCounting(Long categoryId, Member member) { return count; } - @Override - public boolean checkRecipeCategoryExist(Long categoryId) { - return recipeCategoryRepository.existsById(categoryId); - } - @Override public List> searchRecipePreview(String keyword, Member member) { Long recipeCategorySize = recipeCategoryRepository.count()-1; @@ -895,138 +858,4 @@ public RecipeCategory getRecipeCategory(Long categoryId) { return recipeCategoryRepository.findById(categoryId).get(); } - /** - * 부하테스트용 서비스 - */ - private final TestRecipeRepository testRecipeRepository; - private final TestRecipeCategoryMappingRepository testRecipeCategoryMappingRepository; - private final TestStepRepository testStepRepository; - private final TestIngredientRepository testIngredientRepository; - private final TestRecipeRepositoryCustom testRecipeRepositoryCustom; - - @Override - @Transactional(readOnly = false) - public TestRecipe testCreate(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail, List stepImages) throws IOException { - - CompletableFuture savedRecipeFuture = CompletableFuture.supplyAsync(() ->{ - TestRecipe buildRecipe = null; - try { - buildRecipe = RecipeConverter.toTestRecipe(request, thumbnail); - } catch (IOException e) { - throw new RuntimeException(e); - } - return testRecipeRepository.save(buildRecipe); - }); - - savedRecipeFuture.thenAccept(recipe -> { - RecipeConverter.toTestRecipeCategory(request.getCategoryId(),recipe).join().stream() - .map(categoryMapping -> testRecipeCategoryMappingRepository.save(categoryMapping)) - .collect(Collectors.toList()) - .stream() - .map(categoryMapping -> categoryMapping.setRecipe(recipe)); - }); - - - savedRecipeFuture.thenAccept(recipe -> { - RecipeConverter.toTestStep(request, recipe, stepImages).join().stream() - .map(step -> testStepRepository.save(step)) - .collect(Collectors.toList()) - .stream() - .map(step -> step.setRecipe(recipe)); - }); - - savedRecipeFuture.thenAccept(recipe -> { - RecipeConverter.toTestIngredient(request, recipe).join().stream() - .map(ingredient -> testIngredientRepository.save(ingredient)) - .collect(Collectors.toList()) - .stream() - .map(ingredient -> ingredient.setRecipe(recipe)); - }); - - return savedRecipeFuture.join(); - } - - @Override - @Transactional(readOnly = false) - public TestRecipe testCreateWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request){ - TestRecipe buildRecipe = RecipeConverter.toTestRecipeWithImageUrl(request); - testRecipeRepository.save(buildRecipe); - - RecipeConverter.toTestRecipeCategory(request.getCategoryId(),buildRecipe).join().stream() - .map(categoryMapping -> testRecipeCategoryMappingRepository.save(categoryMapping)) - .collect(Collectors.toList()) - .stream() - .map(categoryMapping -> categoryMapping.setRecipe(buildRecipe)); - - RecipeConverter.toTestStepWithImageUrl(request, buildRecipe).join().stream() - .map(step -> testStepRepository.save(step)) - .collect(Collectors.toList()) - .stream() - .map(step -> step.setRecipe(buildRecipe)); - - RecipeConverter.toTestIngredientWithImageUrl(request, buildRecipe).join().stream() - .map(ingredient -> testIngredientRepository.save(ingredient)) - .collect(Collectors.toList()) - .stream() - .map(ingredient -> ingredient.setRecipe(buildRecipe)); - - return buildRecipe; - } - - @Override - public TestRecipe getTestRecipe(Long recipeId) { - TestRecipe findRecipe = testRecipeRepository.findById(recipeId).orElseThrow(()->new RecipeException(CommonStatus.NO_RECIPE_EXIST)); - - findRecipe.updateView(); - return findRecipe; - } - - @Transactional - @Override - public Page testRecipeListByCategory(Long categoryId, Integer pageIndex, String order) { - - List recipeCategory = recipeCategoryRepository.findAllById(categoryId); - - if(recipeCategory.isEmpty()) - throw new RecipeException(CommonStatus.RECIPE_NOT_FOUND); - - List content = new ArrayList<>(); - - BooleanExpression whereCondition = testRecipeRepositoryCustom.recipesInCategoryCondition(categoryId); - - - content = testRecipeRepositoryCustom.testRecipesOrderBy(pageIndex,pageSize, order, whereCondition); - - log.info("서비스단의 상황 : {}", content.size()); - Long count = testRecipeRepositoryCustom.testRecipeTotalCount(whereCondition); - - if (count < pageIndex*pageSize) - throw new RecipeException(CommonStatus.OVER_PAGE_INDEX_ERROR); - if (content.size() > count - pageIndex*pageSize) - content = content.subList(0, count.intValue()-pageIndex*pageSize); - - return new PageImpl<>(content,PageRequest.of(pageIndex,pageSize), count); - } - - @Transactional(readOnly = false) - @Override - public Boolean deleteTestRecipe() { - List findRecipes = testRecipeRepository.findAll(); - - List thumbnailUrls = findRecipes.stream().parallel() - .map(recipe -> recipe.getThumbnailUrl()).collect(Collectors.toList()); - List stepUrlList = testStepRepository.findAll().stream().parallel() - .filter(steps -> steps.getImageUrl() != null) - .map(step -> step.getImageUrl()) - .collect(Collectors.toList()); - - testRecipeRepository.deleteAll(); - - thumbnailUrls.parallelStream().forEach(thumbnailUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(thumbnailUrl).substring(1))); - stepUrlList.parallelStream() - .forEach(stepUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(stepUrl).substring(1))); - - return testRecipeRepository.count() == 0; - - } } diff --git a/src/main/java/zipdabang/server/web/controller/RecipeRestController.java b/src/main/java/zipdabang/server/web/controller/RecipeRestController.java index a7980a3..e5f2a22 100644 --- a/src/main/java/zipdabang/server/web/controller/RecipeRestController.java +++ b/src/main/java/zipdabang/server/web/controller/RecipeRestController.java @@ -22,7 +22,6 @@ import zipdabang.server.converter.RecipeConverter; import zipdabang.server.domain.member.Member; import zipdabang.server.domain.recipe.*; -import zipdabang.server.domain.test.TestRecipe; import zipdabang.server.service.RecipeService; import zipdabang.server.validation.annotation.CheckPage; import zipdabang.server.validation.annotation.CheckTempMember; @@ -43,6 +42,32 @@ private final RecipeService recipeService; +// @Operation(summary = "🍹figma 레시피 작성하기1, 레시피 등록 API 🔑 ✔", description = "레시피 (작성)등록 화면 API입니다. 임시저장 api는 별도로 있음. step이랑 ingredient 몇개 들어오는지 각Count에 적어주세요") +// @ApiResponses({ +// @ApiResponse(responseCode = "2000"), +// @ApiResponse(responseCode = "4003", description = "UNAUTHORIZED, 토큰 모양이 이상함, 토큰 제대로 주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// @ApiResponse(responseCode = "4005", description = "UNAUTHORIZED, 엑세스 토큰 만료, 리프레시 토큰 사용", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// @ApiResponse(responseCode = "4008", description = "UNAUTHORIZED, 토큰 없음, 토큰 줘요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// @ApiResponse(responseCode = "4052", description = "BAD_REQUEST, 사용자가 없습니다. 이 api에서 이거 생기면 백앤드 개발자 호출", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// @ApiResponse(responseCode = "4100", description = "레시피 작성시 누락된 내용이 있습니다. 미완료는 임시저장으로 가세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// @ApiResponse(responseCode = "5000", description = "SERVER ERROR, 백앤드 개발자에게 알려주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), +// }) +// @Parameters({ +// @Parameter(name = "member", hidden = true), +// }) +// @PostMapping(value = "/members/recipes") +// public ResponseDto createRecipe( +// @RequestPart(value = "content") RecipeRequestDto.CreateRecipeDto request, +// @RequestPart(value = "thumbnail") MultipartFile thumbnail, +// @RequestPart(value = "stepImages") List stepImages, +// @CheckTempMember @AuthMember Member member) throws IOException { +// +// log.info("사용자가 준 정보 : {}", request.toString()); +// +// Recipe recipe = recipeService.create(request, thumbnail, stepImages, member); +// return ResponseDto.of(RecipeConverter.toRecipeStatusDto(recipe)); +// } + @Operation(summary = "🍹figma 레시피 작성하기1, 레시피 등록 API 🔑 ✔", description = "레시피 (작성)등록 화면 API입니다. 임시저장 api는 별도로 있음. step이랑 ingredient 몇개 들어오는지 각Count에 적어주세요") @ApiResponses({ @ApiResponse(responseCode = "2000"), @@ -58,14 +83,12 @@ }) @PostMapping(value = "/members/recipes") public ResponseDto createRecipe( - @RequestPart(value = "content") RecipeRequestDto.CreateRecipeDto request, - @RequestPart(value = "thumbnail") MultipartFile thumbnail, - @RequestPart(value = "stepImages") List stepImages, + @RequestBody RecipeRequestDto.SetRecipeWithImageUrlDto request, @CheckTempMember @AuthMember Member member) throws IOException { log.info("사용자가 준 정보 : {}", request.toString()); - Recipe recipe = recipeService.create(request, thumbnail, stepImages, member); + Recipe recipe = recipeService.createWithImageUrl(request, member); return ResponseDto.of(RecipeConverter.toRecipeStatusDto(recipe)); } @@ -86,14 +109,12 @@ public ResponseDto createRecipe( @PatchMapping(value = "/members/recipes/{recipeId}") public ResponseDto updateRecipe( @PathVariable(name = "recipeId") Long recipeId, - @RequestPart(value = "content") RecipeRequestDto.UpdateRecipeDto request, - @RequestPart(value = "thumbnail", required = false) MultipartFile thumbnail, - @RequestPart(value = "stepImages", required = false) List stepImages, + @RequestBody RecipeRequestDto.SetRecipeWithImageUrlDto request, @CheckTempMember @AuthMember Member member) throws IOException { log.info("사용자가 준 정보 : {}", request.toString()); - Recipe recipe = recipeService.update(recipeId, request, thumbnail, stepImages, member); + Recipe recipe = recipeService.update(recipeId, request, member); return ResponseDto.of(RecipeConverter.toRecipeStatusDto(recipe)); } @@ -113,9 +134,7 @@ public ResponseDto updateRecipe( @PostMapping(value = {"/members/recipes/temp/{tempId}", "/members/recipes/temp"}) public ResponseDto createTempRecipe( @PathVariable(required = false) Long tempId, - @RequestPart(value = "content") RecipeRequestDto.TempRecipeDto request, - @RequestPart(value = "thumbnail", required = false) MultipartFile thumbnail, - @RequestPart(value = "stepImages", required = false) List stepImages, + @RequestBody RecipeRequestDto.SetRecipeWithImageUrlDto request, @CheckTempMember @AuthMember Member member) throws IOException { log.info("사용자가 준 정보 : {}", request.toString()); @@ -123,9 +142,9 @@ public ResponseDto createTempRecipe( TempRecipe tempRecipe; if (tempId==null) - tempRecipe = recipeService.tempCreate(request, thumbnail, stepImages, member); + tempRecipe = recipeService.tempCreate(request, member); else - tempRecipe = recipeService.tempUpdate(tempId, request, thumbnail, stepImages, member); + tempRecipe = recipeService.tempUpdate(tempId, request); return ResponseDto.of(RecipeConverter.toTempRecipeStatusDto(tempRecipe)); } @@ -455,7 +474,7 @@ public ResponseDto recipeListByCategory(@Ex }) @GetMapping(value = "/members/recipes/categories/{categoryId}/count") public ResponseDto recipeListByCategoryCounting(@ExistRecipeCategory @PathVariable Long categoryId, @AuthMember Member member){ - Long totalCount = recipeService.getrecipeListByCategoryCounting(categoryId, member); + Long totalCount = recipeService.getRecipeListByCategoryCounting(categoryId, member); return ResponseDto.of(totalCount); } @@ -956,105 +975,4 @@ else if (page < 1) return ResponseDto.of(recipeService.getScrapRecipes(page, member)); } - /** - * 부하 테스트용 컨트롤러 - */ - @Operation(summary = "레시피 등록 테스트 API 🔑 ✔") - @ApiResponses({ - @ApiResponse(responseCode = "2000"), - @ApiResponse(responseCode = "4100", description = "레시피 작성시 누락된 내용이 있습니다. 미완료는 임시저장으로 가세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "5000", description = "SERVER ERROR, 백앤드 개발자에게 알려주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - }) -// @PostMapping(value = "/test/members/recipes") - public ResponseDto testCreateRecipe( - @RequestPart(value = "content") RecipeRequestDto.CreateRecipeDto request, - @RequestPart(value = "thumbnail") MultipartFile thumbnail, - @RequestPart(value = "stepImages") List stepImages) throws IOException { - - log.info("사용자가 준 정보 : {}", request.toString()); - - TestRecipe recipe = recipeService.testCreate(request, thumbnail, stepImages); - return ResponseDto.of(RecipeConverter.toTestRecipeStatusDto(recipe)); - } - - @Operation(summary = "레시피 등록 테스트-image url만 넘겨받기 API 🔑 ✔") - @ApiResponses({ - @ApiResponse(responseCode = "2000"), - @ApiResponse(responseCode = "4100", description = "레시피 작성시 누락된 내용이 있습니다. 미완료는 임시저장으로 가세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "5000", description = "SERVER ERROR, 백앤드 개발자에게 알려주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - }) - @PostMapping(value = "/test/members/recipes") - public ResponseDto testCreateRecipeWithImageURL( - @RequestBody RecipeRequestDto.CreateRecipeWithImageUrlDto request) throws IOException { - - log.info("사용자가 준 정보 : {}", request.toString()); - - TestRecipe recipe = recipeService.testCreateWithImageUrl(request); - return ResponseDto.of(RecipeConverter.toTestRecipeStatusDto(recipe)); - } - - @Operation(summary = "레시피 상세 정보 조회 테스트 API 🔑 ✔") - @ApiResponses({ - @ApiResponse(responseCode = "2000"), - @ApiResponse(responseCode = "4101", description = "BAD_REQUEST, 해당 recipeId를 가진 recipe가 없어요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "5000", description = "SERVER ERROR, 백앤드 개발자에게 알려주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - }) - @GetMapping(value = "/test/members/recipes/{recipeId}") - public ResponseDto testRecipeDetail(@PathVariable(name = "recipeId") Long recipeId) { - - TestRecipe recipe = recipeService.getTestRecipe(recipeId); - - return ResponseDto.of(RecipeConverter.toTestRecipeInfoDto(recipe)); - } - - @Operation(summary = "카테고리 별 레시피 목록 조회 테스트 API 🔑 ✔") - @ApiResponses({ - @ApiResponse(responseCode = "2000", description = "OK, 목록이 있을 땐 이 응답임"), - @ApiResponse(responseCode = "2100", description = "OK, 목록이 없을 경우, result = null", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "4053", description = "BAD_REQUEST, 넘겨받은 categoryId와 일치하는 카테고리 없음. 1~6 사이로 보내세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "4055", description = "BAD_REQUEST, 페이지 인덱스 범위 초과함", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "4104", description = "BAD_REQUEST, 조회 방식 타입이 잘못되었습니다. likes, follow, lastest중 하나로 보내주세요.", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "4105", description = "BAD_REQUEST, 해당 id를 가진 레시피 카테고리가 없습니다. 잘못 보내줬어요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "5000", description = "SERVER ERROR, 백앤드 개발자에게 알려주세요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - }) - @Parameters({ - @Parameter(name = "pageIndex", description = "query string 페이지 번호, 무조건 값 줘야 함, 0 이런거 주면 에러 뱉음"), - @Parameter(name = "order", description = "query string 조회 방식. 인기순: likes, 팔로우순: follow, 최신순: latest로 넘겨주세요") - }) - @GetMapping(value = "/test/members/recipes/categories/{categoryId}") - public ResponseDto testRecipeListByCategory(@ExistRecipeCategory @PathVariable Long categoryId, @CheckPage @RequestParam(name = "pageIndex") Integer pageIndex) { - if (pageIndex == null) - pageIndex = 1; - - pageIndex -= 1; - - Page recipes = recipeService.testRecipeListByCategory(categoryId, pageIndex, "latest"); - - - log.info(recipes.toString()); - - if (recipes.getTotalElements() == 0) - throw new RecipeException(CommonStatus.RECIPE_NOT_FOUND); - if (pageIndex >= recipes.getTotalPages()) - throw new RecipeException(CommonStatus.OVER_PAGE_INDEX_ERROR); - - return ResponseDto.of(RecipeConverter.toPagingTestRecipeDtoList(recipes)); - } - - @Operation(summary = "테스트 레시피 삭제 API 🔑 ✔") - @ApiResponses({ - @ApiResponse(responseCode = "2000", description = "OK, 삭제처리 되었습니다."), - @ApiResponse(responseCode = "4101", description = "BAD_REQUEST, 해당 recipeId를 가진 recipe가 없어요", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - @ApiResponse(responseCode = "5100", description = "SERVER ERROR, 레시피가 삭제되지 않았습니다.", content = @Content(schema = @Schema(implementation = ResponseDto.class))), - }) - - @DeleteMapping("/test/members/recipes") - public ResponseDto deleteTestRecipe() { - Boolean recipeDeleteBoolean = recipeService.deleteTestRecipe(); - - if (recipeDeleteBoolean) - return ResponseDto.of(" 레시피 삭제 완료"); - else - throw new RecipeException(CommonStatus.RECIPE_NOT_DELETED); - } } diff --git a/src/main/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java b/src/main/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java index eafd8cc..01d1ab7 100644 --- a/src/main/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java +++ b/src/main/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java @@ -1,13 +1,8 @@ package zipdabang.server.web.dto.requestDto; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; -import org.springframework.web.multipart.MultipartFile; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.List; public class RecipeRequestDto { @@ -31,7 +26,7 @@ public static class CreateRecipeDto{ } @Getter @Setter - public static class CreateRecipeWithImageUrlDto{ + public static class SetRecipeWithImageUrlDto { List categoryId; String name; String time; @@ -44,33 +39,6 @@ public static class CreateRecipeWithImageUrlDto{ List ingredients; } - @Getter @Setter - public static class UpdateRecipeDto{ - List categoryId; - String name; - String time; - String intro; - String recipeTip; - Integer stepCount; - Integer ingredientCount; - List steps; - List ingredients; - } - - @Getter @Setter - public static class TempRecipeDto{ - - String thumbnailUrl; - String name; - String time; - String intro; - String recipeTip; - Integer stepCount; - Integer ingredientCount; - List steps; - List ingredients; - } - @Getter public static class NewIngredientDto{ private String ingredientName; @@ -97,12 +65,6 @@ public static class UpdateStepDto{ private String description; } - @Getter - public static class TempStepDto{ - private String stepUrl; - private Integer stepNum; - private String description; - } @Getter public static class createCommentDto { diff --git a/src/test/java/zipdabang/server/ZipdabangServerApplicationTests.java b/src/test/java/zipdabang/server/ZipdabangServerApplicationTests.java index 92dc9c5..b8fdb09 100644 --- a/src/test/java/zipdabang/server/ZipdabangServerApplicationTests.java +++ b/src/test/java/zipdabang/server/ZipdabangServerApplicationTests.java @@ -1,13 +1,23 @@ package zipdabang.server; import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.web.servlet.MockMvc; @SpringBootTest +@AutoConfigureMockMvc class ZipdabangServerApplicationTests { + private MockMvc mockMvc; + @Test void contextLoads() { } + @Test + public void testControllerApi() throws Exception { + //mockMvc.perform(); + } + } diff --git a/src/test/java/zipdabang/server/converter/RecipeConverter.java b/src/test/java/zipdabang/server/converter/RecipeConverter.java new file mode 100644 index 0000000..bf68523 --- /dev/null +++ b/src/test/java/zipdabang/server/converter/RecipeConverter.java @@ -0,0 +1,319 @@ +package zipdabang.server.converter; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; +import zipdabang.server.apiPayload.code.CommonStatus; +import zipdabang.server.apiPayload.exception.handler.RecipeException; +import zipdabang.server.aws.s3.AmazonS3Manager; +import zipdabang.server.domain.etc.Uuid; +import zipdabang.server.domain.test.TestIngredient; +import zipdabang.server.domain.test.TestRecipe; +import zipdabang.server.domain.test.TestRecipeCategoryMapping; +import zipdabang.server.domain.test.TestStep; +import zipdabang.server.service.RecipeService; +import zipdabang.server.utils.converter.TimeConverter; +import zipdabang.server.web.dto.requestDto.RecipeRequestDto; +import zipdabang.server.web.dto.responseDto.RecipeResponseDto; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +@Slf4j +@Component +@RequiredArgsConstructor +public class RecipeConverter { + + private final AmazonS3Manager amazonS3Manager; + private final TimeConverter timeConverter; + private final RecipeService recipeService; + + + private static AmazonS3Manager staticAmazonS3Manager; + private static TimeConverter staticTimeConverter; + private static RecipeService staticRecipeService; + + + @PostConstruct + public void init() { + this.staticAmazonS3Manager = this.amazonS3Manager; + this.staticTimeConverter = this.timeConverter; + this.staticRecipeService = this.recipeService; + } + + public static String toKeyName(String imageUrl) { + String input = imageUrl; + + Pattern regex = Pattern.compile(staticAmazonS3Manager.getPattern()); + Matcher matcher = regex.matcher(input); + String extractedString = null; + if (matcher.find()) + extractedString = matcher.group(1); + + return extractedString; + + } + + private static final ExecutorService ioExecutor = Executors.newFixedThreadPool(Math.min(Runtime.getRuntime().availableProcessors(), 8)); + + public static RecipeResponseDto.RecipeStatusDto toTestRecipeStatusDto(TestRecipe recipe) { + return RecipeResponseDto.RecipeStatusDto.builder() + .recipeId(recipe.getId()) + .calledAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) + .build(); + } + + public static String uploadTestThumbnail(MultipartFile thumbnail) throws IOException { + Uuid uuid = staticAmazonS3Manager.createUUID(); + String keyName = staticAmazonS3Manager.generateTestThumbnailKeyName(uuid); + String fileUrl = staticAmazonS3Manager.uploadFile(keyName, thumbnail); + log.info("S3에 업로드 한 test thumbnail 파일의 url : {}", fileUrl); + return fileUrl; + } + + public static String uploadTestStep(MultipartFile stepImage) throws IOException { + Uuid uuid = staticAmazonS3Manager.createUUID(); + String keyName = staticAmazonS3Manager.generateTestStepKeyName(uuid); + String fileUrl = staticAmazonS3Manager.uploadFile(keyName, stepImage); + log.info("S3에 업로드 한 test step 파일의 url : {}", fileUrl); + return fileUrl; + } + + public static TestRecipe toTestRecipe(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail) throws IOException { + + CompletableFuture buildRecipe = new CompletableFuture<>(); + CompletableFuture setThumbnail = new CompletableFuture<>(); + + buildRecipe.complete(TestRecipe.builder() + .isBarista(false) + .name(request.getName()) + .intro(request.getIntro()) + .recipeTip(request.getRecipeTip()) + .time(request.getTime()) + .build()); + + if(thumbnail != null) + setThumbnail.complete(uploadTestThumbnail(thumbnail)); + else + throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); + + return buildRecipe.thenCombine(setThumbnail, (recipe, imageUrl) -> { + recipe.setThumbnail(imageUrl); + return recipe; + }).join(); + } + + public static TestRecipe toTestRecipeWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request){ + + return TestRecipe.builder() + .isBarista(false) + .name(request.getName()) + .intro(request.getIntro()) + .thumbnailUrl(request.getThumbnailUrl()) + .recipeTip(request.getRecipeTip()) + .time(request.getTime()) + .build(); + } + + + public static CompletableFuture> toTestRecipeCategory(List categoryIds, TestRecipe recipe) { + return CompletableFuture.completedFuture(categoryIds.stream().parallel() + .map(recipeCategoryId -> toTestRecipeCategoryMappingDto(recipeCategoryId, recipe)) + .collect(Collectors.toList())); + } + + private static TestRecipeCategoryMapping toTestRecipeCategoryMappingDto(Long categoryId, TestRecipe recipe) { + return TestRecipeCategoryMapping.builder() + .category(staticRecipeService.getRecipeCategory(categoryId)) + .recipe(recipe) + .build(); + } + + public static CompletableFuture> toTestStep(RecipeRequestDto.CreateRecipeDto request, TestRecipe recipe, List stepImages) { + return CompletableFuture.supplyAsync(() -> request.getSteps().stream().parallel() + .map(step-> { + if (step.getDescription() == null) + throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); + try { + return toTestStepDto(step, recipe, stepImages); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()), ioExecutor + ); + } + + public static CompletableFuture> toTestStepWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request, TestRecipe recipe) { + return CompletableFuture.supplyAsync(() -> request.getSteps().stream().parallel() + .map(step-> { + if (step.getDescription() == null) + throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); + try { + return toTestStepWithImageUrlDto(step, recipe); + } catch (IOException e) { + throw new RuntimeException(e); + } + }) + .collect(Collectors.toList()), ioExecutor + ); + } + + private static TestStep toTestStepDto(RecipeRequestDto.StepDto step, TestRecipe recipe, List stepImages) throws IOException { + + CompletableFuture buildStep = new CompletableFuture<>(); + CompletableFuture setStep = new CompletableFuture<>(); + + buildStep.complete(TestStep.builder() + .stepNum(step.getStepNum()) + .description(step.getDescription()) + .recipe(recipe) + .build()); + + for (int i = 0; i <= stepImages.size(); i++) { + Integer imageNum = Integer.parseInt(stepImages.get(i).getOriginalFilename().substring(0,1)) + 1; + if (imageNum == step.getStepNum()){ + MultipartFile stepImage = stepImages.get(i); + setStep.complete(uploadTestStep(stepImage)); + break; + } + else if(i == stepImages.size()) + throw new RecipeException(CommonStatus.NULL_RECIPE_ERROR); + } + + return buildStep.thenCombine(setStep, (createStep, imageUrl) -> { + createStep.setImage(imageUrl); + return createStep; + }).join(); + + } + + private static TestStep toTestStepWithImageUrlDto(RecipeRequestDto.StepWithImageUrlDto step, TestRecipe recipe) throws IOException { + + return TestStep.builder() + .stepNum(step.getStepNum()) + .description(step.getDescription()) + .imageUrl(step.getStepUrl()) + .recipe(recipe) + .build(); + } + + public static CompletableFuture> toTestIngredient(RecipeRequestDto.CreateRecipeDto request, TestRecipe recipe) { + return CompletableFuture.completedFuture(request.getIngredients().stream().parallel() + .map(ingredient -> toTestIngredientDto(ingredient, recipe)) + .collect(Collectors.toList())); + } + + public static CompletableFuture> toTestIngredientWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request, TestRecipe recipe) { + return CompletableFuture.completedFuture(request.getIngredients().stream().parallel() + .map(ingredient -> toTestIngredientDto(ingredient, recipe)) + .collect(Collectors.toList())); + } + + private static TestIngredient toTestIngredientDto(RecipeRequestDto.NewIngredientDto ingredient, TestRecipe recipe) { + + return TestIngredient.builder() + .name(ingredient.getIngredientName()) + .quantity(ingredient.getQuantity()) + .recipe(recipe) + .build(); + } + + public static RecipeResponseDto.RecipeInfoDto toTestRecipeInfoDto(TestRecipe recipe) { + return RecipeResponseDto.RecipeInfoDto.builder() + .recipeInfo(toResponseTestRecipeDto(recipe)) + .ownerId(0L) + .isOwner(false) + .steps(toResponseTestStepDto(recipe)) + .ingredients(toResponseTestIngredientDto(recipe)) + .build(); + } + + public static RecipeResponseDto.RecipeDto toResponseTestRecipeDto(TestRecipe recipe){ + + return RecipeResponseDto.RecipeDto.builder() + .recipeId(recipe.getId()) + .categoryId(getTestCategoryIds(recipe)) + .recipeName(recipe.getName()) + .ownerImage("") + .nickname("test") + .thumbnailUrl(recipe.getThumbnailUrl()+"?size=thumbnail") + .time(recipe.getTime()) + .intro(recipe.getIntro()) + .recipeTip(recipe.getRecipeTip()) + .createdAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) + .updatedAt(staticTimeConverter.ConvertTime(recipe.getUpdatedAt())) + .likes(recipe.getTotalLike()) + .comments(0L) + .scraps(recipe.getTotalScrap()) + .isLiked(false) + .isScrapped(false) + .build(); + } + + public static List getTestCategoryIds(TestRecipe recipe){ + return recipe.getCategoryMappingList().stream() + .map(categoryMapping -> categoryMapping.getCategory().getId()) + .collect(Collectors.toList()); + } + + public static List toResponseTestStepDto(TestRecipe recipe) { + + return recipe.getStepList().stream() + .map(step-> RecipeResponseDto.StepDto.builder() + .stepNum(step.getStepNum()) + .description(step.getDescription()) + .image(step.getImageUrl()+"?size=step") + .build()) + .collect(Collectors.toList()); + } + + public static List toResponseTestIngredientDto(TestRecipe recipe) { + return recipe.getIngredientList().stream() + .map(ingredient -> RecipeResponseDto.IngredientDto.builder() + .IngredientName(ingredient.getName()) + .quantity(ingredient.getQuantity()) + .build()) + .collect(Collectors.toList()); + } + + public static RecipeResponseDto.RecipePageListDto toPagingTestRecipeDtoList(Page recipes) { + return RecipeResponseDto.RecipePageListDto.builder() + .recipeList(recipes.toList().stream() + .map(recipe -> toResponseTestRecipeSimpleDto(recipe)) + .collect(Collectors.toList())) + .totalElements(recipes.getTotalElements()) + .currentPageElements(recipes.getNumberOfElements()) + .totalPage(recipes.getTotalPages()) + .isFirst(recipes.isFirst()) + .isLast(recipes.isLast()) + .build(); + } + + private static RecipeResponseDto.RecipeSimpleDto toResponseTestRecipeSimpleDto(TestRecipe recipe) { + return RecipeResponseDto.RecipeSimpleDto.builder() + .recipeId(recipe.getId()) + .categoryId(getTestCategoryIds(recipe)) + .recipeName(recipe.getName()) + .nickname("test") + .thumbnailUrl(recipe.getThumbnailUrl()+"?size=preview") + .createdAt(staticTimeConverter.ConvertTime(recipe.getCreatedAt())) + .updatedAt(staticTimeConverter.ConvertTime(recipe.getUpdatedAt())) + .comments(0L) + .likes(recipe.getTotalLike()) + .scraps(recipe.getTotalScrap()) + .isLiked(false) + .isScrapped(false) + .build(); + } + +} diff --git a/src/test/java/zipdabang/server/domain/recipe/RecipeCategory.java b/src/test/java/zipdabang/server/domain/recipe/RecipeCategory.java new file mode 100644 index 0000000..2fb3465 --- /dev/null +++ b/src/test/java/zipdabang/server/domain/recipe/RecipeCategory.java @@ -0,0 +1,28 @@ +package zipdabang.server.domain.recipe; + +import lombok.*; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Getter +@Builder +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@DynamicInsert +@DynamicUpdate +@Entity +public class RecipeCategory { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + private String imageUrl; +} diff --git a/src/main/java/zipdabang/server/domain/test/TestComment.java b/src/test/java/zipdabang/server/domain/test/TestComment.java similarity index 100% rename from src/main/java/zipdabang/server/domain/test/TestComment.java rename to src/test/java/zipdabang/server/domain/test/TestComment.java diff --git a/src/main/java/zipdabang/server/domain/test/TestIngredient.java b/src/test/java/zipdabang/server/domain/test/TestIngredient.java similarity index 95% rename from src/main/java/zipdabang/server/domain/test/TestIngredient.java rename to src/test/java/zipdabang/server/domain/test/TestIngredient.java index 0d81f62..724c360 100644 --- a/src/main/java/zipdabang/server/domain/test/TestIngredient.java +++ b/src/test/java/zipdabang/server/domain/test/TestIngredient.java @@ -4,7 +4,6 @@ import org.hibernate.annotations.DynamicInsert; import org.hibernate.annotations.DynamicUpdate; import zipdabang.server.domain.common.BaseEntity; -import zipdabang.server.domain.recipe.Recipe; import javax.persistence.*; diff --git a/src/main/java/zipdabang/server/domain/test/TestLikes.java b/src/test/java/zipdabang/server/domain/test/TestLikes.java similarity index 100% rename from src/main/java/zipdabang/server/domain/test/TestLikes.java rename to src/test/java/zipdabang/server/domain/test/TestLikes.java diff --git a/src/main/java/zipdabang/server/domain/test/TestRecipe.java b/src/test/java/zipdabang/server/domain/test/TestRecipe.java similarity index 100% rename from src/main/java/zipdabang/server/domain/test/TestRecipe.java rename to src/test/java/zipdabang/server/domain/test/TestRecipe.java diff --git a/src/main/java/zipdabang/server/domain/test/TestRecipeCategoryMapping.java b/src/test/java/zipdabang/server/domain/test/TestRecipeCategoryMapping.java similarity index 100% rename from src/main/java/zipdabang/server/domain/test/TestRecipeCategoryMapping.java rename to src/test/java/zipdabang/server/domain/test/TestRecipeCategoryMapping.java diff --git a/src/main/java/zipdabang/server/domain/test/TestScrap.java b/src/test/java/zipdabang/server/domain/test/TestScrap.java similarity index 100% rename from src/main/java/zipdabang/server/domain/test/TestScrap.java rename to src/test/java/zipdabang/server/domain/test/TestScrap.java diff --git a/src/main/java/zipdabang/server/domain/test/TestStep.java b/src/test/java/zipdabang/server/domain/test/TestStep.java similarity index 96% rename from src/main/java/zipdabang/server/domain/test/TestStep.java rename to src/test/java/zipdabang/server/domain/test/TestStep.java index fa30036..c8f5d6a 100644 --- a/src/main/java/zipdabang/server/domain/test/TestStep.java +++ b/src/test/java/zipdabang/server/domain/test/TestStep.java @@ -4,7 +4,6 @@ import org.hibernate.annotations.DynamicInsert; import org.hibernate.annotations.DynamicUpdate; import zipdabang.server.domain.common.BaseEntity; -import zipdabang.server.domain.recipe.Recipe; import javax.persistence.*; diff --git a/src/test/java/zipdabang/server/repository/recipeRepository/RecipeCategoryRepository.java b/src/test/java/zipdabang/server/repository/recipeRepository/RecipeCategoryRepository.java new file mode 100644 index 0000000..0575f8b --- /dev/null +++ b/src/test/java/zipdabang/server/repository/recipeRepository/RecipeCategoryRepository.java @@ -0,0 +1,14 @@ +package zipdabang.server.repository.recipeRepository; + +import org.springframework.data.jpa.repository.JpaRepository; +import zipdabang.server.domain.recipe.RecipeCategory; + +import java.util.List; +import java.util.Optional; + +public interface RecipeCategoryRepository extends JpaRepository { + + List findAllById(Long categoryId); + + Optional findById(Long id); +} diff --git a/src/main/java/zipdabang/server/repository/testRepository/TestIngredientRepository.java b/src/test/java/zipdabang/server/repository/testRepository/TestIngredientRepository.java similarity index 100% rename from src/main/java/zipdabang/server/repository/testRepository/TestIngredientRepository.java rename to src/test/java/zipdabang/server/repository/testRepository/TestIngredientRepository.java diff --git a/src/main/java/zipdabang/server/repository/testRepository/TestRecipeCategoryMappingRepository.java b/src/test/java/zipdabang/server/repository/testRepository/TestRecipeCategoryMappingRepository.java similarity index 100% rename from src/main/java/zipdabang/server/repository/testRepository/TestRecipeCategoryMappingRepository.java rename to src/test/java/zipdabang/server/repository/testRepository/TestRecipeCategoryMappingRepository.java diff --git a/src/main/java/zipdabang/server/repository/testRepository/TestRecipeRepository.java b/src/test/java/zipdabang/server/repository/testRepository/TestRecipeRepository.java similarity index 100% rename from src/main/java/zipdabang/server/repository/testRepository/TestRecipeRepository.java rename to src/test/java/zipdabang/server/repository/testRepository/TestRecipeRepository.java diff --git a/src/main/java/zipdabang/server/repository/testRepository/TestStepRepository.java b/src/test/java/zipdabang/server/repository/testRepository/TestStepRepository.java similarity index 92% rename from src/main/java/zipdabang/server/repository/testRepository/TestStepRepository.java rename to src/test/java/zipdabang/server/repository/testRepository/TestStepRepository.java index 432fb55..9d3a0d5 100644 --- a/src/main/java/zipdabang/server/repository/testRepository/TestStepRepository.java +++ b/src/test/java/zipdabang/server/repository/testRepository/TestStepRepository.java @@ -5,7 +5,6 @@ import zipdabang.server.domain.test.TestStep; import java.util.List; -import java.util.Optional; public interface TestStepRepository extends JpaRepository { List findAllByRecipeId(Long recipeId); diff --git a/src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java b/src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java similarity index 92% rename from src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java rename to src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java index 62ec1fa..992d1d9 100644 --- a/src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java +++ b/src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryCustom/TestRecipeRepositoryCustom.java @@ -1,7 +1,6 @@ package zipdabang.server.repository.testRepository.testRecipeRepositoryCustom; import com.querydsl.core.types.dsl.BooleanExpression; -import zipdabang.server.domain.member.Member; import zipdabang.server.domain.test.TestRecipe; import java.util.List; diff --git a/src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java b/src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java similarity index 93% rename from src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java rename to src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java index b584813..caf3ae9 100644 --- a/src/main/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java +++ b/src/test/java/zipdabang/server/repository/testRepository/testRecipeRepositoryImpl/TestRecipeRepositoryImpl.java @@ -4,7 +4,6 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import zipdabang.server.domain.member.Member; import zipdabang.server.domain.test.QTestRecipe; import zipdabang.server.domain.test.QTestRecipeCategoryMapping; import zipdabang.server.domain.test.TestRecipe; @@ -12,8 +11,6 @@ import java.util.List; -import static zipdabang.server.domain.recipe.QRecipe.recipe; -import static zipdabang.server.domain.recipe.QRecipeCategoryMapping.recipeCategoryMapping; import static zipdabang.server.domain.test.QTestRecipe.testRecipe; import static zipdabang.server.domain.test.QTestRecipeCategoryMapping.testRecipeCategoryMapping; diff --git a/src/test/java/zipdabang/server/service/RecipeService.java b/src/test/java/zipdabang/server/service/RecipeService.java new file mode 100644 index 0000000..b9ad2cc --- /dev/null +++ b/src/test/java/zipdabang/server/service/RecipeService.java @@ -0,0 +1,24 @@ +package zipdabang.server.service; + +import org.springframework.data.domain.Page; +import org.springframework.web.multipart.MultipartFile; +import zipdabang.server.domain.recipe.RecipeCategory; +import zipdabang.server.domain.test.TestRecipe; +import zipdabang.server.web.dto.requestDto.RecipeRequestDto; + +import java.io.IOException; +import java.util.List; + +public interface RecipeService { + public RecipeCategory getRecipeCategory(Long categoryId); + + TestRecipe testCreate(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail, List stepImages) throws IOException; + + TestRecipe getTestRecipe(Long recipeId); + + Page testRecipeListByCategory(Long categoryId, Integer pageIndex, String order); + + Boolean deleteTestRecipe(); + + TestRecipe testCreateWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request); +} diff --git a/src/test/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java b/src/test/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java new file mode 100644 index 0000000..b9014da --- /dev/null +++ b/src/test/java/zipdabang/server/service/serviceImpl/RecipeServiceImpl.java @@ -0,0 +1,182 @@ +package zipdabang.server.service.serviceImpl; + +import com.querydsl.core.types.dsl.BooleanExpression; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import zipdabang.server.apiPayload.code.CommonStatus; +import zipdabang.server.apiPayload.exception.handler.RecipeException; +import zipdabang.server.aws.s3.AmazonS3Manager; +import zipdabang.server.converter.RecipeConverter; +import zipdabang.server.domain.recipe.RecipeCategory; +import zipdabang.server.domain.test.TestRecipe; +import zipdabang.server.repository.recipeRepository.RecipeCategoryRepository; +import zipdabang.server.repository.testRepository.TestIngredientRepository; +import zipdabang.server.repository.testRepository.TestRecipeCategoryMappingRepository; +import zipdabang.server.repository.testRepository.TestRecipeRepository; +import zipdabang.server.repository.testRepository.TestStepRepository; +import zipdabang.server.repository.testRepository.testRecipeRepositoryCustom.TestRecipeRepositoryCustom; +import zipdabang.server.service.RecipeService; +import zipdabang.server.web.dto.requestDto.RecipeRequestDto; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class RecipeServiceImpl implements RecipeService { + + private final TestRecipeRepository testRecipeRepository; + private final TestRecipeCategoryMappingRepository testRecipeCategoryMappingRepository; + private final TestStepRepository testStepRepository; + private final TestIngredientRepository testIngredientRepository; + private final TestRecipeRepositoryCustom testRecipeRepositoryCustom; + private final RecipeCategoryRepository recipeCategoryRepository; + private final AmazonS3Manager amazonS3Manager; + + @Value("${paging.size}") + Integer pageSize; + + @Override + public RecipeCategory getRecipeCategory(Long categoryId) { + return recipeCategoryRepository.findById(categoryId).get(); + } + + @Override + @Transactional(readOnly = false) + public TestRecipe testCreate(RecipeRequestDto.CreateRecipeDto request, MultipartFile thumbnail, List stepImages) throws IOException { + + CompletableFuture savedRecipeFuture = CompletableFuture.supplyAsync(() ->{ + TestRecipe buildRecipe = null; + try { + buildRecipe = RecipeConverter.toTestRecipe(request, thumbnail); + } catch (IOException e) { + throw new RuntimeException(e); + } + return testRecipeRepository.save(buildRecipe); + }); + + savedRecipeFuture.thenAccept(recipe -> { + RecipeConverter.toTestRecipeCategory(request.getCategoryId(),recipe).join().stream() + .map(categoryMapping -> testRecipeCategoryMappingRepository.save(categoryMapping)) + .collect(Collectors.toList()) + .stream() + .map(categoryMapping -> categoryMapping.setRecipe(recipe)); + }); + + + savedRecipeFuture.thenAccept(recipe -> { + RecipeConverter.toTestStep(request, recipe, stepImages).join().stream() + .map(step -> testStepRepository.save(step)) + .collect(Collectors.toList()) + .stream() + .map(step -> step.setRecipe(recipe)); + }); + + savedRecipeFuture.thenAccept(recipe -> { + RecipeConverter.toTestIngredient(request, recipe).join().stream() + .map(ingredient -> testIngredientRepository.save(ingredient)) + .collect(Collectors.toList()) + .stream() + .map(ingredient -> ingredient.setRecipe(recipe)); + }); + + return savedRecipeFuture.join(); + } + + @Override + @Transactional(readOnly = false) + public TestRecipe testCreateWithImageUrl(RecipeRequestDto.CreateRecipeWithImageUrlDto request){ + TestRecipe buildRecipe = RecipeConverter.toTestRecipeWithImageUrl(request); + testRecipeRepository.save(buildRecipe); + + RecipeConverter.toTestRecipeCategory(request.getCategoryId(),buildRecipe).join().stream() + .map(categoryMapping -> testRecipeCategoryMappingRepository.save(categoryMapping)) + .collect(Collectors.toList()) + .stream() + .map(categoryMapping -> categoryMapping.setRecipe(buildRecipe)); + + RecipeConverter.toTestStepWithImageUrl(request, buildRecipe).join().stream() + .map(step -> testStepRepository.save(step)) + .collect(Collectors.toList()) + .stream() + .map(step -> step.setRecipe(buildRecipe)); + + RecipeConverter.toTestIngredientWithImageUrl(request, buildRecipe).join().stream() + .map(ingredient -> testIngredientRepository.save(ingredient)) + .collect(Collectors.toList()) + .stream() + .map(ingredient -> ingredient.setRecipe(buildRecipe)); + + return buildRecipe; + } + + @Override + public TestRecipe getTestRecipe(Long recipeId) { + TestRecipe findRecipe = testRecipeRepository.findById(recipeId).orElseThrow(()->new RecipeException(CommonStatus.NO_RECIPE_EXIST)); + + findRecipe.updateView(); + return findRecipe; + } + + @Transactional + @Override + public Page testRecipeListByCategory(Long categoryId, Integer pageIndex, String order) { + + List recipeCategory = recipeCategoryRepository.findAllById(categoryId); + + if(recipeCategory.isEmpty()) + throw new RecipeException(CommonStatus.RECIPE_NOT_FOUND); + + List content = new ArrayList<>(); + + BooleanExpression whereCondition = testRecipeRepositoryCustom.recipesInCategoryCondition(categoryId); + + + content = testRecipeRepositoryCustom.testRecipesOrderBy(pageIndex,pageSize, order, whereCondition); + + log.info("서비스단의 상황 : {}", content.size()); + Long count = testRecipeRepositoryCustom.testRecipeTotalCount(whereCondition); + + if (count < pageIndex*pageSize) + throw new RecipeException(CommonStatus.OVER_PAGE_INDEX_ERROR); + if (content.size() > count - pageIndex*pageSize) + content = content.subList(0, count.intValue()-pageIndex*pageSize); + + return new PageImpl<>(content, PageRequest.of(pageIndex,pageSize), count); + } + + @Transactional(readOnly = false) + @Override + public Boolean deleteTestRecipe() { + List findRecipes = testRecipeRepository.findAll(); + + List thumbnailUrls = findRecipes.stream().parallel() + .map(recipe -> recipe.getThumbnailUrl()).collect(Collectors.toList()); + List stepUrlList = testStepRepository.findAll().stream().parallel() + .filter(steps -> steps.getImageUrl() != null) + .map(step -> step.getImageUrl()) + .collect(Collectors.toList()); + + testRecipeRepository.deleteAll(); + + thumbnailUrls.parallelStream().forEach(thumbnailUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(thumbnailUrl).substring(1))); + stepUrlList.parallelStream() + .forEach(stepUrl -> amazonS3Manager.deleteFile(RecipeConverter.toKeyName(stepUrl).substring(1))); + + return testRecipeRepository.count() == 0; + + } +} diff --git a/src/test/java/zipdabang/server/web/controller/RecipeRestController.java b/src/test/java/zipdabang/server/web/controller/RecipeRestController.java new file mode 100644 index 0000000..49201cb --- /dev/null +++ b/src/test/java/zipdabang/server/web/controller/RecipeRestController.java @@ -0,0 +1,17 @@ +package zipdabang.server.web.controller; + +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +@Slf4j +@RestController +@Validated +@RequiredArgsConstructor +public class +RecipeRestController { + + +} diff --git a/src/test/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java b/src/test/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java new file mode 100644 index 0000000..4988031 --- /dev/null +++ b/src/test/java/zipdabang/server/web/dto/requestDto/RecipeRequestDto.java @@ -0,0 +1,56 @@ +package zipdabang.server.web.dto.requestDto; + +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +public class RecipeRequestDto { + + @Getter + @Setter + public static class CreateRecipeDto{ + List categoryId; + String name; + String time; + String intro; + String recipeTip; + Integer stepCount; + Integer ingredientCount; + List steps; + List ingredients; + } + + @Getter + public static class StepDto{ + private Integer stepNum; + private String description; + } + + @Getter + public static class NewIngredientDto{ + private String ingredientName; + private String quantity; + } + + @Getter @Setter + public static class CreateRecipeWithImageUrlDto{ + List categoryId; + String name; + String time; + String intro; + String recipeTip; + String thumbnailUrl; + Integer stepCount; + Integer ingredientCount; + List steps; + List ingredients; + } + + @Getter + public static class StepWithImageUrlDto{ + private Integer stepNum; + private String stepUrl; + private String description; + } +}