From fee482d7c351b9267044855033f7b10b373863d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=83=81=ED=9B=88?= Date: Wed, 10 Jul 2024 19:44:12 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[KAN-161]=20feat(product):=20BE=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EC=99=B8=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/product/dto/{ProductDetail.java => ProductRes.java} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/{ProductDetail.java => ProductRes.java} (100%) diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductDetail.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java similarity index 100% rename from server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductDetail.java rename to server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java From 20ad34e513d23c6bd089684f191d557e53c5d018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=83=81=ED=9B=88?= Date: Wed, 10 Jul 2024 19:44:35 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[KAN-161]=20feat(product):=20BE=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EC=A0=9C=EC=99=B8=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/repository/BaseCustomRepository.java | 4 + .../product/controller/ProductController.java | 19 +-- .../domain/product/dto/ProductRes.java | 7 +- .../repository/ProductCustomRepository.java | 116 ++++++++++++++++-- .../product/service/ProductService.java | 37 +++++- 5 files changed, 158 insertions(+), 25 deletions(-) diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/base/repository/BaseCustomRepository.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/base/repository/BaseCustomRepository.java index 2afe343c..c3b6bf3d 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/base/repository/BaseCustomRepository.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/base/repository/BaseCustomRepository.java @@ -99,6 +99,10 @@ protected BooleanExpression contractProductNotDel() { return contractProduct.deleted.isFalse(); } + protected BooleanExpression productNotDel() { + return product.deleted.isFalse(); + } + protected BooleanExpression memberNameContains(String memberName) { return hasText(memberName) ? member.name.containsIgnoreCase(memberName) : null; } diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java index c98e53d4..8849f02c 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java @@ -1,7 +1,7 @@ package kr.or.kosa.cmsplusmain.domain.product.controller; -import kr.or.kosa.cmsplusmain.domain.product.dto.ProductDetail; -import kr.or.kosa.cmsplusmain.domain.product.entity.Product; +import kr.or.kosa.cmsplusmain.domain.base.dto.SortPageDto; +import kr.or.kosa.cmsplusmain.domain.product.dto.ProductRes; import kr.or.kosa.cmsplusmain.domain.product.service.ProductService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; @@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + @RestController @RequestMapping("/api/v1/vendor/product") @RequiredArgsConstructor @@ -17,13 +19,16 @@ public class ProductController { private final ProductService productService; @GetMapping("/{productId}") - public ProductDetail getProduct(@PathVariable("productId") Long productId) { + public ProductRes getProduct(@PathVariable("productId") Long productId) { + String vendorUserName = "vendor1"; + productService.validateProductUser(productId, vendorUserName); return productService.findById(productId); } - - - - + @GetMapping + public SortPageDto.Res getProductListItem(SortPageDto.Req pageable) { + String vendorUserName = "vendor1"; + return productService.findProductsByUser(vendorUserName, pageable); + } } diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java index b566c685..071e3d26 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java @@ -1,6 +1,5 @@ package kr.or.kosa.cmsplusmain.domain.product.dto; -import kr.or.kosa.cmsplusmain.domain.contract.entity.Contract; import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import lombok.Builder; import lombok.Getter; @@ -10,7 +9,7 @@ @Getter @Builder - public class ProductDetail { + public class ProductRes { private final Long productId; private final String productName; @@ -22,8 +21,8 @@ public class ProductDetail { private final int contractNum; // 계약 건수 - public static ProductDetail fromEntity(Product product, int contractNum) { - return ProductDetail.builder() + public static ProductRes fromEntity(Product product, int contractNum) { + return ProductRes.builder() .productId(product.getId()) .productName(product.getName()) .createdDateTime(product.getCreatedDateTime()) diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java index 854eab14..fc161a8b 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java @@ -1,13 +1,21 @@ package kr.or.kosa.cmsplusmain.domain.product.repository; +import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; +import kr.or.kosa.cmsplusmain.domain.base.dto.SortPageDto; import kr.or.kosa.cmsplusmain.domain.base.repository.BaseCustomRepository; +import kr.or.kosa.cmsplusmain.domain.product.dto.ProductRes; import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import org.springframework.stereotype.Repository; +import java.util.List; +import java.util.stream.Collectors; + import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContract.contract; import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContractProduct.contractProduct; +import static kr.or.kosa.cmsplusmain.domain.product.entity.QProduct.product; +import static kr.or.kosa.cmsplusmain.domain.vendor.entity.QVendor.vendor; @Repository public class ProductCustomRepository extends BaseCustomRepository { @@ -16,20 +24,112 @@ public ProductCustomRepository(EntityManager em, JPAQueryFactory jpaQueryFactory super(em, jpaQueryFactory); } + // 상품이 매핑되어있는 계약수 public int getContractNumber(Long productId) { - -// 상품이 포함된 계약의 개수를 구하는 sql -// select count(distinct pc.contract_id) -// from product_contract pc -// join contract c -// where pc.product_id = #{productId} and c.deleted = 0 + /* + * 상품이 포함된 계약의 개수를 구함 + * select count(distinct pc.contract_id) + * from contract_product cp + * join contract c + * where cp.product_id = #{productId} and c.deleted = 0 + * */ return jpaQueryFactory .select(contract.id.countDistinct()) .from(contractProduct) .join(contractProduct.contract, contract) // 계약-상품 테이블의 외래키인 계약ID를 타고 들어감 - .where(contractProduct.product.id.eq(productId), contract.deleted.eq(false)) + .where(contractProduct.product.id.eq(productId), + contractNotDel()) .fetchOne().intValue(); + } + + // 고객의 상품 목록 + public List findProductListWithCondition(String vendorUserName, SortPageDto.Req pageable) { + /* + * 해당 고객의 모든 상품(삭제되지않은)을 가져오는데, 상품의 정보와 상품이 포함된 계약 갯수를 가져와야함 + * + * 해당 고객의 모든 상품(삭제되지않은) + * select * + * from product p + * join vendor v + * where v.vendor_userName = #{userName} and p.deleted = 0 + * + * 상품의 정보와 상품이 포함된 계약 갯수 + * select count(distinct pc.contract_id) + * from product_contract pc + * join contract c + * where pc.product_id = #{productId} and c.deleted = 0 + * + * 1. 해당 고객의 모든 상품(삭제되지않은)을 가져오는데, 상품의 정보와 상품이 포함된 계약 갯수를 가져와야함 + * select vendor_product.* count(distinct pc.contract_id) + * from (select * + * from product p + * join vendor v + * where v.vendor_userName = #{userName} and p.deleted = 0) vp , product_contract pc + * join contract c + * where pc.product_id = vp.product_id and c.deleted = 0 + * + * 2. (최종) + * select p.*, count(distinct cp.contract_id) as contract_count + * from product p + * join vendor v on v.vendor_id = p.vendor_id + * left join contract_product cp on cp.product_id = p.product_id and cp.deleted = 0 + * left join contract c on c.contract_id = cp.contract_id and c.deleted = 0 + * where v.vendor_username = 'vendor1' and p.deleted = 0 + * group by p.product_id; + * */ + List result = jpaQueryFactory // 프로젝션 대상이 2개이므로 튜플 사용 + .select(product, contractProduct.contract.countDistinct()) + .from(product) + .join(product.vendor, vendor) + .leftJoin(contractProduct) + .on(contractProduct.product.eq(product), + (contractProductNotDel())) + .leftJoin(contract) + .on(contractProduct.contract.eq(contract), + (contractNotDel())) + .where( + vendor.username.eq(vendorUserName), + productNotDel() + ) + .groupBy(product.id) + .offset(pageable.getPage()) + .limit(pageable.getSize()) + .fetch(); + + return result; + } + + // 고객의 상품 총 갯수 + public int countAllProducts(String vendorUsername) { + return jpaQueryFactory + .select(product.id.count()) + .from(product) + .join(product.vendor, vendor) + .where( + vendorUsernameEq(vendorUsername), + productNotDel() + ) + .fetchOne().intValue(); + } + + // 특정 고객이 본인의 상품이 아닌거 조회하는거 처리 + public boolean isExistProductByUsername(Long productId, String vendorUsername) { + /* + * 고객테이블에 있는 고객이름이 해당 상품의 고객ID의 이름인지 확인 + * select 1 + * from product p + * join vendor v on p.vendor_id = v.vendor_id + * where p.product_id = #{productId} and v.vendor_username = #{vendorUsername} + * */ + Integer count = jpaQueryFactory + .selectOne() + .from(product) + .join(product.vendor, vendor) + .where(product.id.eq(productId), + vendor.username.eq(vendorUsername)) + .fetchFirst(); + return count != null; } -} +} \ No newline at end of file diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java index 15d06d5d..a9aedf50 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java @@ -1,14 +1,20 @@ - package kr.or.kosa.cmsplusmain.domain.product.service; +import com.querydsl.core.Tuple; +import kr.or.kosa.cmsplusmain.domain.base.dto.SortPageDto; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import kr.or.kosa.cmsplusmain.domain.product.dto.ProductDetail; +import kr.or.kosa.cmsplusmain.domain.product.dto.ProductRes; import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import kr.or.kosa.cmsplusmain.domain.product.repository.ProductCustomRepository; import kr.or.kosa.cmsplusmain.domain.product.repository.ProductRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import java.util.List; +import java.util.stream.Collectors; + +import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContractProduct.contractProduct; +import static kr.or.kosa.cmsplusmain.domain.product.entity.QProduct.product; @Slf4j @Service @@ -19,8 +25,7 @@ public class ProductService { private final ProductRepository productRepository; private final ProductCustomRepository productCustomRepository; - public ProductDetail findById(Long productId) { - + public ProductRes findById(Long productId) { // 계약 건수 int contractNum = productCustomRepository .getContractNumber(productId); @@ -31,9 +36,29 @@ public ProductDetail findById(Long productId) { .orElseThrow(() -> new IllegalArgumentException("Product not found")); // 계약 건수 + 상품 정보 - return ProductDetail.fromEntity(product, contractNum); + return ProductRes.fromEntity(product, contractNum); + } + public SortPageDto.Res findProductsByUser(String vendorUserName, SortPageDto.Req pageable) { + int countProductListItem = productCustomRepository.countAllProducts(vendorUserName); + int totalPages = (int) Math.ceil((double) countProductListItem / pageable.getSize()); + List productListTuples = productCustomRepository.findProductListWithCondition(vendorUserName, pageable); + + List productList = productListTuples + .stream() + .map(tuple -> ProductRes.fromEntity( + tuple.get(product), // 튜플 stream + tuple.get(contractProduct.contract.countDistinct()).intValue() + )) + .collect(Collectors.toList()); + + return new SortPageDto.Res<>(totalPages, productList); } -} + public void validateProductUser(Long productId, String vendorUserName) { + if (!productCustomRepository.isExistProductByUsername(productId, vendorUserName)) { + throw new IllegalArgumentException("Not Owner"); + } + } +} \ No newline at end of file From 8721e0e0dfb283cb4c1e04abcd1ace49e705e973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=83=81=ED=9B=88?= Date: Wed, 10 Jul 2024 20:40:50 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[KAN-161]=20refactor(product):=20BE=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=ED=94=84=EB=A1=9C=EC=A0=9D=EC=85=98=20DTO?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20service=EC=99=80=20re?= =?UTF-8?q?pository=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../product/controller/ProductController.java | 5 +- .../domain/product/dto/ProductQRes.java | 33 ++++++++++++ .../domain/product/dto/ProductRes.java | 52 +++++++++---------- .../repository/ProductCustomRepository.java | 13 +++-- .../product/service/ProductService.java | 31 +++++------ 5 files changed, 80 insertions(+), 54 deletions(-) create mode 100644 server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductQRes.java diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java index 8849f02c..e006ca2d 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/controller/ProductController.java @@ -9,8 +9,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RestController @RequestMapping("/api/v1/vendor/product") @RequiredArgsConstructor @@ -21,8 +19,7 @@ public class ProductController { @GetMapping("/{productId}") public ProductRes getProduct(@PathVariable("productId") Long productId) { String vendorUserName = "vendor1"; - productService.validateProductUser(productId, vendorUserName); - return productService.findById(productId); + return productService.findById(productId, vendorUserName); } @GetMapping diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductQRes.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductQRes.java new file mode 100644 index 00000000..47a51b27 --- /dev/null +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductQRes.java @@ -0,0 +1,33 @@ +package kr.or.kosa.cmsplusmain.domain.product.dto; + +import com.querydsl.core.annotations.QueryProjection; +import kr.or.kosa.cmsplusmain.domain.product.entity.Product; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class ProductQRes { + + private final Product product; + private final int contractNumber; + + // 쿼리프로젝션을 이용해서 repository->service용 DTO + @QueryProjection + public ProductQRes(Product product, int contractNumber) { + this.product = product; + this.contractNumber = contractNumber; + } + + public ProductRes toProductRes() { + return ProductRes.builder() + .productId(product.getId()) + .productName(product.getName()) + .productPrice(product.getPrice()) + .productMemo(product.getMemo()) + .contractNumber(contractNumber) + .createdDateTime(product.getCreatedDateTime()) // 엔티티에서 가져옴 + .build(); + } + +} \ No newline at end of file diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java index 071e3d26..9920bd73 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/dto/ProductRes.java @@ -3,33 +3,29 @@ import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import lombok.Builder; import lombok.Getter; - import java.time.LocalDateTime; - - @Getter - @Builder - public class ProductRes { - - private final Long productId; - private final String productName; - - private final LocalDateTime createdDateTime; - - private final int productPrice; - private final String productMemo; - - private final int contractNum; // 계약 건수 - - public static ProductRes fromEntity(Product product, int contractNum) { - return ProductRes.builder() - .productId(product.getId()) - .productName(product.getName()) - .createdDateTime(product.getCreatedDateTime()) - .productPrice(product.getPrice()) - .productMemo(product.getMemo()) - .contractNum(contractNum) - .build(); - } - - } \ No newline at end of file +@Getter +@Builder +public class ProductRes { + + private final Long productId; + private final String productName; + private final LocalDateTime createdDateTime; + private final int productPrice; + private final String productMemo; + + private final int contractNumber; // 계약 건수 + + public static ProductRes fromEntity(Product product, int contractNumber) { + return ProductRes.builder() + .productId(product.getId()) + .productName(product.getName()) + .createdDateTime(product.getCreatedDateTime()) + .productPrice(product.getPrice()) + .productMemo(product.getMemo()) + .contractNumber(contractNumber) + .build(); + } + +} \ No newline at end of file diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java index fc161a8b..b4bf062b 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/repository/ProductCustomRepository.java @@ -1,16 +1,14 @@ package kr.or.kosa.cmsplusmain.domain.product.repository; -import com.querydsl.core.Tuple; import com.querydsl.jpa.impl.JPAQueryFactory; import jakarta.persistence.EntityManager; import kr.or.kosa.cmsplusmain.domain.base.dto.SortPageDto; import kr.or.kosa.cmsplusmain.domain.base.repository.BaseCustomRepository; -import kr.or.kosa.cmsplusmain.domain.product.dto.ProductRes; +import kr.or.kosa.cmsplusmain.domain.product.dto.ProductQRes; +import kr.or.kosa.cmsplusmain.domain.product.dto.QProductQRes; import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import org.springframework.stereotype.Repository; - import java.util.List; -import java.util.stream.Collectors; import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContract.contract; import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContractProduct.contractProduct; @@ -43,7 +41,8 @@ public int getContractNumber(Long productId) { } // 고객의 상품 목록 - public List findProductListWithCondition(String vendorUserName, SortPageDto.Req pageable) { + // 프로젝션 대상이 2개이기 떄문에 QueryProjection을 이용해 해결 + public List findProductListWithCondition(String vendorUserName, SortPageDto.Req pageable) { /* * 해당 고객의 모든 상품(삭제되지않은)을 가져오는데, 상품의 정보와 상품이 포함된 계약 갯수를 가져와야함 * @@ -77,8 +76,8 @@ public List findProductListWithCondition(String vendorUserName, SortPageD * where v.vendor_username = 'vendor1' and p.deleted = 0 * group by p.product_id; * */ - List result = jpaQueryFactory // 프로젝션 대상이 2개이므로 튜플 사용 - .select(product, contractProduct.contract.countDistinct()) + List result = jpaQueryFactory + .select(new QProductQRes(product, contractProduct.contract.countDistinct().intValue())) .from(product) .join(product.vendor, vendor) .leftJoin(contractProduct) diff --git a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java index a9aedf50..b10b622d 100644 --- a/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java +++ b/server/src/main/java/kr/or/kosa/cmsplusmain/domain/product/service/ProductService.java @@ -1,20 +1,15 @@ package kr.or.kosa.cmsplusmain.domain.product.service; -import com.querydsl.core.Tuple; import kr.or.kosa.cmsplusmain.domain.base.dto.SortPageDto; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import kr.or.kosa.cmsplusmain.domain.product.dto.ProductRes; import kr.or.kosa.cmsplusmain.domain.product.entity.Product; import kr.or.kosa.cmsplusmain.domain.product.repository.ProductCustomRepository; import kr.or.kosa.cmsplusmain.domain.product.repository.ProductRepository; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.stream.Collectors; - -import static kr.or.kosa.cmsplusmain.domain.contract.entity.QContractProduct.contractProduct; -import static kr.or.kosa.cmsplusmain.domain.product.entity.QProduct.product; @Slf4j @Service @@ -25,7 +20,12 @@ public class ProductService { private final ProductRepository productRepository; private final ProductCustomRepository productCustomRepository; - public ProductRes findById(Long productId) { + // 상품 상세 조회 + public ProductRes findById(Long productId, String vendorUserName) { + + // 해당 상품들 주인이 맞는지 검증 + validateProductUser(productId, vendorUserName); + // 계약 건수 int contractNum = productCustomRepository .getContractNumber(productId); @@ -37,24 +37,25 @@ public ProductRes findById(Long productId) { // 계약 건수 + 상품 정보 return ProductRes.fromEntity(product, contractNum); + } + // 상품 목록 조회 public SortPageDto.Res findProductsByUser(String vendorUserName, SortPageDto.Req pageable) { + int countProductListItem = productCustomRepository.countAllProducts(vendorUserName); int totalPages = (int) Math.ceil((double) countProductListItem / pageable.getSize()); - List productListTuples = productCustomRepository.findProductListWithCondition(vendorUserName, pageable); - List productList = productListTuples + List productList = productCustomRepository.findProductListWithCondition(vendorUserName, pageable) .stream() - .map(tuple -> ProductRes.fromEntity( - tuple.get(product), // 튜플 stream - tuple.get(contractProduct.contract.countDistinct()).intValue() - )) - .collect(Collectors.toList()); + .map(pqr -> pqr.toProductRes()) + .toList(); return new SortPageDto.Res<>(totalPages, productList); + } + // 유효성 검증 public void validateProductUser(Long productId, String vendorUserName) { if (!productCustomRepository.isExistProductByUsername(productId, vendorUserName)) { throw new IllegalArgumentException("Not Owner"); From d5115ac0c0d469716dba96c367ed99a888e5d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EC=83=81=ED=9B=88?= Date: Wed, 10 Jul 2024 20:41:14 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[KAN-161]=20refactor(product):=20BE=20?= =?UTF-8?q?=EC=BF=BC=EB=A6=AC=20=ED=94=84=EB=A1=9C=EC=A0=9D=EC=85=98=20DTO?= =?UTF-8?q?=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20service=EC=99=80=20re?= =?UTF-8?q?pository=20=EB=A1=9C=EC=A7=81=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/vendor/modal/ProductModal.jsx | 2 -- .../pages/vendor/product/ProductListPage.jsx | 22 +++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/client/src/components/vendor/modal/ProductModal.jsx b/client/src/components/vendor/modal/ProductModal.jsx index 286107c7..35fac286 100644 --- a/client/src/components/vendor/modal/ProductModal.jsx +++ b/client/src/components/vendor/modal/ProductModal.jsx @@ -12,8 +12,6 @@ const ProductModal = ({ isShowModal, setIsShowModal, modalTitle, productDetailDa return
; } - console.log(productDetailData); - return ( { - const [isShowModal, setIsShowModal] = useState(false); - const [modalTitle, setModalTitle] = useState(''); //모달 제목 상태 - const [productId, setProductId] = useState(''); + const [isShowModal, setIsShowModal] = useState(false); // 모달 on,off + const [modalTitle, setModalTitle] = useState(''); // 모달 제목 상태 + const [productId, setProductId] = useState(''); // 상품ID const [productList, setProductList] = useState([]); // 상품 목록 const [productDetailData, setProductDetailData] = useState(null); // 상품 상세 정보 + const [pageNum, setPageNum] = useState(''); // 페이지번호 + const [size, setSize] = useState(''); // 페이지 사이즈 // 상품 상세 조회용 더미데이터(상품 목록 조회에서 가져온 데이터라 가정) const dummyData = { @@ -44,9 +46,9 @@ const ProductListPage = () => { }; // 컴포넌트 마운트시 더미데이터 세팅 - useEffect(() => { - setProductId(dummyData.data[0].id); - }, []); + // useEffect(() => { + // setProductId(dummyData.data[0].id); + // }, []); // useEffect(() => { // const fetchProductList = async () => { @@ -80,6 +82,8 @@ const ProductListPage = () => { } }; + const pageButtonClickHandle = () => {}; + return (
@@ -101,6 +105,10 @@ const ProductListPage = () => { modalTitle={modalTitle} productDetailData={productDetailData} /> + + + +
); };