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 914bbab..63da2b8 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/productLine/controller/ProductLineController.java b/src/main/java/org/store/clothstar/productLine/controller/ProductLineController.java index 3f9f129..bef3864 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; @@ -40,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); } 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 85474da..fa345bf 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,77 @@ 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; // ~개 판매중 + + @Builder.Default + @Schema(description = "상품 옵션") + private List productList = new ArrayList<>(); + + @Schema(description = "판매자 정보") + private SellerSimpleResponse seller; + + @Schema(description = "생성일시") + @JsonSerialize(using = LocalDateTimeSerializer.class) 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(); + + @QueryProjection + 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 94% 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 d8cd979..3674b88 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; @@ -58,7 +58,7 @@ public class ProductLineWithProductsJPAResponse { 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/service/ProductLineService.java b/src/main/java/org/store/clothstar/productLine/service/ProductLineService.java index 0eaf28c..8b3b138 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; @@ -46,21 +44,21 @@ public List getAllProductLines() { } @Transactional(readOnly = true) - public Page getAllProductLinesWithProductsOffsetPaging(Pageable pageable, String keyword) { + public Page getAllProductLinesWithProductsOffsetPaging(Pageable pageable, String keyword) { Page allOffsetPaging = productLineRepository.findAllOffsetPaging(pageable, keyword); return allOffsetPaging.map(this::convertToDtoWithProducts); } @Transactional(readOnly = true) - public Slice getAllProductLinesWithProductsSlicePaging(Pageable pageable, String keyword) { + 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) { + public ProductLineDetailResponse getProductLineWithProducts(Long productLineId) { ProductLineEntity productLine = productLineRepository.findById(productLineId) .orElseThrow(() -> new ResponseStatusException(HttpStatus.BAD_REQUEST, "상품 정보를 찾을 수 없습니다.")); @@ -68,14 +66,14 @@ public ProductLineWithProductsJPAResponse getProductLineWithProducts(Long produc } @Transactional - public Page getProductLinesByCategoryWithOffsetPaging(Long categoryId, Pageable pageable, String keyword) { + 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) { + public Slice getProductLinesByCategoryWithSlicePaging(Long categoryId, Pageable pageable, String keyword) { Slice allSlicePagingByCategory = productLineRepository.findEntitiesByCategoryWithSlicePaging(categoryId, pageable, keyword); return allSlicePagingByCategory.map(this::convertToDtoWithProducts); @@ -112,24 +110,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 7050d4c..9e0ce0c 100644 --- a/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java +++ b/src/test/java/org/store/clothstar/productLine/service/ProductLineServiceTest.java @@ -1,6 +1,5 @@ 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; @@ -16,7 +15,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; @@ -97,14 +96,14 @@ public void givenProductLines_whenGetProductLineList_thenGetProductLines() { 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)); // when - ProductLineWithProductsJPAResponse response = productLineService.getProductLineWithProducts(productLineId); + ProductLineDetailResponse response = productLineService.getProductLineWithProducts(productLineId); // then assertThat(response).isNotNull();