Skip to content

Commit caf43c2

Browse files
authored
v2.0.0 (#45)
v2.0.0
2 parents 6f2db64 + d3665bd commit caf43c2

25 files changed

Lines changed: 755 additions & 285 deletions

src/main/java/com/funeat/auth/util/AuthArgumentResolver.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.funeat.auth.util;
22

33
import com.funeat.auth.dto.LoginInfo;
4-
import java.util.Objects;
54
import jakarta.servlet.http.HttpServletRequest;
65
import jakarta.servlet.http.HttpSession;
6+
import java.util.Objects;
77
import org.springframework.core.MethodParameter;
88
import org.springframework.stereotype.Component;
99
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -14,6 +14,8 @@
1414
@Component
1515
public class AuthArgumentResolver implements HandlerMethodArgumentResolver {
1616

17+
private static final LoginInfo GUEST = new LoginInfo(-1L);
18+
1719
@Override
1820
public boolean supportsParameter(final MethodParameter parameter) {
1921
return parameter.hasParameterAnnotation(AuthenticationPrincipal.class);
@@ -24,8 +26,11 @@ public Object resolveArgument(final MethodParameter parameter, final ModelAndVie
2426
final NativeWebRequest webRequest, final WebDataBinderFactory binderFactory) {
2527
final HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
2628
final HttpSession session = Objects.requireNonNull(request).getSession(false);
27-
final String id = String.valueOf(session.getAttribute("member"));
29+
if (Objects.isNull(session)) {
30+
return GUEST;
31+
}
2832

33+
final String id = String.valueOf(session.getAttribute("member"));
2934
return new LoginInfo(Long.valueOf(id));
3035
}
3136
}

src/main/java/com/funeat/product/application/ProductService.java

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package com.funeat.product.application;
22

3+
import static com.funeat.member.exception.MemberErrorCode.MEMBER_NOT_FOUND;
34
import static com.funeat.product.exception.CategoryErrorCode.CATEGORY_NOT_FOUND;
45
import static com.funeat.product.exception.ProductErrorCode.PRODUCT_NOT_FOUND;
56

67
import com.funeat.common.dto.PageDto;
8+
import com.funeat.member.domain.Member;
9+
import com.funeat.member.exception.MemberException.MemberNotFoundException;
10+
import com.funeat.member.persistence.MemberRepository;
11+
import com.funeat.member.persistence.RecipeFavoriteRepository;
712
import com.funeat.product.domain.Category;
813
import com.funeat.product.domain.Product;
914
import com.funeat.product.dto.ProductInCategoryDto;
@@ -51,6 +56,7 @@ public class ProductService {
5156
private static final int RANKING_SIZE = 3;
5257
private static final int DEFAULT_PAGE_SIZE = 10;
5358
private static final int DEFAULT_CURSOR_PAGINATION_SIZE = 11;
59+
private static final long GUEST_ID = -1L;
5460

5561
private final CategoryRepository categoryRepository;
5662
private final ProductRepository productRepository;
@@ -59,19 +65,24 @@ public class ProductService {
5965
private final ProductRecipeRepository productRecipeRepository;
6066
private final RecipeImageRepository recipeImageRepository;
6167
private final RecipeRepository recipeRepository;
68+
private final MemberRepository memberRepository;
69+
private final RecipeFavoriteRepository recipeFavoriteRepository;
6270

6371
public ProductService(final CategoryRepository categoryRepository, final ProductRepository productRepository,
6472
final ReviewTagRepository reviewTagRepository, final ReviewRepository reviewRepository,
6573
final ProductRecipeRepository productRecipeRepository,
6674
final RecipeImageRepository recipeImageRepository,
67-
final RecipeRepository recipeRepository) {
75+
final RecipeRepository recipeRepository, final MemberRepository memberRepository,
76+
final RecipeFavoriteRepository recipeFavoriteRepository) {
6877
this.categoryRepository = categoryRepository;
6978
this.productRepository = productRepository;
7079
this.reviewTagRepository = reviewTagRepository;
7180
this.reviewRepository = reviewRepository;
7281
this.productRecipeRepository = productRecipeRepository;
7382
this.recipeImageRepository = recipeImageRepository;
7483
this.recipeRepository = recipeRepository;
84+
this.memberRepository = memberRepository;
85+
this.recipeFavoriteRepository = recipeFavoriteRepository;
7586
}
7687

7788
public ProductsInCategoryResponse getAllProductsInCategory(final Long categoryId, final Long lastProductId,
@@ -174,20 +185,30 @@ private List<ProductReviewCountDto> findAllWithReviewCountByNameContaining(final
174185
return productRepository.findAllWithReviewCountByNameContaining(query, lastProductId, size);
175186
}
176187

177-
public SortingRecipesResponse getProductRecipes(final Long productId, final Pageable pageable) {
188+
public SortingRecipesResponse getProductRecipes(final Long memberId, final Long productId, final Pageable pageable) {
178189
final Product product = productRepository.findById(productId)
179190
.orElseThrow(() -> new ProductNotFoundException(PRODUCT_NOT_FOUND, productId));
180191

181192
final Page<Recipe> recipes = recipeRepository.findRecipesByProduct(product, pageable);
182193

183194
final PageDto pageDto = PageDto.toDto(recipes);
184195
final List<RecipeDto> recipeDtos = recipes.stream()
185-
.map(recipe -> {
186-
final List<RecipeImage> images = recipeImageRepository.findByRecipe(recipe);
187-
final List<Product> products = productRecipeRepository.findProductByRecipe(recipe);
188-
return RecipeDto.toDto(recipe, images, products);
189-
})
190-
.collect(Collectors.toList());
196+
.map(recipe -> createRecipeDto(memberId, recipe))
197+
.toList();
191198
return SortingRecipesResponse.toResponse(pageDto, recipeDtos);
192199
}
200+
201+
private RecipeDto createRecipeDto(final Long memberId, final Recipe recipe) {
202+
final List<RecipeImage> images = recipeImageRepository.findByRecipe(recipe);
203+
final List<Product> products = productRecipeRepository.findProductByRecipe(recipe);
204+
205+
if (memberId == GUEST_ID) {
206+
return RecipeDto.toDto(recipe, images, products, false);
207+
}
208+
209+
final Member member = memberRepository.findById(memberId)
210+
.orElseThrow(() -> new MemberNotFoundException(MEMBER_NOT_FOUND, memberId));
211+
final Boolean favorite = recipeFavoriteRepository.existsByMemberAndRecipeAndFavoriteTrue(member, recipe);
212+
return RecipeDto.toDto(recipe, images, products, favorite);
213+
}
193214
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.funeat.product.dto;
2+
3+
import com.funeat.product.domain.Category;
4+
5+
public class CategoryDto {
6+
7+
private final Long id;
8+
private final String name;
9+
private final String image;
10+
11+
private CategoryDto(final Long id, final String name, final String image) {
12+
this.id = id;
13+
this.name = name;
14+
this.image = image;
15+
}
16+
17+
public static CategoryDto toDto(final Category category) {
18+
return new CategoryDto(category.getId(), category.getName(), category.getImage());
19+
}
20+
21+
public Long getId() {
22+
return id;
23+
}
24+
25+
public String getName() {
26+
return name;
27+
}
28+
29+
public String getImage() {
30+
return image;
31+
}
32+
}

src/main/java/com/funeat/product/dto/ProductResponse.java

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.funeat.product.dto;
22

3+
import com.funeat.product.domain.Category;
4+
import com.funeat.product.domain.CategoryType;
35
import com.funeat.product.domain.Product;
46
import com.funeat.tag.domain.Tag;
57
import com.funeat.tag.dto.TagDto;
@@ -15,27 +17,30 @@ public class ProductResponse {
1517
private final String content;
1618
private final Double averageRating;
1719
private final Long reviewCount;
20+
private final CategoryDto category;
1821
private final List<TagDto> tags;
1922

2023
public ProductResponse(final Long id, final String name, final Long price, final String image, final String content,
21-
final Double averageRating, final Long reviewCount, final List<TagDto> tags) {
24+
final Double averageRating, final Long reviewCount, final CategoryDto category, final List<TagDto> tags) {
2225
this.id = id;
2326
this.name = name;
2427
this.price = price;
2528
this.image = image;
2629
this.content = content;
2730
this.averageRating = averageRating;
2831
this.reviewCount = reviewCount;
32+
this.category = category;
2933
this.tags = tags;
3034
}
3135

3236
public static ProductResponse toResponse(final Product product, final List<Tag> tags) {
33-
List<TagDto> tagDtos = new ArrayList<>();
34-
for (Tag tag : tags) {
37+
final CategoryDto categoryDto = CategoryDto.toDto(product.getCategory());
38+
final List<TagDto> tagDtos = new ArrayList<>();
39+
for (final Tag tag : tags) {
3540
tagDtos.add(TagDto.toDto(tag));
3641
}
3742
return new ProductResponse(product.getId(), product.getName(), product.getPrice(), product.getImage(),
38-
product.getContent(), product.getAverageRating(), product.getReviewCount(), tagDtos);
43+
product.getContent(), product.getAverageRating(), product.getReviewCount(), categoryDto, tagDtos);
3944
}
4045

4146
public Long getId() {
@@ -66,6 +71,10 @@ public Long getReviewCount() {
6671
return reviewCount;
6772
}
6873

74+
public CategoryDto getCategory() {
75+
return category;
76+
}
77+
6978
public List<TagDto> getTags() {
7079
return tags;
7180
}

src/main/java/com/funeat/product/dto/RankingProductDto.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,22 @@ public class RankingProductDto {
66

77
private final Long id;
88
private final String name;
9+
private final Long price;
910
private final String image;
1011
private final String categoryType;
1112

12-
public RankingProductDto(final Long id, final String name, final String image, final String categoryType) {
13+
public RankingProductDto(final Long id, final String name, final Long price,
14+
final String image, final String categoryType) {
1315
this.id = id;
1416
this.name = name;
17+
this.price = price;
1518
this.image = image;
1619
this.categoryType = categoryType;
1720
}
1821

1922
public static RankingProductDto toDto(final Product product) {
20-
return new RankingProductDto(product.getId(), product.getName(), product.getImage(),
21-
product.getCategory().getType().getName());
23+
return new RankingProductDto(product.getId(), product.getName(), product.getPrice(),
24+
product.getImage(), product.getCategory().getType().getName());
2225
}
2326

2427
public Long getId() {
@@ -29,6 +32,10 @@ public String getName() {
2932
return name;
3033
}
3134

35+
public Long getPrice() {
36+
return price;
37+
}
38+
3239
public String getImage() {
3340
return image;
3441
}

src/main/java/com/funeat/product/presentation/ProductApiController.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.funeat.product.presentation;
22

3+
import com.funeat.auth.dto.LoginInfo;
4+
import com.funeat.auth.util.AuthenticationPrincipal;
35
import com.funeat.product.application.ProductService;
46
import com.funeat.product.dto.ProductResponse;
57
import com.funeat.product.dto.ProductSortCondition;
@@ -8,7 +10,6 @@
810
import com.funeat.product.dto.SearchProductResultsResponse;
911
import com.funeat.product.dto.SearchProductsResponse;
1012
import com.funeat.recipe.dto.SortingRecipesResponse;
11-
import org.springframework.data.domain.PageRequest;
1213
import org.springframework.data.domain.Pageable;
1314
import org.springframework.data.web.PageableDefault;
1415
import org.springframework.http.ResponseEntity;
@@ -64,9 +65,10 @@ public ResponseEntity<SearchProductResultsResponse> getSearchResults(@RequestPar
6465
}
6566

6667
@GetMapping("/products/{productId}/recipes")
67-
public ResponseEntity<SortingRecipesResponse> getProductRecipes(@PathVariable final Long productId,
68+
public ResponseEntity<SortingRecipesResponse> getProductRecipes(@AuthenticationPrincipal final LoginInfo loginInfo,
69+
@PathVariable final Long productId,
6870
@PageableDefault final Pageable pageable) {
69-
final SortingRecipesResponse response = productService.getProductRecipes(productId, pageable);
71+
final SortingRecipesResponse response = productService.getProductRecipes(loginInfo.getId(), productId, pageable);
7072
return ResponseEntity.ok(response);
7173
}
7274
}

src/main/java/com/funeat/product/presentation/ProductController.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.funeat.product.presentation;
22

3+
import com.funeat.auth.dto.LoginInfo;
4+
import com.funeat.auth.util.AuthenticationPrincipal;
35
import com.funeat.product.dto.ProductResponse;
46
import com.funeat.product.dto.ProductsInCategoryResponse;
57
import com.funeat.product.dto.RankingProductsResponse;
@@ -71,6 +73,7 @@ ResponseEntity<SearchProductResultsResponse> getSearchResults(@RequestParam fina
7173
description = "해당 상품 꿀조합 목록 조회 성공."
7274
)
7375
@GetMapping
74-
ResponseEntity<SortingRecipesResponse> getProductRecipes(@PathVariable final Long productId,
76+
ResponseEntity<SortingRecipesResponse> getProductRecipes(@AuthenticationPrincipal final LoginInfo loginInfo,
77+
@PathVariable final Long productId,
7578
@PageableDefault final Pageable pageable);
7679
}

src/main/java/com/funeat/recipe/application/RecipeService.java

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,11 @@
6363
public class RecipeService {
6464

6565
private static final long RANKING_MINIMUM_FAVORITE_COUNT = 1L;
66-
private static final int RANKING_SIZE = 3;
66+
private static final int RANKING_SIZE = 4;
6767
private static final int DEFAULT_PAGE_SIZE = 10;
6868
private static final int RECIPE_COMMENT_PAGE_SIZE = 10;
6969
private static final int DEFAULT_CURSOR_PAGINATION_SIZE = 11;
70+
private static final long GUEST_ID = -1L;
7071

7172
private final MemberRepository memberRepository;
7273
private final ProductRepository productRepository;
@@ -155,21 +156,31 @@ public MemberRecipesResponse findRecipeByMember(final Long memberId, final Pagea
155156
return MemberRecipesResponse.toResponse(page, dtos);
156157
}
157158

158-
public SortingRecipesResponse getSortingRecipes(final Pageable pageable) {
159+
public SortingRecipesResponse getSortingRecipes(final Long memberId, final Pageable pageable) {
159160
final Page<Recipe> pages = recipeRepository.findAll(pageable);
160161

161162
final PageDto page = PageDto.toDto(pages);
162163
final List<RecipeDto> recipes = pages.getContent().stream()
163-
.map(recipe -> {
164-
final List<RecipeImage> images = recipeImageRepository.findByRecipe(recipe);
165-
final List<Product> products = productRecipeRepository.findProductByRecipe(recipe);
166-
return RecipeDto.toDto(recipe, images, products);
167-
})
168-
.collect(Collectors.toList());
164+
.map(recipe -> createRecipeDto(memberId, recipe))
165+
.toList();
169166

170167
return SortingRecipesResponse.toResponse(page, recipes);
171168
}
172169

170+
private RecipeDto createRecipeDto(final Long memberId, final Recipe recipe) {
171+
final List<RecipeImage> images = recipeImageRepository.findByRecipe(recipe);
172+
final List<Product> products = productRecipeRepository.findProductByRecipe(recipe);
173+
174+
if (memberId == GUEST_ID) {
175+
return RecipeDto.toDto(recipe, images, products, false);
176+
}
177+
178+
final Member member = memberRepository.findById(memberId)
179+
.orElseThrow(() -> new MemberNotFoundException(MEMBER_NOT_FOUND, memberId));
180+
final Boolean favorite = recipeFavoriteRepository.existsByMemberAndRecipeAndFavoriteTrue(member, recipe);
181+
return RecipeDto.toDto(recipe, images, products, favorite);
182+
}
183+
173184
@Transactional
174185
public void likeRecipe(final Long memberId, final Long recipeId, final RecipeFavoriteRequest request) {
175186
final Member member = memberRepository.findById(memberId)
@@ -217,21 +228,31 @@ private List<Recipe> findAllByProductNameContaining(final String query, final Lo
217228
return recipeRepository.findAllByProductNameContaining(query, lastRecipeId, size);
218229
}
219230

220-
public RankingRecipesResponse getTop3Recipes() {
231+
public RankingRecipesResponse getTop4Recipes(final Long memberId) {
221232
final List<Recipe> recipes = recipeRepository.findRecipesByFavoriteCountGreaterThanEqual(RANKING_MINIMUM_FAVORITE_COUNT);
222233

223234
final List<RankingRecipeDto> dtos = recipes.stream()
224235
.sorted(Comparator.comparing(Recipe::calculateRankingScore).reversed())
225236
.limit(RANKING_SIZE)
226-
.map(recipe -> {
227-
final List<RecipeImage> findRecipeImages = recipeImageRepository.findByRecipe(recipe);
228-
final RecipeAuthorDto author = RecipeAuthorDto.toDto(recipe.getMember());
229-
return RankingRecipeDto.toDto(recipe, findRecipeImages, author);
230-
})
231-
.collect(Collectors.toList());
237+
.map(recipe -> createRankingRecipeDto(memberId, recipe))
238+
.toList();
232239
return RankingRecipesResponse.toResponse(dtos);
233240
}
234241

242+
private RankingRecipeDto createRankingRecipeDto(final Long memberId, final Recipe recipe) {
243+
final List<RecipeImage> findRecipeImages = recipeImageRepository.findByRecipe(recipe);
244+
final RecipeAuthorDto author = RecipeAuthorDto.toDto(recipe.getMember());
245+
246+
if (memberId == GUEST_ID) {
247+
return RankingRecipeDto.toDto(recipe, findRecipeImages, author, false);
248+
}
249+
250+
final Member member = memberRepository.findById(memberId)
251+
.orElseThrow(() -> new MemberNotFoundException(MEMBER_NOT_FOUND, memberId));
252+
final boolean favorite = recipeFavoriteRepository.existsByMemberAndRecipeAndFavoriteTrue(member, recipe);
253+
return RankingRecipeDto.toDto(recipe, findRecipeImages, author, favorite);
254+
}
255+
235256
@Transactional
236257
public Long writeCommentOfRecipe(final Long memberId, final Long recipeId,
237258
final RecipeCommentCreateRequest request) {

0 commit comments

Comments
 (0)