Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ public ApiResponse<ProductRegisterResponseDto> registerProduct(
)
@GetMapping("/latest")
public ApiResponse<ProductResponseDTO.ProductListResultDTO> getProductList(
@RequestParam(required = false) Long cursorId) {
return ApiResponse.onSuccess(productService.getProducts(cursorId));
@RequestParam(required = false) Long cursorId, @OptionalUser User user) {
return ApiResponse.onSuccess(productService.getProducts(cursorId, user));
}

@GetMapping("/search/autocomplete")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.DecodEat.domain.products.entity.RawMaterial.RawMaterialCategory.*;

public class ProductConverter {
public static ProductDetailDto toProductDetailDto(Product product,
List<String> productInfoImageUrls ,
ProductNutrition productNutrition) {
ProductNutrition productNutrition,
boolean isLiked) {
Map<RawMaterialCategory, List<String>> nutrientsMap =
product.getIngredients().stream()
.collect(Collectors.groupingBy(
Expand All @@ -35,6 +37,7 @@ public static ProductDetailDto toProductDetailDto(Product product,
.name(product.getProductName())
.manufacturer(product.getManufacturer())
.productImage(product.getProductImage())
.isLiked(isLiked)
.calcium(productNutrition.getCalcium())
.carbohydrate(productNutrition.getCarbohydrate())
.cholesterol(productNutrition.getCholesterol())
Expand Down Expand Up @@ -67,13 +70,14 @@ public static ProductRegisterResponseDto toProductRegisterDto(Product product, L
}

// 단일 Product → ProductListItemDTO 변환
public static ProductResponseDTO.ProductListItemDTO toProductListItemDTO(Product product){
public static ProductResponseDTO.ProductListItemDTO toProductListItemDTO(Product product, boolean isLiked) {
return ProductResponseDTO.ProductListItemDTO.builder()
.productId(product.getProductId())
.manufacturer(product.getManufacturer())
.productName(product.getProductName())
.productImage(product.getProductImage())
.decodeStatus(product.getDecodeStatus())
.isLiked(isLiked)
.build();
}

Expand Down Expand Up @@ -105,9 +109,9 @@ public static ProductRegisterHistoryDto toProductRegisterHistoryDto(Product prod


// Slice<Product> → ProductListResultDTO 변환
public static ProductResponseDTO.ProductListResultDTO toProductListResultDTO(Slice<Product> slice) {
public static ProductResponseDTO.ProductListResultDTO toProductListResultDTO(Slice<Product> slice, Set<Long> likedProductIds) {
List<ProductResponseDTO.ProductListItemDTO> productList = slice.getContent().stream()
.map(ProductConverter::toProductListItemDTO)
.map(product -> toProductListItemDTO(product, likedProductIds.contains(product.getProductId())))
.toList();

Long nextCursorId = (slice.hasNext() && !productList.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class ProductDetailDto {

private List<String> imageUrl;

private boolean isLiked;

private Double calcium;
private Double carbohydrate;
private Double cholesterol;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ public static class ProductListItemDTO {

@Schema(description = "뷴석 상태", example = "COMPLETED")
private DecodeStatus decodeStatus;

@Schema(description = "좋아요 여부", example = "true")
private boolean isLiked;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,23 @@
import com.DecodEat.domain.products.entity.ProductLike;
import com.DecodEat.domain.users.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;

public interface ProductLikeRepository extends JpaRepository<ProductLike, Long> {

Optional<ProductLike> findByUserAndProduct(User user, Product product);

// 여러 제품에 대한 좋아요 여부 조회 ( 제품 리스트 조회시 N + 1 문제 해결)
@Query("SELECT pl.product.productId " +
"FROM ProductLike pl " +
"WHERE pl.user = :user AND pl.product.productId IN :productIds")
List<Long> findLikedProductIdsByUserAndProductIds(@Param("user") User user,
@Param("productIds") List<Long> productIds);

boolean existsByUserAndProduct(User user, Product product);

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@
import org.springframework.web.multipart.MultipartFile;

import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;

import static com.DecodEat.global.apiPayload.code.status.ErrorStatus.*;
Expand Down Expand Up @@ -62,7 +59,12 @@ public ProductDetailDto getDetail(Long id, User user) {

ProductNutrition productNutrition = productNutritionRepository.findByProduct(product).orElseThrow(() -> new GeneralException(PRODUCT_NUTRITION_NOT_EXISTED));

return ProductConverter.toProductDetailDto(product, imageUrls, productNutrition);
// 좋아요 여부 확인
boolean isLiked = false;
if(user != null){
isLiked = productLikeRepository.existsByUserAndProduct(user,product);
}
return ProductConverter.toProductDetailDto(product, imageUrls, productNutrition, isLiked);
}

public ProductRegisterResponseDto addProduct(User user, ProductRegisterRequestDto requestDto, MultipartFile productImage, List<MultipartFile> productInfoImages) {
Expand Down Expand Up @@ -110,11 +112,25 @@ public ProductRegisterResponseDto addProduct(User user, ProductRegisterRequestDt
}

@Transactional(readOnly = true)
public ProductResponseDTO.ProductListResultDTO getProducts(Long cursorId) {
public ProductResponseDTO.ProductListResultDTO getProducts(Long cursorId, User user) {
Pageable pageable = PageRequest.of(0, PAGE_SIZE);
Slice<Product> slice = productRepository.findCompletedProductsByCursor(cursorId, pageable);

return ProductConverter.toProductListResultDTO(slice);
// 기본값: 전부 false
Set<Long> likedProductIds = Collections.emptySet();

// user가 null이 아닐 때만 DB에서 좋아요 여부 조회
if (user != null && !slice.isEmpty()) {
List<Long> productIds = slice.getContent().stream()
.map(Product::getProductId)
.toList();

likedProductIds = new HashSet<>(
productLikeRepository.findLikedProductIdsByUserAndProductIds(user, productIds)
);
}

return ProductConverter.toProductListResultDTO(slice, likedProductIds);
}

// todo: 검색은 상품 엔티티와 1:1 매핑 불가능 -> userbehavior 어떻게?
Expand Down
Loading