diff --git a/src/main/java/site/kikihi/custom/global/logging/ControllerLoggingAspect.java b/src/main/java/site/kikihi/custom/global/logging/ControllerLoggingAspect.java index bae91c3..b3eb7b5 100644 --- a/src/main/java/site/kikihi/custom/global/logging/ControllerLoggingAspect.java +++ b/src/main/java/site/kikihi/custom/global/logging/ControllerLoggingAspect.java @@ -21,7 +21,7 @@ @Slf4j public class ControllerLoggingAspect { - @Pointcut("execution(* com.jiyoung.kikihi.platform.adapter.in.web..*.*(..))") + @Pointcut("execution(* site.kikihi.custom.platform.adapter.in.web..*.*(..))") private void controllerPointcut() {} @Before("controllerPointcut()") diff --git a/src/main/java/site/kikihi/custom/global/logging/LoggingAspect.java b/src/main/java/site/kikihi/custom/global/logging/LoggingAspect.java index 2d070d3..78e193a 100644 --- a/src/main/java/site/kikihi/custom/global/logging/LoggingAspect.java +++ b/src/main/java/site/kikihi/custom/global/logging/LoggingAspect.java @@ -13,7 +13,7 @@ @Slf4j public class LoggingAspect { - @Pointcut("execution(* com.jiyoung.kikihi.platform.application.service.*Service.*(..))") + @Pointcut("execution(* site.kikihi.custom.platform.application.service.*Service.*(..))") private void applicationLayer() { } diff --git a/src/main/java/site/kikihi/custom/platform/adapter/in/web/RecommendationController.java b/src/main/java/site/kikihi/custom/platform/adapter/in/web/RecommendationController.java index ee8b80b..dc0e3a3 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/in/web/RecommendationController.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/in/web/RecommendationController.java @@ -76,9 +76,9 @@ public ApiResponse> getSimilarProducts( UUID userId = principalDetails != null ? principalDetails.getId() : null; // 유사한 상품 추천 서비스 호출 - List similarProducts = service.getSimilarProducts(userId,productId); + List similarProducts = service.getSimilarProducts(userId,productId); // 응답 주기 - return ApiResponse.ok(KeyboardRecommendationResponse.from(similarProducts)); + return ApiResponse.ok(similarProducts); } } diff --git a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardOptions.java b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardOptions.java index 41e85fc..b97852a 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardOptions.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardOptions.java @@ -54,7 +54,7 @@ public String getValue() { @Getter @RequiredArgsConstructor - @Schema(name = "[요청][상품] 키압(Key Pressure) Enum", description = "키압 옵션") + @Schema(name = "[요청][상품] 레이아웃(Layout) Enum", description = "레이아웃 옵션") public enum Layout { @Schema(description = "인체공학적 (스텝스컬쳐2)", example = "egonomic") ERGONOMIC("egonomic"), diff --git a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardRecommendationRequest.java b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardRecommendationRequest.java index 792175c..66764b7 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardRecommendationRequest.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/request/product/KeyboardRecommendationRequest.java @@ -6,10 +6,10 @@ @Getter @Setter -@Schema(name = "[요청][상품] 키보드 추천 요청 DTO", description = "키보드 추천 요청에 사용하는 DTO입니다.") +@Schema(name = "[요청][상품] 키보드 추천 요청 Request", description = "키보드 추천 요청에 사용하는 DTO입니다.") public class KeyboardRecommendationRequest { - @Schema(description = "키보드 배열(Size) 옵션", example = "ten", required = true) + @Schema(description = "키보드 배열(Size) 옵션", example = "tenkeyless", required = true) private KeyboardOptions.Size size; @Schema(description = "키압(Key Pressure) 옵션", example = "light", required = true) diff --git a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/response/product/KeyboardRecommendationResponse.java b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/response/product/KeyboardRecommendationResponse.java index 84888b3..898e254 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/response/product/KeyboardRecommendationResponse.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/in/web/dto/response/product/KeyboardRecommendationResponse.java @@ -34,7 +34,7 @@ public record KeyboardRecommendationResponse( String productName, @Schema(description = "정상가(원)", example = "599000.0") - double price, + Double price, @Schema(description = "북마크(좋아요)한 상품 여부", example = "true") boolean likedByMe @@ -43,26 +43,17 @@ public record KeyboardRecommendationResponse( /// 정적 팩토리 메서드 // 단일 객체 변환 메서드 추가 - public static KeyboardRecommendationResponse from(Product product) { + public static KeyboardRecommendationResponse from(Product product, boolean likedByMe) { return KeyboardRecommendationResponse.builder() .id(product.getId()) .thumbnail(product.getThumbnail()) .manufacturerName(product.getManufacturer()) .productName(product.getName()) .price(product.getPrice()) - .likedByMe(false) + .likedByMe(likedByMe) .build(); } - // 기존 리스트 변환 메서드는 그대로 유지 - public static List from(List productList) { - return productList.stream() - .map(KeyboardRecommendationResponse::from) // 단일 객체 변환 메서드 호출 - .toList(); - } - - - } diff --git a/src/main/java/site/kikihi/custom/platform/adapter/out/RecommendKeyboardAdapter.java b/src/main/java/site/kikihi/custom/platform/adapter/out/RecommendKeyboardAdapter.java index 564ccf9..eb98a71 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/out/RecommendKeyboardAdapter.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/out/RecommendKeyboardAdapter.java @@ -10,7 +10,6 @@ import org.springframework.stereotype.Component; import site.kikihi.custom.platform.adapter.in.web.dto.request.product.KeyboardOptions; import site.kikihi.custom.platform.adapter.out.mongo.product.ProductDocument; -import site.kikihi.custom.platform.adapter.out.mongo.product.ProductDocumentRepository; import site.kikihi.custom.platform.application.out.bookmark.BookmarkPort; import site.kikihi.custom.platform.application.out.recommend.RecommendKeyboardPort; import site.kikihi.custom.platform.domain.bookmark.Bookmark; @@ -53,21 +52,28 @@ public List filterAndRecommendKeyboards( if (keyPressure != null) { String keyPressureField = "spec_table.기능 > 키압"; if (keyPressure <= 49) { // LIGHT 구간 - query.addCriteria(Criteria.where(keyPressureField).regex("^([0-4]?[0-9])g$")); + andCriterias.add(Criteria.where(keyPressureField).regex("^([0-4]?[0-9])g$")); } else { // NORMAL 구간 - query.addCriteria(Criteria.where(keyPressureField).regex("^([5-9][0-9]|[1-9][0-9]{2,})g$")); + andCriterias.add(Criteria.where(keyPressureField).regex("^([5-9][0-9]|[1-9][0-9]{2,})g$")); } } // Layout if (layout != null && !layout.isBlank()) { - if ("ERGONOMIC".equalsIgnoreCase(layout)) { - query.addCriteria(Criteria.where("spec_table.키보드구조 > 스텝스컬쳐2").is("○")); + String val = layout.trim(); + boolean ergonomic = "ERGONOMIC".equalsIgnoreCase(val) || "egonomic".equalsIgnoreCase(val); + if (ergonomic) { + andCriterias.add(new Criteria().orOperator( + Criteria.where("spec_table.키보드구조 > 스텝스컬쳐2").is("○"), + Criteria.where("description").regex("스텝스컬쳐2", "i") + )); } else if ("SIMPLE".equalsIgnoreCase(layout)) { - andCriterias.add(Criteria.where("spec_table.키보드구조 > 로우프로파일(LP)").is("○")); - andCriterias.add(Criteria.where("description").regex("스텝스컬쳐2", "i")); - andCriterias.add(Criteria.where("description").regex("lp", "i")); + andCriterias.add(new Criteria().orOperator( + Criteria.where("spec_table.키보드구조 > 로우프로파일(LP)").is("○"), + Criteria.where("description").regex("lp", "i") + )); } + } // Switch Type @@ -83,13 +89,13 @@ public List filterAndRecommendKeyboards( // SoundDampener if (soundDampener != null) { - if (soundDampener == KeyboardOptions.SoundDampener.YES.getValue()) { + if (KeyboardOptions.SoundDampener.YES.getValue().equals(soundDampener)) { andCriterias.add(new Criteria().orOperator( Criteria.where("spec_table.키보드구조 > 흡음재").is("○"), Criteria.where("description").regex("흡음재") )); } else { - query.addCriteria(new Criteria().andOperator( + andCriterias.add(new Criteria().andOperator( Criteria.where("spec_table.키보드구조 > 흡음재").ne("○"), Criteria.where("description").not().regex("흡음재") )); @@ -98,13 +104,13 @@ public List filterAndRecommendKeyboards( // RGB if (rgb != null) { - if (rgb == KeyboardOptions.RGB.YES.getValue()) { + if (KeyboardOptions.RGB.YES.getValue().equals(rgb)) { andCriterias.add(new Criteria().orOperator( Criteria.where("spec_table.키보드구조 > RGB 백라이트").is("○"), Criteria.where("description").regex("RGB", "i") )); } else { - query.addCriteria(new Criteria().andOperator( + andCriterias.add(new Criteria().andOperator( Criteria.where("spec_table.키보드구조 > RGB 백라이트").ne("○"), Criteria.where("description").not().regex("RGB", "i") )); @@ -113,19 +119,19 @@ public List filterAndRecommendKeyboards( // 가격 if (minPrice > 0 || maxPrice > 0) { - query.addCriteria(Criteria.where("options").elemMatch( - Criteria.where("main_price").gte(minPrice).lte(maxPrice) - )); - } + List priceBounds = new ArrayList<>(); + if (minPrice > 0) priceBounds.add(Criteria.where("main_price").gte(minPrice)); + if (maxPrice > 0) priceBounds.add(Criteria.where("main_price").lte(maxPrice)); + query.addCriteria(Criteria.where("options") + .elemMatch(new Criteria().andOperator(priceBounds.toArray(new Criteria[0])))); + } - // And 조건 최종 적용 if (!andCriterias.isEmpty()) { query.addCriteria(new Criteria().andOperator(andCriterias.toArray(new Criteria[0]))); } List results = mongoTemplate.find(query, ProductDocument.class); return results.stream().map(ProductDocument::toDomain).toList(); - } diff --git a/src/main/java/site/kikihi/custom/platform/adapter/out/mongo/product/ProductDocument.java b/src/main/java/site/kikihi/custom/platform/adapter/out/mongo/product/ProductDocument.java index dc7b772..b8338b6 100644 --- a/src/main/java/site/kikihi/custom/platform/adapter/out/mongo/product/ProductDocument.java +++ b/src/main/java/site/kikihi/custom/platform/adapter/out/mongo/product/ProductDocument.java @@ -22,32 +22,33 @@ public class ProductDocument { @Id - private String id; // + private String id; - private String category; // + private String category; - private String name; // + private String name; - private double price; // + private double price; - private List description; // + private List description; @Field("thumbnail") - private String thumbnail; // + private String thumbnail; - private String manufacturer; // + private String manufacturer; @Field("detail_purchase_url") - private String detailPageUrl; // + private String detailPageUrl; @Field("options") - private List> options; // + private List> options; @Field("all_detail_images") - private List allDetailImages; // + private List allDetailImages; @Field("spec_table") - private Map specTable; // spec_table은 현재 비어있는 상태로 초기화 + @Builder.Default + private Map specTable = new java.util.HashMap<>(); /// 도메인 변경 public Product toDomain(){ diff --git a/src/main/java/site/kikihi/custom/platform/application/in/recommendation/RecommendationUseCase.java b/src/main/java/site/kikihi/custom/platform/application/in/recommendation/RecommendationUseCase.java index 181c941..f579003 100644 --- a/src/main/java/site/kikihi/custom/platform/application/in/recommendation/RecommendationUseCase.java +++ b/src/main/java/site/kikihi/custom/platform/application/in/recommendation/RecommendationUseCase.java @@ -15,6 +15,6 @@ public interface RecommendationUseCase { List getTutorialKeyboardRecommendation(UUID userId, KeyboardRecommendationRequest request); /// 유사한 상품 추천 - List getSimilarProducts(UUID userId, String productId); + List getSimilarProducts(UUID userId, String productId); } diff --git a/src/main/java/site/kikihi/custom/platform/application/service/RecommendationService.java b/src/main/java/site/kikihi/custom/platform/application/service/RecommendationService.java index 681b03f..eaec2c6 100644 --- a/src/main/java/site/kikihi/custom/platform/application/service/RecommendationService.java +++ b/src/main/java/site/kikihi/custom/platform/application/service/RecommendationService.java @@ -17,6 +17,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; @Service @Transactional @@ -118,9 +119,11 @@ public List getTutorialKeyboardRecommendation(UU ); return documents.stream() - .map(KeyboardRecommendationResponse :: from) - .toList(); - + .map(product -> { + boolean likedByMe = bookmarkPort.checkBookmarkByUserIdAndProductId(userId, product.getId()); + return KeyboardRecommendationResponse.from(product, likedByMe); + }) + .collect(Collectors.toList()); } /** @@ -130,7 +133,7 @@ public List getTutorialKeyboardRecommendation(UU * @return */ @Override - public List getSimilarProducts(UUID userId, String productId) { + public List getSimilarProducts(UUID userId, String productId) { /// 유저가 있다면 체크, 없다면 바로 상품 조회 // if (userId != null) { // /// 커스텀을 제작했다면, 비슷한 특성의 상품들을 추천 @@ -145,8 +148,15 @@ public List getSimilarProducts(UUID userId, String productId) { Product product = loadProduct(productId); /// 유사한 상품 필터링 - return recommendKeyboardPort.getSimilarProducts(userId, productId,product); + List documents=recommendKeyboardPort.getSimilarProducts(userId, productId,product); + // 각 상품별 북마크 여부 체크 후 응답 리스트 생성 + return documents.stream() + .map(similarProduct -> { + boolean likedByMe = bookmarkPort.checkBookmarkByUserIdAndProductId(userId, similarProduct.getId()); + return KeyboardRecommendationResponse.from(similarProduct, likedByMe); + }) + .collect(Collectors.toList()); }