diff --git a/src/main/java/org/store/clothstar/category/controller/CategoryController.java b/src/main/java/org/store/clothstar/category/controller/CategoryController.java index 914bbab9..63da2b89 100644 --- a/src/main/java/org/store/clothstar/category/controller/CategoryController.java +++ b/src/main/java/org/store/clothstar/category/controller/CategoryController.java @@ -17,7 +17,7 @@ import org.store.clothstar.category.service.CategoryService; import org.store.clothstar.common.dto.MessageDTO; import org.store.clothstar.common.util.URIBuilder; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; +import org.store.clothstar.productLine.dto.response.ProductLineDetailResponse; import org.store.clothstar.productLine.service.ProductLineService; import java.net.URI; @@ -68,21 +68,21 @@ public ResponseEntity updateCategories( @Operation(summary = "카테고리별 상품 조회 (Offset Paging)", description = "카테고리 ID로 해당 카테고리에 속하는 모든 상품을 Offset Paging을 통해 조회한다.") @GetMapping("/{categoryId}/productLines/offset") - public ResponseEntity> getProductLinesByCategory( + public ResponseEntity> getProductLinesByCategory( @PathVariable Long categoryId, @PageableDefault(size = 18) Pageable pageable, @RequestParam(required = false) String keyword) { - Page productLineResponses = productLineService.getProductLinesByCategoryWithOffsetPaging(categoryId, pageable, keyword); + Page productLineResponses = productLineService.getProductLinesByCategoryWithOffsetPaging(categoryId, pageable, keyword); return ResponseEntity.ok().body(productLineResponses); } @Operation(summary = "카테고리별 상품 조회 (Slice Paging)", description = "카테고리 ID로 해당 카테고리에 속하는 모든 상품을 Slice Paging을 통해 조회한다.") @GetMapping("/{categoryId}/productLines/slice") - public ResponseEntity> getProductLinesByCategorySlice( + public ResponseEntity> getProductLinesByCategorySlice( @PathVariable Long categoryId, @PageableDefault(size = 18) Pageable pageable, @RequestParam(required = false) String keyword) { - Slice productLineResponses = productLineService.getProductLinesByCategoryWithSlicePaging(categoryId, pageable, keyword); + Slice productLineResponses = productLineService.getProductLinesByCategoryWithSlicePaging(categoryId, pageable, keyword); return ResponseEntity.ok().body(productLineResponses); } } \ No newline at end of file diff --git a/src/main/java/org/store/clothstar/product/entity/ProductEntity.java b/src/main/java/org/store/clothstar/product/entity/ProductEntity.java index f613fc0b..aaf8cd8f 100644 --- a/src/main/java/org/store/clothstar/product/entity/ProductEntity.java +++ b/src/main/java/org/store/clothstar/product/entity/ProductEntity.java @@ -10,29 +10,24 @@ import org.store.clothstar.product.dto.request.UpdateProductRequest; import org.store.clothstar.productLine.entity.ProductLineEntity; -@Entity @Getter @NoArgsConstructor @AllArgsConstructor @Builder -@BatchSize(size = 100) -@Table(name = "product") +//@BatchSize(size = 100) +@Entity(name = "product") public class ProductEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long productId; + private String name; + private int extraCharge; + private Long stock; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "product_line_id", nullable = false) -// @JsonManagedReference private ProductLineEntity productLine; - private String name; - - private int extraCharge; - - private Long stock; - public void updateOption(UpdateProductRequest updateProductRequest) { this.name = updateProductRequest.getName(); this.extraCharge = updateProductRequest.getExtraCharge(); diff --git a/src/main/java/org/store/clothstar/productLine/controller/ProductLineController.java b/src/main/java/org/store/clothstar/productLine/controller/ProductLineController.java index d0bef38d..bef3864b 100644 --- a/src/main/java/org/store/clothstar/productLine/controller/ProductLineController.java +++ b/src/main/java/org/store/clothstar/productLine/controller/ProductLineController.java @@ -16,7 +16,7 @@ import org.store.clothstar.productLine.dto.request.CreateProductLineRequest; import org.store.clothstar.productLine.dto.request.UpdateProductLineRequest; import org.store.clothstar.productLine.dto.response.ProductLineResponse; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; +import org.store.clothstar.productLine.dto.response.ProductLineDetailResponse; import org.store.clothstar.productLine.service.ProductLineService; import java.net.URI; @@ -30,6 +30,7 @@ public class ProductLineController { private final ProductLineService productLineService; + @Deprecated @Operation(summary = "전체 상품 조회", description = "삭제되지 않은 모든 상품을 조회한다.") @GetMapping("/v1/productLines") public ResponseEntity> getAllProductLines() { @@ -39,26 +40,26 @@ public ResponseEntity> getAllProductLines() { @Operation(summary = "전체 상품 Offset Paging 조회", description = "삭제되지 않은 모든 상품을 조회한다.") @GetMapping("/v1/productLines/offset") - public ResponseEntity> getAllProductLinesOffsetPaging( + public ResponseEntity> getAllProductLinesOffsetPaging( @PageableDefault(size = 18) Pageable pageable, @RequestParam(required = false) String keyword){ - Page productLineResponses = productLineService.getAllProductLinesWithProductsOffsetPaging(pageable, keyword); + Page productLineResponses = productLineService.getAllProductLinesWithProductsOffsetPaging(pageable, keyword); return ResponseEntity.ok().body(productLineResponses); } @Operation(summary = "전체 상품 Slice Paging 조회", description = "삭제되지 않은 모든 상품을 조회한다.") @GetMapping("/v1/productLines/slice") - public ResponseEntity> getAllProductLinesSlicePaging( + public ResponseEntity> getAllProductLinesSlicePaging( @PageableDefault(size = 18) Pageable pageable, @RequestParam(required = false) String keyword) { - Slice productLineResponses = productLineService.getAllProductLinesWithProductsSlicePaging(pageable, keyword); + Slice productLineResponses = productLineService.getAllProductLinesWithProductsSlicePaging(pageable, keyword); return ResponseEntity.ok().body(productLineResponses); } @Operation(summary = "상품 상세 조회", description = "productLineId로 상품과 하위 옵션들을 상세 조회한다.") @GetMapping("/v1/productLines/{productLineId}") - public ResponseEntity getProductLine(@PathVariable("productLineId") Long productLineId) { - ProductLineWithProductsJPAResponse productLineWithProducts = productLineService.getProductLineWithProducts(productLineId); + public ResponseEntity getProductLine(@PathVariable("productLineId") Long productLineId) { + ProductLineDetailResponse productLineWithProducts = productLineService.getProductLineWithProducts(productLineId); return ResponseEntity.ok().body(productLineWithProducts); } @@ -82,6 +83,7 @@ public ResponseEntity updateProductLine( return ResponseEntity.ok().body(new MessageDTO(HttpStatus.OK.value(), "ProductLine updated successfully")); } + @Operation(summary = "상품 삭제", description = "productLineId를 통해 deletedAt 컬럼을 설정해 soft delete를 수행한다.") @DeleteMapping("/v1/productLines/{productLineId}") public ResponseEntity deleteProductLine(@PathVariable("productLineId") Long productLineId) { productLineService.setDeletedAt(productLineId); diff --git a/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineDetailResponse.java b/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineDetailResponse.java index 85474daa..ac46b31d 100644 --- a/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineDetailResponse.java +++ b/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineDetailResponse.java @@ -1,42 +1,74 @@ package org.store.clothstar.productLine.dto.response; -import lombok.Builder; -import lombok.Getter; -import org.store.clothstar.productLine.domain.ProductLine; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; +import com.querydsl.core.annotations.QueryProjection; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import org.store.clothstar.member.dto.response.SellerSimpleResponse; +import org.store.clothstar.product.dto.response.ProductResponse; +import org.store.clothstar.product.entity.ProductEntity; import org.store.clothstar.productLine.domain.type.ProductLineStatus; +import org.store.clothstar.productLine.entity.ProductLineEntity; import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; -@Getter @Builder +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor public class ProductLineDetailResponse { - private Long productId; + + @Schema(description = "상품 id", example = "1") + private Long productLineId; + + @Schema(description = "상품 이름", example = "우유 모자") private String name; - private String brandName; + + @Schema(description = "상품 설명", example = "우유 모자입니다.") private String content; + + @Schema(description = "상품 가격", example = "10000") private int price; + + @Schema(description = "상품 전체 재고", example = "100") private Long totalStock; - private Long saleCount; - private ProductLineStatus productLineStatus; - private String biz_no; + + @Schema(description = "상품 상태", example = "FOR_SALE") + private ProductLineStatus status; + + @Schema(description = "상품 판매량", example = "10") + private Long saleCount; // ~개 판매중 + + @Schema(description = "상품 옵션") + private List productList; + + @Schema(description = "판매자 정보") + private SellerSimpleResponse seller; + + @Schema(description = "생성일시") private LocalDateTime createdAt; + + @Schema(description = "수정일시") private LocalDateTime modifiedAt; - private LocalDateTime deletedAt; - - public static ProductLineDetailResponse from(ProductLine productLine) { - return ProductLineDetailResponse.builder() - .productId(productLine.getProductLineId()) - .name(productLine.getName()) - .content(productLine.getContent()) - .brandName(productLine.getBrandName()) - .price(productLine.getPrice()) - .totalStock(productLine.getTotalStock()) - .saleCount(productLine.getSaleCount()) - .productLineStatus(productLine.getStatus()) - .biz_no(productLine.getBiz_no()) - .createdAt(productLine.getCreatedAt()) - .modifiedAt(productLine.getModifiedAt()) - .deletedAt(productLine.getDeletedAt()) - .build(); + + public ProductLineDetailResponse(ProductLineEntity productLine) { + this.productLineId = productLine.getProductLineId(); + this.name = productLine.getName(); + this.content = productLine.getContent(); + this.price = productLine.getPrice(); + this.totalStock = productLine.getProducts().stream().mapToLong(ProductEntity::getStock).sum(); + this.status = productLine.getStatus(); + this.saleCount = productLine.getSaleCount(); + this.createdAt = productLine.getCreatedAt(); + this.modifiedAt = productLine.getModifiedAt(); + this.seller = SellerSimpleResponse.from(productLine.getSeller()); + this.productList = productLine.getProducts().stream() + .map(ProductResponse::from) + .collect(Collectors.toList()); } -} \ No newline at end of file +} diff --git a/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineWithProductsJPAResponse.java b/src/main/java/org/store/clothstar/productLine/dto/response/ProductLinePaginationResponse.java similarity index 91% rename from src/main/java/org/store/clothstar/productLine/dto/response/ProductLineWithProductsJPAResponse.java rename to src/main/java/org/store/clothstar/productLine/dto/response/ProductLinePaginationResponse.java index 06eae968..bf4027a7 100644 --- a/src/main/java/org/store/clothstar/productLine/dto/response/ProductLineWithProductsJPAResponse.java +++ b/src/main/java/org/store/clothstar/productLine/dto/response/ProductLinePaginationResponse.java @@ -20,7 +20,7 @@ @Setter @AllArgsConstructor @NoArgsConstructor -public class ProductLineWithProductsJPAResponse { +public class ProductLinePaginationResponse { @Schema(description = "상품 id", example = "1") private Long productLineId; @@ -41,7 +41,7 @@ public class ProductLineWithProductsJPAResponse { private ProductLineStatus status; @Schema(description = "상품 옵션") - private List productList = new ArrayList<>(); + private List productList; @Schema(description = "상품 판매량", example = "10") private Long saleCount; // ~개 판매중 @@ -56,8 +56,7 @@ public class ProductLineWithProductsJPAResponse { @Schema(description = "수정일시") private LocalDateTime modifiedAt; - @QueryProjection - public ProductLineWithProductsJPAResponse(ProductLineEntity productLine, Seller seller, Long totalStock) { + public ProductLinePaginationResponse(ProductLineEntity productLine, Seller seller, Long totalStock) { this.productLineId = productLine.getProductLineId(); this.name = productLine.getName(); this.content = productLine.getContent(); diff --git a/src/main/java/org/store/clothstar/productLine/entity/ProductLineEntity.java b/src/main/java/org/store/clothstar/productLine/entity/ProductLineEntity.java index 35eb8f07..a90561d6 100644 --- a/src/main/java/org/store/clothstar/productLine/entity/ProductLineEntity.java +++ b/src/main/java/org/store/clothstar/productLine/entity/ProductLineEntity.java @@ -23,41 +23,33 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@BatchSize(size = 100) @Entity(name = "product_line") -//@Table(name = "product_line") public class ProductLineEntity extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long productLineId; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id", nullable = false) - private Seller seller; - - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "category_id", nullable = false) - private CategoryEntity category; - private String name; - private String content; - private int price; - -// private Long totalStock; + private Long saleCount; @Enumerated(EnumType.STRING) private ProductLineStatus status; - private Long saleCount; @OneToMany(mappedBy = "productLine", fetch = FetchType.LAZY, cascade = CascadeType.ALL) -// @JsonBackReference @JsonIgnore private List products; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id", nullable = false) + private CategoryEntity category; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + private Seller seller; + public void updateProductLine(UpdateProductLineRequest updateProductLineRequest) { this.name = updateProductLineRequest.getName(); this.content = updateProductLineRequest.getContent(); diff --git a/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustom.java b/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustom.java index 7e657ea2..757b1129 100644 --- a/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustom.java +++ b/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustom.java @@ -4,20 +4,14 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Repository; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; import org.store.clothstar.productLine.entity.ProductLineEntity; -import java.util.Optional; - @Repository public interface ProductLineRepositoryCustom { - Page getProductLinesWithOptions(Pageable pageable); - - Optional findProductLineWithOptionsById(Long productLineId); - Page findAllOffsetPaging(Pageable pageable, String keyword); + Page findAllOffsetPaging(Pageable pageable, String keyword); - Slice findAllSlicePaging(Pageable pageable, String keyword); + Slice findAllSlicePaging(Pageable pageable, String keyword); Page findEntitiesByCategoryWithOffsetPaging(Long categoryId, Pageable pageable, String keyword); diff --git a/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustomImpl.java b/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustomImpl.java index f6e63455..156d8720 100644 --- a/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustomImpl.java +++ b/src/main/java/org/store/clothstar/productLine/repository/ProductLineRepositoryCustomImpl.java @@ -9,18 +9,12 @@ import org.springframework.data.support.PageableExecutionUtils; import org.springframework.stereotype.Repository; import org.store.clothstar.member.domain.QSeller; -import org.store.clothstar.product.dto.response.ProductResponse; import org.store.clothstar.product.entity.QProductEntity; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; -import org.store.clothstar.productLine.dto.response.QProductLineWithProductsJPAResponse; import org.store.clothstar.productLine.entity.ProductLineEntity; import org.store.clothstar.productLine.entity.QProductLineEntity; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; @Repository @RequiredArgsConstructor @@ -33,64 +27,27 @@ public class ProductLineRepositoryCustomImpl implements ProductLineRepositoryCus QSeller qSeller = QSeller.seller; @Override - public Page getProductLinesWithOptions(Pageable pageable) { - List content = getProductLines(pageable, null); + public Page findAllOffsetPaging(Pageable pageable, String keyword) { + List content = getProductLines(pageable, keyword); - JPAQuery totalCount = jpaQueryFactory - .select(qProductLine.count()) - .from(qProductLine) - .where(qProductLine.deletedAt.isNull()); - - return PageableExecutionUtils.getPage(content, pageable, totalCount::fetchOne); - } - - @Override - public Optional findProductLineWithOptionsById(Long productLineId) { - // 1. ProductLine과 관련된 Seller와 총 재고량을 가져옴 - ProductLineWithProductsJPAResponse result = jpaQueryFactory - .select(new QProductLineWithProductsJPAResponse( - qProductLine, - qSeller, - qProduct.stock.sum() - )) - .from(qProductLine) - .innerJoin(qProductLine.seller, qSeller).fetchJoin() - .leftJoin(qProductLine.products, qProduct) - .where(qProductLine.productLineId.eq(productLineId) - .and(qProductLine.deletedAt.isNull())) - .groupBy(qProductLine.productLineId, qSeller) - .fetchOne(); - - // 2. ProductLine에 속한 Product들을 가져옴 - if (result != null) { - List productResponses = jpaQueryFactory - .selectFrom(qProduct) - .where(qProduct.productLine.productLineId.eq(productLineId)) - .fetch() - .stream() - .map(ProductResponse::from) - .collect(Collectors.toList()); - result.setProductList(productResponses); + boolean hasNext = false; + if (content.size() > pageable.getPageSize()) { + content.remove(content.size() - 1); + hasNext = true; } - return Optional.ofNullable(result); - } - - @Override - public Page findAllOffsetPaging(Pageable pageable, String keyword) { - List content = getProductLines(pageable, keyword); - JPAQuery totalCount = jpaQueryFactory - .select(qProductLine.count()) + .select(qProductLine.countDistinct()) .from(qProductLine) - .where(qProductLine.deletedAt.isNull().and(getSearchCondition(keyword))); + .where(qProductLine.deletedAt.isNull() + .and(getSearchCondition(keyword))); return PageableExecutionUtils.getPage(content, pageable, totalCount::fetchOne); } @Override - public Slice findAllSlicePaging(Pageable pageable, String keyword) { - List content = getProductLines(pageable, keyword); + public Slice findAllSlicePaging(Pageable pageable, String keyword) { + List content = getProductLines(pageable, keyword); boolean hasNext = false; if (content.size() > pageable.getPageSize()) { @@ -134,47 +91,19 @@ public Slice findEntitiesByCategoryWithSlicePaging(Long categ return new SliceImpl<>(content, pageable, hasNext); } - private List getProductLines(Pageable pageable, String keyword) { + private List getProductLines(Pageable pageable, String keyword) { List> orderSpecifiers = getOrderSpecifiers(pageable.getSort()); - BooleanExpression searchCondition = getSearchCondition(keyword); - - // 1. 모든 ProductLine을 가져옴 - List productLines = jpaQueryFactory - .select(new QProductLineWithProductsJPAResponse( - qProductLine, - qSeller, - qProduct.stock.sum() - )) + + // 카테고리별로 ProductLine 엔티티를 가져옴 + return jpaQueryFactory + .selectDistinct(qProductLine) .from(qProductLine) - .innerJoin(qProductLine.seller, qSeller).fetchJoin() - .leftJoin(qProductLine.products, qProduct) - .where(qProductLine.deletedAt.isNull().and(searchCondition)) - .groupBy(qProductLine.productLineId, qSeller) + .where(qProductLine.deletedAt.isNull() + .and(getSearchCondition(keyword))) .orderBy(orderSpecifiers.toArray(new OrderSpecifier[0])) .offset(pageable.getOffset()) .limit(pageable.getPageSize() + 1) .fetch(); - - // 2. 모든 Product를 가져옴 - Map> productMap = jpaQueryFactory - .selectFrom(qProduct) - .where(qProduct.productLine.productLineId.in( - productLines.stream() - .map(ProductLineWithProductsJPAResponse::getProductLineId) - .collect(Collectors.toList()) - )) - .fetch() - .stream() - .collect(Collectors.groupingBy( - p -> p.getProductLine().getProductLineId(), - Collectors.mapping(ProductResponse::from, Collectors.toList()) - )); - - // 3. ProductLine에 Product를 매핑 - productLines.forEach(productLine -> - productLine.setProductList(productMap.get(productLine.getProductLineId()))); - - return productLines; } private List getProductLineEntitiesByCategory(Long categoryId, Pageable pageable, String keyword) { diff --git a/src/main/java/org/store/clothstar/productLine/service/ProductLineService.java b/src/main/java/org/store/clothstar/productLine/service/ProductLineService.java index 8a1b8b8a..b86909a3 100644 --- a/src/main/java/org/store/clothstar/productLine/service/ProductLineService.java +++ b/src/main/java/org/store/clothstar/productLine/service/ProductLineService.java @@ -13,13 +13,11 @@ import org.store.clothstar.category.repository.CategoryJpaRepository; import org.store.clothstar.member.domain.Seller; import org.store.clothstar.member.repository.SellerRepository; -import org.store.clothstar.product.dto.response.ProductResponse; -import org.store.clothstar.product.entity.ProductEntity; import org.store.clothstar.productLine.domain.type.ProductLineStatus; import org.store.clothstar.productLine.dto.request.CreateProductLineRequest; import org.store.clothstar.productLine.dto.request.UpdateProductLineRequest; import org.store.clothstar.productLine.dto.response.ProductLineResponse; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; +import org.store.clothstar.productLine.dto.response.ProductLineDetailResponse; import org.store.clothstar.productLine.entity.ProductLineEntity; import org.store.clothstar.productLine.repository.ProductLineJPARepository; @@ -47,47 +45,45 @@ public List getAllProductLines() { } @Transactional(readOnly = true) - public Page getAllProductLinesWithProductsOffsetPaging(Pageable pageable, String keyword) { - return productLineRepository.findAllOffsetPaging(pageable, keyword); - } + public Page getAllProductLinesWithProductsOffsetPaging(Pageable pageable, String keyword) { + Page allOffsetPaging = productLineRepository.findAllOffsetPaging(pageable, keyword); - @Transactional(readOnly = true) - public Slice getAllProductLinesWithProductsSlicePaging(Pageable pageable, String keyword) { - return productLineRepository.findAllSlicePaging(pageable, keyword); + return allOffsetPaging.map(this::convertToDtoWithProducts); } @Transactional(readOnly = true) - public Optional getProductLine(Long productLineId) { - return productLineRepository.findById(productLineId) - .map(ProductLineResponse::from); + public Slice getAllProductLinesWithProductsSlicePaging(Pageable pageable, String keyword) { + Slice allSlicePaging = productLineRepository.findAllSlicePaging(pageable, keyword); + return allSlicePaging.map(this::convertToDtoWithProducts); } + @Deprecated @Transactional(readOnly = true) - public ProductLineWithProductsJPAResponse getProductLineWithProducts(Long productLineId) { - ProductLineWithProductsJPAResponse productLineWithProducts = - productLineRepository.findProductLineWithOptionsById(productLineId) - .orElseThrow(() -> new ResponseStatusException( - HttpStatus.BAD_REQUEST, "productLineId :" + productLineId + "인 상품 및 옵션 정보를 찾을 수 없습니다.")); - + public ProductLineDetailResponse getProductLineWithProducts(Long productLineId) { + ProductLineEntity productLine = productLineRepository.findById(productLineId) + .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "상품 정보를 찾을 수 없습니다.")); - return productLineWithProducts; + return convertToDtoWithProducts(productLine); } @Transactional - public Page getProductLinesByCategoryWithOffsetPaging(Long categoryId, Pageable pageable, String keyword) { - Page productLineEntities = productLineRepository.findEntitiesByCategoryWithOffsetPaging(categoryId, pageable, keyword); - return productLineEntities.map(this::convertToDtoWithProducts); + public Page getProductLinesByCategoryWithOffsetPaging(Long categoryId, Pageable pageable, String keyword) { + Page allOffsetPagingByCategory = productLineRepository.findEntitiesByCategoryWithOffsetPaging(categoryId, pageable, keyword); + + return allOffsetPagingByCategory.map(this::convertToDtoWithProducts); } @Transactional - public Slice getProductLinesByCategoryWithSlicePaging(Long categoryId, Pageable pageable, String keyword) { - Slice productLineEntities = productLineRepository.findEntitiesByCategoryWithSlicePaging(categoryId, pageable, keyword); - return productLineEntities.map(this::convertToDtoWithProducts); + public Slice getProductLinesByCategoryWithSlicePaging(Long categoryId, Pageable pageable, String keyword) { + Slice allSlicePagingByCategory = productLineRepository.findEntitiesByCategoryWithSlicePaging(categoryId, pageable, keyword); + + return allSlicePagingByCategory.map(this::convertToDtoWithProducts); } @Transactional public Long createProductLine(CreateProductLineRequest createProductLineRequest) { Long memberId = 1L; + Seller seller = sellerRepository.findById(memberId) .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "판매자 정보를 찾을 수 없습니다.")); @@ -115,24 +111,8 @@ public void setDeletedAt(Long productId) { productLine.delete(); } - private ProductLineWithProductsJPAResponse convertToDtoWithProducts(ProductLineEntity productLine) { - // 전체 재고량 계산 - Long totalStock = productLine.getProducts().stream().mapToLong(ProductEntity::getStock).sum(); - - // ProductLineWithProductsJPAResponse 객체 생성 - ProductLineWithProductsJPAResponse dto = new ProductLineWithProductsJPAResponse( - productLine, - productLine.getSeller(), - totalStock - ); - - // productList 설정 - List productResponses = productLine.getProducts().stream() - .map(ProductResponse::from) - .collect(Collectors.toList()); - dto.setProductList(productResponses); - - return dto; + private ProductLineDetailResponse convertToDtoWithProducts(ProductLineEntity productLine) { + return new ProductLineDetailResponse(productLine); } public List findByIdIn(List productLineIds) { diff --git a/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java b/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java index f2b9a0d0..90a265be 100644 --- a/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java +++ b/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java @@ -1,5 +1,6 @@ package org.store.clothstar.productLine.service; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -15,7 +16,7 @@ import org.store.clothstar.productLine.dto.request.CreateProductLineRequest; import org.store.clothstar.productLine.dto.request.UpdateProductLineRequest; import org.store.clothstar.productLine.dto.response.ProductLineResponse; -import org.store.clothstar.productLine.dto.response.ProductLineWithProductsJPAResponse; +import org.store.clothstar.productLine.dto.response.ProductLineDetailResponse; import org.store.clothstar.productLine.entity.ProductLineEntity; import org.store.clothstar.productLine.repository.ProductLineJPARepository; @@ -91,51 +92,20 @@ public void givenProductLines_whenGetProductLineList_thenGetProductLines() { assertThat(response.get(0).getBrandName()).isEqualTo("브랜드1"); } - @DisplayName("product_line_id로 상품 단건 조회에 성공한다.") - @Test - public void givenProductLineId_whenGetProductLineById_thenProductLineReturned() { - // given - Long productLineId = 1L; - ProductLineEntity productLine = mock(ProductLineEntity.class); - Seller seller = mock(Seller.class); - - when(productLine.getProductLineId()).thenReturn(productLineId); - when(productLine.getSeller()).thenReturn(seller); - when(seller.getBrandName()).thenReturn("내셔널지오그래픽키즈 제주점"); - when(productLine.getName()).thenReturn("내셔널지오그래픽 곰돌이 후드티"); - when(productLine.getContent()).thenReturn("귀여운 곰돌이가 그려진 후드티에요!"); - when(productLine.getPrice()).thenReturn(69000); - when(productLine.getStatus()).thenReturn(ProductLineStatus.ON_SALE); - - given(productLineRepository.findById(productLineId)).willReturn(Optional.of(productLine)); - - // when - Optional response = productLineService.getProductLine(productLineId); - - // then - assertThat(response).isPresent(); - response.ifPresent(productLineResponse -> { - assertThat(productLineResponse.getBrandName()).isEqualTo("내셔널지오그래픽키즈 제주점"); - assertThat(productLineResponse.getName()).isEqualTo("내셔널지오그래픽 곰돌이 후드티"); - assertThat(productLineResponse.getContent()).isEqualTo("귀여운 곰돌이가 그려진 후드티에요!"); - assertThat(productLineResponse.getPrice()).isEqualTo(69000); - assertThat(productLineResponse.getProductLineStatus()).isEqualTo(ProductLineStatus.ON_SALE); - }); - } - + @Disabled @DisplayName("상품 id와 상품과 1:N 관계에 있는 상품 옵션 리스트를 조회한다.") @Test public void givenProductLineId_whenGetProductLineWithProducts_thenProductLineWithProducts() { // given Long productLineId = 1L; - ProductLineWithProductsJPAResponse mockResponse = mock(ProductLineWithProductsJPAResponse.class); + ProductLineDetailResponse mockResponse = mock(ProductLineDetailResponse.class); when(mockResponse.getProductLineId()).thenReturn(productLineId); when(mockResponse.getTotalStock()).thenReturn(90L); - given(productLineRepository.findProductLineWithOptionsById(productLineId)).willReturn(Optional.of(mockResponse)); +// given(productLineRepository.findProductLineWithOptionsById(productLineId)).willReturn(Optional.of(mockResponse)); // when - ProductLineWithProductsJPAResponse response = productLineService.getProductLineWithProducts(productLineId); + ProductLineDetailResponse response = productLineService.getProductLineWithProducts(productLineId); // then assertThat(response).isNotNull();