빠른배송..
처음 문제는 같은 사이즈의 데이터에 대해서 판매가격이 여러개일 경우 여러개를 동시에 띄우는게 문제였음.
이건 가격이 낮은 1개의 데이터만 출력(limit)하면 되서 문제가 아닌데..
이렇게 하면 빠른배송 상품이 일반배송 상품보다 가격이 높을경우 빠른배송 상품이 없는것 처럼 보임
빠른 배송 상품이 존재 할경우 빠른배송 상품 마크는 띄우되 가격은 더 낮은 일반배송 가격을 띄우고 사이즈를 선택했을때 빠른배송, 일반배송 버튼 각각에 가격을 띄워야 하는데...
이걸 front 단에서 filter를 걸어서 하려고 했음
왜냐면 쿼리로 구현하는게 너무 복잡한것 같아서
그런데 문제는
1. foreach를 써서 filter를 하니 데이터가 몇개 없는데도 꽤나 무겁게 느껴짐
2. 사이즈별 데이터 foreach 돌려서
백엔드로 로직 짜는게 훨씬 간편하고 쉽구나... 프론트로는 데이터를 띄우는데만 집중할것
// repository
//보관상품 데이터만 출력
@Query(value="SELECT "
+ "new com.example.ballis.DTO.ProductBuyDTO"
+ "(prod.id, prod.productEngName, prod.productKorName, prod.modelNumber, prod.sizeMin, prod.sizeMax, prod.sizeUnit, "
+ "img.imagePath, sell.sellingStatus, sell.productSize, MIN(sell.wishPrice), sell.inventoryDiv, sell.member.memberNumber) "
+ "FROM Product prod "
+ "INNER JOIN Image img ON prod.id = img.targetId "
+ "LEFT JOIN Selling sell ON prod.id = sell.product "
+ "WHERE prod.id = :productid "
+ "AND img.pageDiv = 1 AND sell.sellingStatus = 1 AND sell.inventoryDiv = 1 "
+ "GROUP BY prod.id, prod.productEngName, prod.productKorName, prod.modelNumber, prod.sizeMin, "
+ "prod.sizeMax, prod.sizeUnit, img.imagePath, sell.sellingStatus, sell.productSize, sell.inventoryDiv, sell.member.memberNumber "
+ "ORDER BY MIN(sell.wishPrice) ASC"
,nativeQuery = false)
List<ProductBuyDTO> getFastProduct(@Param("productid") Long productid);
// 일반상품 데이터만 출력
@Query(value="SELECT "
+ "new com.example.ballis.DTO.ProductBuyDTO"
+ "(prod.id, prod.productEngName, prod.productKorName, prod.modelNumber, prod.sizeMin, prod.sizeMax, prod.sizeUnit, "
+ "img.imagePath, sell.sellingStatus, sell.productSize, MIN(sell.wishPrice), sell.inventoryDiv, sell.member.memberNumber) "
+ "FROM Product prod "
+ "INNER JOIN Image img ON prod.id = img.targetId "
+ "LEFT JOIN Selling sell ON prod.id = sell.product "
+ "WHERE prod.id = :productid "
+ "AND img.pageDiv = 1 AND sell.sellingStatus = 1 AND sell.inventoryDiv = 2 "
+ "GROUP BY prod.id, prod.productEngName, prod.productKorName, prod.modelNumber, prod.sizeMin, "
+ "prod.sizeMax, prod.sizeUnit, img.imagePath, sell.sellingStatus, sell.productSize, sell.inventoryDiv, sell.member.memberNumber "
+ "ORDER BY MIN(sell.wishPrice) ASC"
,nativeQuery = false)
List<ProductBuyDTO> getNormalProduct(@Param("productid") Long productid);
서비스에서는 기존 쿼리를 재활용해서 보관상품 데이터와 일반상품 데이터를 구분해서 출력하도록 했다. 이때 sell.productSize로 group by하고 MIN(sell.wishPrice)를 select함으로써 각 사이즈에 대해 가장 낮은 판매가격을 가진 데이터만 출력하도록 했음
//service
// 빠른 배송 상품 중 각 사이즈별 최저가 데이터만 출력
public List<ProductBuyDTO> getFastProduct(Long productid) {
return productRepository.getFastProduct(productid);
}
// 일반 배송 상품 중 각 사이즈별 최저가 데이터만 출력
public List<ProductBuyDTO> getNormalProduct(Long productid) {
return productRepository.getNormalProduct(productid);
}
// 각 사이즈별 빠른 배송, 일반 배송 상품 중 판매가격이 더 낮은 데이터만 출력
public List<ProductBuyDTO> getCheaperProduct(Long productid) {
List<ProductBuyDTO> fastProducts = getFastProduct(productid);
List<ProductBuyDTO> normalProducts = getNormalProduct(productid);
List<ProductBuyDTO> result = new ArrayList<>();
for (ProductBuyDTO fastProduct : fastProducts) {
boolean isSizeMatched = false;
for(ProductBuyDTO normalProduct : normalProducts) {
if(fastProduct.getSellProductSize().equals(normalProduct.getSellProductSize())) {
result.add(fastProduct.getSellWishPrice() <= normalProduct.getSellWishPrice() ? fastProduct : normalProduct);
isSizeMatched = true;
break;
}
}
if (!isSizeMatched) {
result.add(fastProduct);
}
}
for (ProductBuyDTO normalProduct : normalProducts) {
boolean isSizeMatched = false;
for(ProductBuyDTO fastProduct : fastProducts) {
if(normalProduct.getSellProductSize().equals(fastProduct.getSellProductSize())) {
isSizeMatched = true;
break;
}
}
if (!isSizeMatched) {
result.add(normalProduct);
}
}
return result;
}
첫번째 for 문에서 빠른배송 상품에 대해 사이즈가 일치하는 일반배송 상품이 존재하는지 체크하고
1. 존재한다면 둘중 sellWishPrice가 더 작은 데이터를 result에 넣어주고 isSizeMatched를 true로 바꿈.
2. 존재하지 않는다면 isSizeMatched 값은 default인 false이고 이때는 빠른배송 상품을 result에 넣어준다(빠른 배송상품을 기준으로 for문을 돌렸으므로)
첫번째 for문으로 빠른배송 상품과 일반배송 상품이 둘다 존재할때, 빠른배송 상품만 존재할때의 경우는 데이터를 입력 받지만 일반배송상품만 존재할때는 데이터를 입력받지 못함
두번째 for문에서 일반배송 상품에 대해 사이즈가 일치하는 빠른배송 상품이 존재하는지 체크한다. 코드 낭비 같지만... 이렇게 하지 않으면 일반배송 상품만 존재하는 경우를 체크할 수가 없음
이렇게 각 사이즈별로 빠른배송만 존재하는경우, 일반배송만 존재하는경우, 빠른배송 일반배송 둘다 존재하는경우, 3가지 경우에 대해 최저가를 가지는 데이터만 출력하도록 함
// controller
@GetMapping("/api/get/product/buy/fast")
public ResponseEntity<List<ProductBuyDTO>> getFastProduct(@RequestParam Long productid) {
List<ProductBuyDTO> lists = productService.getFastProduct(productid);
return new ResponseEntity<>(lists, HttpStatus.OK);
}
@GetMapping("/api/get/product/buy/normal")
public ResponseEntity<List<ProductBuyDTO>> getNormalProduct(@RequestParam Long productid) {
List<ProductBuyDTO> lists = productService.getNormalProduct(productid);
return new ResponseEntity<>(lists, HttpStatus.OK);
}
@GetMapping("/api/get/product/buy/cheaper")
public ResponseEntity<List<ProductBuyDTO>> getCheaperProduct(@RequestParam Long productid) {
List<ProductBuyDTO> lists = productService.getCheaperProduct(productid);
return new ResponseEntity<>(lists, HttpStatus.OK);
}
빠른배송 상품 데이터만 출력, 일반배송 상품 데이터만 출력, 두개를 비교해서 더 싼 데이터만 출력 각각 엔드포인트를 만들어서 제대로 동작하는지 확인함.
그런데 이 경우 각각 get을 해야하니까 낭비 아닌가 싶어서 하나의 엔드포인트로 만듬. 그러기 위해서 dto부터 만들었음
// 추가된 dto
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductBuyListDTO {
private List<ProductBuyDTO> fastProducts;
private List<ProductBuyDTO> normalProducts;
private List<ProductBuyDTO> cheaperProducts;
}
// 수정된 controller
@GetMapping("/api/get/product/buy")
public ResponseEntity<ProductBuyListDTO> getProduct(@RequestParam Long productid) {
ProductBuyListDTO productBuyListDTO = new ProductBuyListDTO();
productBuyListDTO.setFastProducts(productService.getFastProduct(productid));
productBuyListDTO.setNormalProducts(productService.getNormalProduct(productid));
productBuyListDTO.setCheaperProducts(productService.getCheaperProduct(productid));
return new ResponseEntity<>(productBuyListDTO, HttpStatus.OK);
}
이렇게 하니까 데이터 줄때는 깔끔한데 프론트에서 읽을때 각각 경우를 따진다음에 다시 읽어야 되서 귀찮넹 ㅎㅎㅎㅎ
두개다 있는 경우를 비교해서 최저가 데이터만 출력하도록 하는것만 있으면 되지 않나??? 했는데...-> 이건 각 사이즈 별로 가격 띄울때 필요
빠른배송만 있는것 -> 각 사이즈별 빠른배송 아이콘 띄울때 필요, 둘다 있는데 일반배송이 최저가일떄 빠른배송 버튼에 가격 띄울떄 필요
일반배송만 있는것 -> 둘다 있는데 빠른배송이 최저가일때 일반배송 버튼에 가격 띄울떄 필요...
결국 다 필요하긴 함
3개의 엔드포인트로 나누는것과 1개의 엔드포인트로 통일하는것 중에 뭐가 더 나은지 몰라서 gpt한테 물어봤더니...
여러 개의 엔드포인트를 사용하는 경우, 프론트엔드에서 필요한 데이터만 가져오기 때문에 성능 면에서 유리할 수 있습니다. 그러나 여러 개의 요청을 보내야 하므로, 클라이언트-서버 간의 통신 비용이 증가할 수 있습니다. 또한, 엔드포인트가 많을수록 유지보수가 어려워질 수 있습니다.
한 개의 엔드포인트를 사용하는 경우, 클라이언트-서버 간의 통신 비용이 감소하여 성능 면에서 유리할 수 있습니다. 또한, 데이터를 한 번에 모두 가져올 수 있으므로 코드의 가독성이 높아질 수 있습니다. 그러나 데이터의 크기가 큰 경우, 필요한 데이터만 가져오지 않아서 클라이언트에게 부담이 될 수 있습니다.
결국 나는 3개의 list를 다 가져와야 하므로 한개의 엔드포인트로 가져오는게 낫겠군!
!!!!!!!!위 코드의 문제 확인
3개의 경우가 교집합 없이 분류되야 사용하기 편한데 빠른배송, 일반배송 모두 존재하는경우 이떄의 최저값도 담고 둘중 하나만 존재하는 경우도 result에 담는 바람에 빠른배송, 일반배송 데이터와 겹치게됨. 빠른배송, 일반배송 둘다 존재하는 경우는 둘다 존재하는 경우에 대해서만! 값을 담도록 수정해야 데이터 사용할때 편하다.
이렇게 해야 둘다 존재하는경우->최저값 데이터 출력됨,
이 값이 없을시 빠른배송과 일반배송 둘중 하나에만 데이터 존재 할것이므로 둘다 출력하면 하나만 출력됨
//최종 service
// 빠른 배송 상품 중 각 사이즈별 최저가 데이터만 출력
public List<ProductBuyDTO> getFastProduct(Long productid) {
return productRepository.getFastProduct(productid);
}
// 일반 배송 상품 중 각 사이즈별 최저가 데이터만 출력
public List<ProductBuyDTO> getNormalProduct(Long productid) {
return productRepository.getNormalProduct(productid);
}
// 각 사이즈별 빠른 배송, 일반 배송 상품 중 판매가격이 더 낮은 데이터만 출력
public List<ProductBuyDTO> getCheaperProduct(Long productid) {
List<ProductBuyDTO> fastProducts = getFastProduct(productid);
List<ProductBuyDTO> normalProducts = getNormalProduct(productid);
List<ProductBuyDTO> result = new ArrayList<>();
for (ProductBuyDTO fastProduct : fastProducts) {
for(ProductBuyDTO normalProduct : normalProducts) {
if(fastProduct.getSellProductSize().equals(normalProduct.getSellProductSize())) {
result.add(fastProduct.getSellWishPrice() <= normalProduct.getSellWishPrice() ? fastProduct : normalProduct);
break;
}
}
}
return result;
}
아 이렇게 하니까 다음 화면으로 넘어가는 버튼에 가격띄우는건 편한데 전체 사이즈에 가격 띄울때 불편~
결론->둘다 쓰자.. 백엔드에서 둘다 넣어서 둘다 출력해버려~