From d2f5ae103d98fc02f28510f6b3bea86aa91a78fb Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 13:09:12 +0900 Subject: [PATCH 1/6] =?UTF-8?q?init:=20=EC=A0=9C=ED=92=88=20=EC=B6=94?= =?UTF-8?q?=EC=B2=9C=20=EC=A1=B0=ED=9A=8C=20=EC=B4=88=EA=B8=B0=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 --- .../controller/RecommendationController.java | 126 ++++++++++++++++++ .../yessir/controller/SkinTypeController.java | 3 +- .../java/yes1sir/yessir/model/Product.java | 73 ++++++++++ .../java/yes1sir/yessir/model/SkinType.java | 46 +++++-- .../yessir/repository/ProductRepository.java | 10 ++ .../service/DataInitializationService.java | 69 ++++++++++ .../yessir/service/ProductService.java | 26 ++++ 7 files changed, 338 insertions(+), 15 deletions(-) create mode 100644 src/main/java/yes1sir/yessir/controller/RecommendationController.java create mode 100644 src/main/java/yes1sir/yessir/model/Product.java create mode 100644 src/main/java/yes1sir/yessir/repository/ProductRepository.java create mode 100644 src/main/java/yes1sir/yessir/service/DataInitializationService.java create mode 100644 src/main/java/yes1sir/yessir/service/ProductService.java diff --git a/src/main/java/yes1sir/yessir/controller/RecommendationController.java b/src/main/java/yes1sir/yessir/controller/RecommendationController.java new file mode 100644 index 0000000..f8f0f68 --- /dev/null +++ b/src/main/java/yes1sir/yessir/controller/RecommendationController.java @@ -0,0 +1,126 @@ +package yes1sir.yessir.controller; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import yes1sir.yessir.model.Product; +import yes1sir.yessir.service.ProductService; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequestMapping("${app.base.url}/api/recommendations") +public class RecommendationController { + + private final ProductService productService; + + @Autowired + public RecommendationController(ProductService productService) { + this.productService = productService; + } + + @GetMapping("/{skinTypeId}") + public ResponseEntity getRecommendations(@PathVariable Long skinTypeId) { + List products = productService.getProductsBySkinTypeId(skinTypeId); + if (products.isEmpty()) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("추천 제품을 찾을 수 없습니다.")); + } else { + List recommendations = products.stream() + .map(product -> new ProductRecommendation( + product.getBrandName(), + product.getProductName(), + product.getRecommendedType(), + product.getPrice(), + product.getPurpose(), + product.getImage())) + .collect(Collectors.toList()); + return ResponseEntity.ok(recommendations); + } + } + + static class ProductRecommendation { + private String brandName; + private String productName; + private String recommendedType; + private double price; + private String purpose; + private String image; + + public ProductRecommendation(String brandName, String productName, String recommendedType, double price, String purpose, String image) { + this.brandName = brandName; + this.productName = productName; + this.recommendedType = recommendedType; + this.price = price; + this.purpose = purpose; + this.image = image; + } + + // Getters and setters + public String getBrandName() { + return brandName; + } + + public void setBrandName(String brandName) { + this.brandName = brandName; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getRecommendedType() { + return recommendedType; + } + + public void setRecommendedType(String recommendedType) { + this.recommendedType = recommendedType; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getPurpose() { + return purpose; + } + + public void setPurpose(String purpose) { + this.purpose = purpose; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + } + + static class ErrorResponse { + private String detail; + + public ErrorResponse(String detail) { + this.detail = detail; + } + + // Getter and setter + public String getDetail() { + return detail; + } + + public void setDetail(String detail) { + this.detail = detail; + } + } +} diff --git a/src/main/java/yes1sir/yessir/controller/SkinTypeController.java b/src/main/java/yes1sir/yessir/controller/SkinTypeController.java index 0b4cb11..5cbb406 100644 --- a/src/main/java/yes1sir/yessir/controller/SkinTypeController.java +++ b/src/main/java/yes1sir/yessir/controller/SkinTypeController.java @@ -1,7 +1,6 @@ package yes1sir.yessir.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -9,7 +8,7 @@ import yes1sir.yessir.service.SkinTypeService; @RestController -@RequestMapping("${app.base.url}/api/skin_types") +@RequestMapping("/api/skin_types") public class SkinTypeController { private final SkinTypeService skinTypeService; diff --git a/src/main/java/yes1sir/yessir/model/Product.java b/src/main/java/yes1sir/yessir/model/Product.java new file mode 100644 index 0000000..2dc18e3 --- /dev/null +++ b/src/main/java/yes1sir/yessir/model/Product.java @@ -0,0 +1,73 @@ +package yes1sir.yessir.model; + +import jakarta.persistence.*; + +@Entity +public class Product { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private String brandName; + private String productName; + private String recommendedType; + private double price; + private String purpose; + private String image; + + // Getters and setters + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getBrandName() { + return brandName; + } + + public void setBrandName(String brandName) { + this.brandName = brandName; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getRecommendedType() { + return recommendedType; + } + + public void setRecommendedType(String recommendedType) { + this.recommendedType = recommendedType; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getPurpose() { + return purpose; + } + + public void setPurpose(String purpose) { + this.purpose = purpose; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } +} diff --git a/src/main/java/yes1sir/yessir/model/SkinType.java b/src/main/java/yes1sir/yessir/model/SkinType.java index b638841..d62067d 100644 --- a/src/main/java/yes1sir/yessir/model/SkinType.java +++ b/src/main/java/yes1sir/yessir/model/SkinType.java @@ -1,21 +1,41 @@ package yes1sir.yessir.model; -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import lombok.Getter; -import lombok.Setter; +import jakarta.persistence.*; @Entity -@Table(name = "SkinType") -@Getter -@Setter public class SkinType { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long skinTypeID; - private String skinTypeName; - private String description; + private Long id; + private String typeName; + + // Getters and setters + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTypeName() { + return typeName; + } + + public void setTypeName(String typeName) { + this.typeName = typeName; + } + + // 추가된 메서드들 + public Long getSkinTypeID() { + return this.id; + } + + public String getSkinTypeName() { + return this.typeName; + } + + public String getDescription() { + return "Description for " + this.typeName; // 필요에 따라 설명을 다르게 설정할 수 있습니다. + } } diff --git a/src/main/java/yes1sir/yessir/repository/ProductRepository.java b/src/main/java/yes1sir/yessir/repository/ProductRepository.java new file mode 100644 index 0000000..68ddb01 --- /dev/null +++ b/src/main/java/yes1sir/yessir/repository/ProductRepository.java @@ -0,0 +1,10 @@ +package yes1sir.yessir.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import yes1sir.yessir.model.Product; + +import java.util.List; + +public interface ProductRepository extends JpaRepository { + List findByRecommendedType(String recommendedType); +} diff --git a/src/main/java/yes1sir/yessir/service/DataInitializationService.java b/src/main/java/yes1sir/yessir/service/DataInitializationService.java new file mode 100644 index 0000000..6dc601f --- /dev/null +++ b/src/main/java/yes1sir/yessir/service/DataInitializationService.java @@ -0,0 +1,69 @@ +package yes1sir.yessir.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import yes1sir.yessir.model.Product; +import yes1sir.yessir.model.SkinType; +import yes1sir.yessir.repository.ProductRepository; +import yes1sir.yessir.repository.SkinTypeRepository; + +import jakarta.annotation.PostConstruct; + +@Service +public class DataInitializationService { + + private final ProductRepository productRepository; + private final SkinTypeRepository skinTypeRepository; + + @Autowired + public DataInitializationService(ProductRepository productRepository, SkinTypeRepository skinTypeRepository) { + this.productRepository = productRepository; + this.skinTypeRepository = skinTypeRepository; + } + + @PostConstruct + public void init() { + // 피부 유형 저장 + saveSkinType("DRPT"); + saveSkinType("DRNT"); + saveSkinType("DSPT"); + saveSkinType("DSNT"); + saveSkinType("DRPW"); + saveSkinType("DRNW"); + saveSkinType("DSPW"); + saveSkinType("DSNW"); + saveSkinType("ORPT"); + saveSkinType("ORNT"); + saveSkinType("OSPT"); + saveSkinType("OSNT"); + saveSkinType("ORPW"); + saveSkinType("ORNW"); + saveSkinType("OSPW"); + saveSkinType("OSNW"); + + // 제품 정보 저장 + saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", "DRPT", 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); + saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", "ORNT", 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); + saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", "DRNT", 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); + saveProduct("라운드랩", "[민감진정] 라운드랩 포 맨 소나무 진정 토너/로션 2종 세트(+클렌저 40ml 증정)", "ORPT", 32000, "질감 개선, 주름 제거, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0019/A00000019915608ko.jpg?l=ko"); + saveProduct("라운드랩", "[고민진정] 라운드랩 포 맨 소나무 진정 시카 토너 200ml", "DSPT", 18500, "모공 청소, 주름 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0019/A00000019915301ko.jpg?l=ko"); + // 추가적인 제품 정보는 같은 형식으로 계속 삽입... + } + + private void saveSkinType(String typeName) { + SkinType skinType = new SkinType(); + skinType.setTypeName(typeName); + skinTypeRepository.save(skinType); + } + + private void saveProduct(String brandName, String productName, String recommendedType, double price, String purpose, String image) { + Product product = new Product(); + product.setBrandName(brandName); + product.setProductName(productName); + product.setRecommendedType(recommendedType); + product.setPrice(price); + product.setPurpose(purpose); + product.setImage(image); + productRepository.save(product); + } +} diff --git a/src/main/java/yes1sir/yessir/service/ProductService.java b/src/main/java/yes1sir/yessir/service/ProductService.java new file mode 100644 index 0000000..7eb73d8 --- /dev/null +++ b/src/main/java/yes1sir/yessir/service/ProductService.java @@ -0,0 +1,26 @@ +package yes1sir.yessir.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import yes1sir.yessir.model.Product; +import yes1sir.yessir.repository.ProductRepository; +import yes1sir.yessir.repository.SkinTypeRepository; + +import java.util.List; + +@Service +public class ProductService { + + private final ProductRepository productRepository; + private final SkinTypeRepository skinTypeRepository; + + @Autowired + public ProductService(ProductRepository productRepository, SkinTypeRepository skinTypeRepository) { + this.productRepository = productRepository; + this.skinTypeRepository = skinTypeRepository; + } + + public List getProductsBySkinTypeId(Long skinTypeId) { + return productRepository.findByRecommendedType(skinTypeRepository.findById(skinTypeId).orElseThrow().getTypeName()); + } +} From 1a4b710a37d9ffaad86b563b44c2bda2889264c5 Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 13:17:34 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20db=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/yes1sir/yessir/model/Product.java | 26 +++++--- .../java/yes1sir/yessir/model/SkinType.java | 12 ++++ .../yessir/repository/ProductRepository.java | 3 +- .../service/DataInitializationService.java | 60 +++++++++++-------- .../yessir/service/ProductService.java | 4 +- 5 files changed, 69 insertions(+), 36 deletions(-) diff --git a/src/main/java/yes1sir/yessir/model/Product.java b/src/main/java/yes1sir/yessir/model/Product.java index 2dc18e3..f4be7a9 100644 --- a/src/main/java/yes1sir/yessir/model/Product.java +++ b/src/main/java/yes1sir/yessir/model/Product.java @@ -1,6 +1,7 @@ package yes1sir.yessir.model; import jakarta.persistence.*; +import java.util.Set; @Entity public class Product { @@ -9,11 +10,18 @@ public class Product { private Long id; private String brandName; private String productName; - private String recommendedType; private double price; private String purpose; private String image; + @ManyToMany + @JoinTable( + name = "product_skin_type", + joinColumns = @JoinColumn(name = "product_id"), + inverseJoinColumns = @JoinColumn(name = "skin_type_id") + ) + private Set recommendedTypes; + // Getters and setters public Long getId() { return id; @@ -39,14 +47,6 @@ public void setProductName(String productName) { this.productName = productName; } - public String getRecommendedType() { - return recommendedType; - } - - public void setRecommendedType(String recommendedType) { - this.recommendedType = recommendedType; - } - public double getPrice() { return price; } @@ -70,4 +70,12 @@ public String getImage() { public void setImage(String image) { this.image = image; } + + public Set getRecommendedTypes() { + return recommendedTypes; + } + + public void setRecommendedTypes(Set recommendedTypes) { + this.recommendedTypes = recommendedTypes; + } } diff --git a/src/main/java/yes1sir/yessir/model/SkinType.java b/src/main/java/yes1sir/yessir/model/SkinType.java index d62067d..230d7e0 100644 --- a/src/main/java/yes1sir/yessir/model/SkinType.java +++ b/src/main/java/yes1sir/yessir/model/SkinType.java @@ -1,6 +1,7 @@ package yes1sir.yessir.model; import jakarta.persistence.*; +import java.util.Set; @Entity public class SkinType { @@ -9,6 +10,9 @@ public class SkinType { private Long id; private String typeName; + @ManyToMany(mappedBy = "recommendedTypes") + private Set products; + // Getters and setters public Long getId() { return id; @@ -26,6 +30,14 @@ public void setTypeName(String typeName) { this.typeName = typeName; } + public Set getProducts() { + return products; + } + + public void setProducts(Set products) { + this.products = products; + } + // 추가된 메서드들 public Long getSkinTypeID() { return this.id; diff --git a/src/main/java/yes1sir/yessir/repository/ProductRepository.java b/src/main/java/yes1sir/yessir/repository/ProductRepository.java index 68ddb01..d400bb8 100644 --- a/src/main/java/yes1sir/yessir/repository/ProductRepository.java +++ b/src/main/java/yes1sir/yessir/repository/ProductRepository.java @@ -2,9 +2,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import yes1sir.yessir.model.Product; +import yes1sir.yessir.model.SkinType; import java.util.List; public interface ProductRepository extends JpaRepository { - List findByRecommendedType(String recommendedType); + List findByRecommendedTypesContaining(SkinType skinType); } diff --git a/src/main/java/yes1sir/yessir/service/DataInitializationService.java b/src/main/java/yes1sir/yessir/service/DataInitializationService.java index 6dc601f..bc60b73 100644 --- a/src/main/java/yes1sir/yessir/service/DataInitializationService.java +++ b/src/main/java/yes1sir/yessir/service/DataInitializationService.java @@ -8,6 +8,8 @@ import yes1sir.yessir.repository.SkinTypeRepository; import jakarta.annotation.PostConstruct; +import java.util.HashSet; +import java.util.Set; @Service public class DataInitializationService { @@ -24,43 +26,51 @@ public DataInitializationService(ProductRepository productRepository, SkinTypeRe @PostConstruct public void init() { // 피부 유형 저장 - saveSkinType("DRPT"); - saveSkinType("DRNT"); - saveSkinType("DSPT"); - saveSkinType("DSNT"); - saveSkinType("DRPW"); - saveSkinType("DRNW"); - saveSkinType("DSPW"); - saveSkinType("DSNW"); - saveSkinType("ORPT"); - saveSkinType("ORNT"); - saveSkinType("OSPT"); - saveSkinType("OSNT"); - saveSkinType("ORPW"); - saveSkinType("ORNW"); - saveSkinType("OSPW"); - saveSkinType("OSNW"); + SkinType DRPT = saveSkinType("DRPT"); + SkinType DRNT = saveSkinType("DRNT"); + SkinType DSPT = saveSkinType("DSPT"); + SkinType DSNT = saveSkinType("DSNT"); + SkinType DRPW = saveSkinType("DRPW"); + SkinType DRNW = saveSkinType("DRNW"); + SkinType DSPW = saveSkinType("DSPW"); + SkinType DSNW = saveSkinType("DSNW"); + SkinType ORPT = saveSkinType("ORPT"); + SkinType ORNT = saveSkinType("ORNT"); + SkinType OSPT = saveSkinType("OSPT"); + SkinType OSNT = saveSkinType("OSNT"); + SkinType ORPW = saveSkinType("ORPW"); + SkinType ORNW = saveSkinType("ORNW"); + SkinType OSPW = saveSkinType("OSPW"); + SkinType OSNW = saveSkinType("OSNW"); // 제품 정보 저장 - saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", "DRPT", 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); - saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", "ORNT", 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); - saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", "DRNT", 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); - saveProduct("라운드랩", "[민감진정] 라운드랩 포 맨 소나무 진정 토너/로션 2종 세트(+클렌저 40ml 증정)", "ORPT", 32000, "질감 개선, 주름 제거, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0019/A00000019915608ko.jpg?l=ko"); - saveProduct("라운드랩", "[고민진정] 라운드랩 포 맨 소나무 진정 시카 토너 200ml", "DSPT", 18500, "모공 청소, 주름 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0019/A00000019915301ko.jpg?l=ko"); + Set recommendedTypes1 = new HashSet<>(); + recommendedTypes1.add(OSPT); + recommendedTypes1.add(OSPW); + saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", recommendedTypes1, 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); + + Set recommendedTypes2 = new HashSet<>(); + recommendedTypes2.add(ORNT); + saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", recommendedTypes2, 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); + + Set recommendedTypes3 = new HashSet<>(); + recommendedTypes3.add(DRNT); + saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", recommendedTypes3, 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); + // 추가적인 제품 정보는 같은 형식으로 계속 삽입... } - private void saveSkinType(String typeName) { + private SkinType saveSkinType(String typeName) { SkinType skinType = new SkinType(); skinType.setTypeName(typeName); - skinTypeRepository.save(skinType); + return skinTypeRepository.save(skinType); } - private void saveProduct(String brandName, String productName, String recommendedType, double price, String purpose, String image) { + private void saveProduct(String brandName, String productName, Set recommendedTypes, double price, String purpose, String image) { Product product = new Product(); product.setBrandName(brandName); product.setProductName(productName); - product.setRecommendedType(recommendedType); + product.setRecommendedTypes(recommendedTypes); product.setPrice(price); product.setPurpose(purpose); product.setImage(image); diff --git a/src/main/java/yes1sir/yessir/service/ProductService.java b/src/main/java/yes1sir/yessir/service/ProductService.java index 7eb73d8..cbf156e 100644 --- a/src/main/java/yes1sir/yessir/service/ProductService.java +++ b/src/main/java/yes1sir/yessir/service/ProductService.java @@ -3,6 +3,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import yes1sir.yessir.model.Product; +import yes1sir.yessir.model.SkinType; import yes1sir.yessir.repository.ProductRepository; import yes1sir.yessir.repository.SkinTypeRepository; @@ -21,6 +22,7 @@ public ProductService(ProductRepository productRepository, SkinTypeRepository sk } public List getProductsBySkinTypeId(Long skinTypeId) { - return productRepository.findByRecommendedType(skinTypeRepository.findById(skinTypeId).orElseThrow().getTypeName()); + SkinType skinType = skinTypeRepository.findById(skinTypeId).orElseThrow(); + return productRepository.findByRecommendedTypesContaining(skinType); } } From 744f0dd76748728629c135634c4a7b833cea8813 Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 13:54:07 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=EC=B6=94=EC=B2=9C=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=20=ED=98=95=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/RecommendationController.java | 45 +++++++++---------- .../java/yes1sir/yessir/model/Product.java | 19 +++++--- .../yessir/repository/ProductRepository.java | 2 +- .../service/DataInitializationService.java | 25 ++++++----- .../yessir/service/ProductService.java | 2 +- 5 files changed, 49 insertions(+), 44 deletions(-) diff --git a/src/main/java/yes1sir/yessir/controller/RecommendationController.java b/src/main/java/yes1sir/yessir/controller/RecommendationController.java index f8f0f68..f424abb 100644 --- a/src/main/java/yes1sir/yessir/controller/RecommendationController.java +++ b/src/main/java/yes1sir/yessir/controller/RecommendationController.java @@ -1,10 +1,10 @@ package yes1sir.yessir.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import yes1sir.yessir.model.Product; +import yes1sir.yessir.model.SkinType; import yes1sir.yessir.service.ProductService; import java.util.List; @@ -25,33 +25,37 @@ public RecommendationController(ProductService productService) { public ResponseEntity getRecommendations(@PathVariable Long skinTypeId) { List products = productService.getProductsBySkinTypeId(skinTypeId); if (products.isEmpty()) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ErrorResponse("추천 제품을 찾을 수 없습니다.")); + return ResponseEntity.noContent().build(); } else { - List recommendations = products.stream() - .map(product -> new ProductRecommendation( + List response = products.stream() + .map(product -> new ProductResponse( product.getBrandName(), product.getProductName(), product.getRecommendedType(), + product.getApplicableSkinTypes().stream().map(SkinType::getTypeName).collect(Collectors.joining(", ")), product.getPrice(), product.getPurpose(), - product.getImage())) + product.getImage() + )) .collect(Collectors.toList()); - return ResponseEntity.ok(recommendations); + return ResponseEntity.ok(response); } } - static class ProductRecommendation { + static class ProductResponse { private String brandName; private String productName; private String recommendedType; + private String applicableTypes; private double price; private String purpose; private String image; - public ProductRecommendation(String brandName, String productName, String recommendedType, double price, String purpose, String image) { + public ProductResponse(String brandName, String productName, String recommendedType, String applicableTypes, double price, String purpose, String image) { this.brandName = brandName; this.productName = productName; this.recommendedType = recommendedType; + this.applicableTypes = applicableTypes; this.price = price; this.purpose = purpose; this.image = image; @@ -82,6 +86,14 @@ public void setRecommendedType(String recommendedType) { this.recommendedType = recommendedType; } + public String getApplicableTypes() { + return applicableTypes; + } + + public void setApplicableTypes(String applicableTypes) { + this.applicableTypes = applicableTypes; + } + public double getPrice() { return price; } @@ -106,21 +118,4 @@ public void setImage(String image) { this.image = image; } } - - static class ErrorResponse { - private String detail; - - public ErrorResponse(String detail) { - this.detail = detail; - } - - // Getter and setter - public String getDetail() { - return detail; - } - - public void setDetail(String detail) { - this.detail = detail; - } - } } diff --git a/src/main/java/yes1sir/yessir/model/Product.java b/src/main/java/yes1sir/yessir/model/Product.java index f4be7a9..69c8f5b 100644 --- a/src/main/java/yes1sir/yessir/model/Product.java +++ b/src/main/java/yes1sir/yessir/model/Product.java @@ -13,6 +13,7 @@ public class Product { private double price; private String purpose; private String image; + private String recommendedType; // single recommended type @ManyToMany @JoinTable( @@ -20,7 +21,7 @@ public class Product { joinColumns = @JoinColumn(name = "product_id"), inverseJoinColumns = @JoinColumn(name = "skin_type_id") ) - private Set recommendedTypes; + private Set applicableSkinTypes; // Getters and setters public Long getId() { @@ -71,11 +72,19 @@ public void setImage(String image) { this.image = image; } - public Set getRecommendedTypes() { - return recommendedTypes; + public Set getApplicableSkinTypes() { + return applicableSkinTypes; } - public void setRecommendedTypes(Set recommendedTypes) { - this.recommendedTypes = recommendedTypes; + public void setApplicableSkinTypes(Set applicableSkinTypes) { + this.applicableSkinTypes = applicableSkinTypes; + } + + public String getRecommendedType() { + return recommendedType; + } + + public void setRecommendedType(String recommendedType) { + this.recommendedType = recommendedType; } } diff --git a/src/main/java/yes1sir/yessir/repository/ProductRepository.java b/src/main/java/yes1sir/yessir/repository/ProductRepository.java index d400bb8..ab9ad72 100644 --- a/src/main/java/yes1sir/yessir/repository/ProductRepository.java +++ b/src/main/java/yes1sir/yessir/repository/ProductRepository.java @@ -7,5 +7,5 @@ import java.util.List; public interface ProductRepository extends JpaRepository { - List findByRecommendedTypesContaining(SkinType skinType); + List findByApplicableSkinTypesContaining(SkinType skinType); } diff --git a/src/main/java/yes1sir/yessir/service/DataInitializationService.java b/src/main/java/yes1sir/yessir/service/DataInitializationService.java index bc60b73..8ffb873 100644 --- a/src/main/java/yes1sir/yessir/service/DataInitializationService.java +++ b/src/main/java/yes1sir/yessir/service/DataInitializationService.java @@ -44,18 +44,18 @@ public void init() { SkinType OSNW = saveSkinType("OSNW"); // 제품 정보 저장 - Set recommendedTypes1 = new HashSet<>(); - recommendedTypes1.add(OSPT); - recommendedTypes1.add(OSPW); - saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", recommendedTypes1, 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); + Set applicableSkinTypes1 = new HashSet<>(); + applicableSkinTypes1.add(OSPT); + applicableSkinTypes1.add(OSPW); + saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", "D, S", applicableSkinTypes1, 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); - Set recommendedTypes2 = new HashSet<>(); - recommendedTypes2.add(ORNT); - saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", recommendedTypes2, 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); + Set applicableSkinTypes2 = new HashSet<>(); + applicableSkinTypes2.add(ORNT); + saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", "O, W", applicableSkinTypes2, 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); - Set recommendedTypes3 = new HashSet<>(); - recommendedTypes3.add(DRNT); - saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", recommendedTypes3, 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); + Set applicableSkinTypes3 = new HashSet<>(); + applicableSkinTypes3.add(DRNT); + saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", "D, R", applicableSkinTypes3, 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); // 추가적인 제품 정보는 같은 형식으로 계속 삽입... } @@ -66,11 +66,12 @@ private SkinType saveSkinType(String typeName) { return skinTypeRepository.save(skinType); } - private void saveProduct(String brandName, String productName, Set recommendedTypes, double price, String purpose, String image) { + private void saveProduct(String brandName, String productName, String recommendedType, Set applicableSkinTypes, double price, String purpose, String image) { Product product = new Product(); product.setBrandName(brandName); product.setProductName(productName); - product.setRecommendedTypes(recommendedTypes); + product.setRecommendedType(recommendedType); + product.setApplicableSkinTypes(applicableSkinTypes); product.setPrice(price); product.setPurpose(purpose); product.setImage(image); diff --git a/src/main/java/yes1sir/yessir/service/ProductService.java b/src/main/java/yes1sir/yessir/service/ProductService.java index cbf156e..ad3a3a4 100644 --- a/src/main/java/yes1sir/yessir/service/ProductService.java +++ b/src/main/java/yes1sir/yessir/service/ProductService.java @@ -23,6 +23,6 @@ public ProductService(ProductRepository productRepository, SkinTypeRepository sk public List getProductsBySkinTypeId(Long skinTypeId) { SkinType skinType = skinTypeRepository.findById(skinTypeId).orElseThrow(); - return productRepository.findByRecommendedTypesContaining(skinType); + return productRepository.findByApplicableSkinTypesContaining(skinType); } } From bb2733f032528e3af78102fbe13e506d46f3c672 Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 14:30:18 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=EB=B9=8C=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yessir/controller/HomeController.java | 12 ++ .../controller/RecommendationController.java | 115 +++--------------- .../yessir/controller/SkinTypeController.java | 92 -------------- .../java/yes1sir/yessir/model/Product.java | 32 ++--- .../java/yes1sir/yessir/model/SkinType.java | 19 +-- .../yessir/repository/SkinTypeRepository.java | 3 + .../service/DataInitializationService.java | 64 +++------- .../yessir/service/ProductService.java | 8 +- .../yessir/service/SkinTypeService.java | 13 +- src/main/resources/application.properties | 4 + src/main/resources/templates/index.html | 48 ++++++++ .../yessir/SkinTypeControllerTest.java | 1 - 12 files changed, 130 insertions(+), 281 deletions(-) create mode 100644 src/main/java/yes1sir/yessir/controller/HomeController.java delete mode 100644 src/main/java/yes1sir/yessir/controller/SkinTypeController.java create mode 100644 src/main/resources/templates/index.html diff --git a/src/main/java/yes1sir/yessir/controller/HomeController.java b/src/main/java/yes1sir/yessir/controller/HomeController.java new file mode 100644 index 0000000..fc61bdf --- /dev/null +++ b/src/main/java/yes1sir/yessir/controller/HomeController.java @@ -0,0 +1,12 @@ +package yes1sir.yessir.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HomeController { + @GetMapping("/") + public String index() { + return "index"; + } +} diff --git a/src/main/java/yes1sir/yessir/controller/RecommendationController.java b/src/main/java/yes1sir/yessir/controller/RecommendationController.java index f424abb..2116068 100644 --- a/src/main/java/yes1sir/yessir/controller/RecommendationController.java +++ b/src/main/java/yes1sir/yessir/controller/RecommendationController.java @@ -1,121 +1,34 @@ package yes1sir.yessir.controller; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import yes1sir.yessir.model.Product; import yes1sir.yessir.model.SkinType; import yes1sir.yessir.service.ProductService; +import yes1sir.yessir.service.SkinTypeService; import java.util.List; -import java.util.stream.Collectors; +import java.util.Optional; @RestController -@RequestMapping("${app.base.url}/api/recommendations") +@RequestMapping("/api") public class RecommendationController { + private final SkinTypeService skinTypeService; private final ProductService productService; @Autowired - public RecommendationController(ProductService productService) { + public RecommendationController(SkinTypeService skinTypeService, ProductService productService) { + this.skinTypeService = skinTypeService; this.productService = productService; } - @GetMapping("/{skinTypeId}") - public ResponseEntity getRecommendations(@PathVariable Long skinTypeId) { - List products = productService.getProductsBySkinTypeId(skinTypeId); - if (products.isEmpty()) { - return ResponseEntity.noContent().build(); - } else { - List response = products.stream() - .map(product -> new ProductResponse( - product.getBrandName(), - product.getProductName(), - product.getRecommendedType(), - product.getApplicableSkinTypes().stream().map(SkinType::getTypeName).collect(Collectors.joining(", ")), - product.getPrice(), - product.getPurpose(), - product.getImage() - )) - .collect(Collectors.toList()); - return ResponseEntity.ok(response); - } - } - - static class ProductResponse { - private String brandName; - private String productName; - private String recommendedType; - private String applicableTypes; - private double price; - private String purpose; - private String image; - - public ProductResponse(String brandName, String productName, String recommendedType, String applicableTypes, double price, String purpose, String image) { - this.brandName = brandName; - this.productName = productName; - this.recommendedType = recommendedType; - this.applicableTypes = applicableTypes; - this.price = price; - this.purpose = purpose; - this.image = image; - } - - // Getters and setters - public String getBrandName() { - return brandName; - } - - public void setBrandName(String brandName) { - this.brandName = brandName; - } - - public String getProductName() { - return productName; - } - - public void setProductName(String productName) { - this.productName = productName; - } - - public String getRecommendedType() { - return recommendedType; - } - - public void setRecommendedType(String recommendedType) { - this.recommendedType = recommendedType; - } - - public String getApplicableTypes() { - return applicableTypes; - } - - public void setApplicableTypes(String applicableTypes) { - this.applicableTypes = applicableTypes; - } - - public double getPrice() { - return price; - } - - public void setPrice(double price) { - this.price = price; - } - - public String getPurpose() { - return purpose; - } - - public void setPurpose(String purpose) { - this.purpose = purpose; - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } + @GetMapping("/{typeName}") + public List getRecommendationsBySkinType(@PathVariable String typeName) { + Optional skinType = skinTypeService.getSkinTypeByTypeName(typeName); + return skinType.map(productService::getProductsBySkinType).orElse(null); // 적절한 에러 처리를 추가할 수 있습니다. } } diff --git a/src/main/java/yes1sir/yessir/controller/SkinTypeController.java b/src/main/java/yes1sir/yessir/controller/SkinTypeController.java deleted file mode 100644 index 5cbb406..0000000 --- a/src/main/java/yes1sir/yessir/controller/SkinTypeController.java +++ /dev/null @@ -1,92 +0,0 @@ -package yes1sir.yessir.controller; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import yes1sir.yessir.model.SkinType; -import yes1sir.yessir.service.SkinTypeService; - -@RestController -@RequestMapping("/api/skin_types") -public class SkinTypeController { - - private final SkinTypeService skinTypeService; - - @Autowired - public SkinTypeController(SkinTypeService skinTypeService) { - this.skinTypeService = skinTypeService; - } - - @GetMapping("/{userId}") - public ResponseEntity getSkinTypeByUserId(@PathVariable Long userId) { - return skinTypeService.getSkinTypeByUserId(userId) - .map(skinType -> ResponseEntity.ok(new SkinTypeResponse(userId, skinType))) - .>map(ResponseEntity::ok) - .orElseGet(() -> ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse("사용자를 찾을 수 없습니다."))); - } - - static class SkinTypeResponse { - private Long userId; - private Long skinTypeID; - private String skinTypeName; - private String description; - - public SkinTypeResponse(Long userId, SkinType skinType) { - this.userId = userId; - this.skinTypeID = skinType.getSkinTypeID(); - this.skinTypeName = skinType.getSkinTypeName(); - this.description = skinType.getDescription(); - } - - // Getters and setters - public Long getUserId() { - return userId; - } - - public void setUserId(Long userId) { - this.userId = userId; - } - - public Long getSkinTypeID() { - return skinTypeID; - } - - public void setSkinTypeID(Long skinTypeID) { - this.skinTypeID = skinTypeID; - } - - public String getSkinTypeName() { - return skinTypeName; - } - - public void setSkinTypeName(String skinTypeName) { - this.skinTypeName = skinTypeName; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - } - - static class ErrorResponse { - private String detail; - - public ErrorResponse(String detail) { - this.detail = detail; - } - - // Getter and setter - public String getDetail() { - return detail; - } - - public void setDetail(String detail) { - this.detail = detail; - } - } -} diff --git a/src/main/java/yes1sir/yessir/model/Product.java b/src/main/java/yes1sir/yessir/model/Product.java index 69c8f5b..69c4e3f 100644 --- a/src/main/java/yes1sir/yessir/model/Product.java +++ b/src/main/java/yes1sir/yessir/model/Product.java @@ -5,15 +5,17 @@ @Entity public class Product { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String brandName; + private String productName; + private String brandName; + private String recommendedType; private double price; private String purpose; private String image; - private String recommendedType; // single recommended type @ManyToMany @JoinTable( @@ -23,7 +25,7 @@ public class Product { ) private Set applicableSkinTypes; - // Getters and setters + // Getters and Setters public Long getId() { return id; } @@ -32,6 +34,14 @@ public void setId(Long id) { this.id = id; } + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + public String getBrandName() { return brandName; } @@ -40,12 +50,12 @@ public void setBrandName(String brandName) { this.brandName = brandName; } - public String getProductName() { - return productName; + public String getRecommendedType() { + return recommendedType; } - public void setProductName(String productName) { - this.productName = productName; + public void setRecommendedType(String recommendedType) { + this.recommendedType = recommendedType; } public double getPrice() { @@ -79,12 +89,4 @@ public Set getApplicableSkinTypes() { public void setApplicableSkinTypes(Set applicableSkinTypes) { this.applicableSkinTypes = applicableSkinTypes; } - - public String getRecommendedType() { - return recommendedType; - } - - public void setRecommendedType(String recommendedType) { - this.recommendedType = recommendedType; - } } diff --git a/src/main/java/yes1sir/yessir/model/SkinType.java b/src/main/java/yes1sir/yessir/model/SkinType.java index 230d7e0..e2ad757 100644 --- a/src/main/java/yes1sir/yessir/model/SkinType.java +++ b/src/main/java/yes1sir/yessir/model/SkinType.java @@ -5,15 +5,17 @@ @Entity public class SkinType { + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + private String typeName; - @ManyToMany(mappedBy = "recommendedTypes") + @ManyToMany(mappedBy = "applicableSkinTypes") private Set products; - // Getters and setters + // Getters and Setters public Long getId() { return id; } @@ -37,17 +39,4 @@ public Set getProducts() { public void setProducts(Set products) { this.products = products; } - - // 추가된 메서드들 - public Long getSkinTypeID() { - return this.id; - } - - public String getSkinTypeName() { - return this.typeName; - } - - public String getDescription() { - return "Description for " + this.typeName; // 필요에 따라 설명을 다르게 설정할 수 있습니다. - } } diff --git a/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java b/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java index bffdcb5..9295e59 100644 --- a/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java +++ b/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java @@ -3,5 +3,8 @@ import org.springframework.data.jpa.repository.JpaRepository; import yes1sir.yessir.model.SkinType; +import java.util.Optional; + public interface SkinTypeRepository extends JpaRepository { + Optional findByTypeName(String typeName); } diff --git a/src/main/java/yes1sir/yessir/service/DataInitializationService.java b/src/main/java/yes1sir/yessir/service/DataInitializationService.java index 8ffb873..54dbc61 100644 --- a/src/main/java/yes1sir/yessir/service/DataInitializationService.java +++ b/src/main/java/yes1sir/yessir/service/DataInitializationService.java @@ -26,55 +26,31 @@ public DataInitializationService(ProductRepository productRepository, SkinTypeRe @PostConstruct public void init() { // 피부 유형 저장 - SkinType DRPT = saveSkinType("DRPT"); - SkinType DRNT = saveSkinType("DRNT"); - SkinType DSPT = saveSkinType("DSPT"); - SkinType DSNT = saveSkinType("DSNT"); - SkinType DRPW = saveSkinType("DRPW"); - SkinType DRNW = saveSkinType("DRNW"); - SkinType DSPW = saveSkinType("DSPW"); - SkinType DSNW = saveSkinType("DSNW"); - SkinType ORPT = saveSkinType("ORPT"); - SkinType ORNT = saveSkinType("ORNT"); - SkinType OSPT = saveSkinType("OSPT"); - SkinType OSNT = saveSkinType("OSNT"); - SkinType ORPW = saveSkinType("ORPW"); - SkinType ORNW = saveSkinType("ORNW"); - SkinType OSPW = saveSkinType("OSPW"); - SkinType OSNW = saveSkinType("OSNW"); + SkinType DRPT = new SkinType(); + DRPT.setTypeName("DRPT"); + skinTypeRepository.save(DRPT); - // 제품 정보 저장 - Set applicableSkinTypes1 = new HashSet<>(); - applicableSkinTypes1.add(OSPT); - applicableSkinTypes1.add(OSPW); - saveProduct("원오브뎀", "[키링증정] 원오브뎀 드 뗑 쿠션 12g 2종 택 1", "D, S", applicableSkinTypes1, 23600, "여드름 억제, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); + SkinType OSPT = new SkinType(); + OSPT.setTypeName("OSPT"); + skinTypeRepository.save(OSPT); - Set applicableSkinTypes2 = new HashSet<>(); - applicableSkinTypes2.add(ORNT); - saveProduct("우르오스", "[옥택연Pick]우르오스 스킨워시 500ml 단품/기획(+메쉬파우치)", "O, W", applicableSkinTypes2, 15700, "여드름 억제, 모공 청소, 반점 제거", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020580213ko.jpg?l=ko"); + // 더 많은 피부 유형 저장 코드 생략 - Set applicableSkinTypes3 = new HashSet<>(); - applicableSkinTypes3.add(DRNT); - saveProduct("아이디얼포맨", "[콜라겐]아이디얼 포 맨 퍼펙트 올인원 기획 2024 AD(150mL+30mL)", "D, R", applicableSkinTypes3, 22500, "반점 제거, 모공 청소, 주름 제거, 탄력 증진", "https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020787604ko.jpg?l=ko"); + // 제품 저장 + Set applicableSkinTypes1 = new HashSet<>(); + applicableSkinTypes1.add(OSPT); - // 추가적인 제품 정보는 같은 형식으로 계속 삽입... - } + Product product1 = new Product(); + product1.setProductName("[키링증정] 원오브뎀 드 뎀 쿠션 12g 2종 택 1"); + product1.setBrandName("원오브뎀"); + product1.setRecommendedType("O, S"); + product1.setApplicableSkinTypes(applicableSkinTypes1); + product1.setPrice(23600); + product1.setPurpose("여드름 억제, 반점 제거"); + product1.setImage("https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); - private SkinType saveSkinType(String typeName) { - SkinType skinType = new SkinType(); - skinType.setTypeName(typeName); - return skinTypeRepository.save(skinType); - } + productRepository.save(product1); - private void saveProduct(String brandName, String productName, String recommendedType, Set applicableSkinTypes, double price, String purpose, String image) { - Product product = new Product(); - product.setBrandName(brandName); - product.setProductName(productName); - product.setRecommendedType(recommendedType); - product.setApplicableSkinTypes(applicableSkinTypes); - product.setPrice(price); - product.setPurpose(purpose); - product.setImage(image); - productRepository.save(product); + // 더 많은 제품 저장 코드 생략 } } diff --git a/src/main/java/yes1sir/yessir/service/ProductService.java b/src/main/java/yes1sir/yessir/service/ProductService.java index ad3a3a4..804acf1 100644 --- a/src/main/java/yes1sir/yessir/service/ProductService.java +++ b/src/main/java/yes1sir/yessir/service/ProductService.java @@ -5,7 +5,6 @@ import yes1sir.yessir.model.Product; import yes1sir.yessir.model.SkinType; import yes1sir.yessir.repository.ProductRepository; -import yes1sir.yessir.repository.SkinTypeRepository; import java.util.List; @@ -13,16 +12,13 @@ public class ProductService { private final ProductRepository productRepository; - private final SkinTypeRepository skinTypeRepository; @Autowired - public ProductService(ProductRepository productRepository, SkinTypeRepository skinTypeRepository) { + public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; - this.skinTypeRepository = skinTypeRepository; } - public List getProductsBySkinTypeId(Long skinTypeId) { - SkinType skinType = skinTypeRepository.findById(skinTypeId).orElseThrow(); + public List getProductsBySkinType(SkinType skinType) { return productRepository.findByApplicableSkinTypesContaining(skinType); } } diff --git a/src/main/java/yes1sir/yessir/service/SkinTypeService.java b/src/main/java/yes1sir/yessir/service/SkinTypeService.java index b399ad0..cf2bcba 100644 --- a/src/main/java/yes1sir/yessir/service/SkinTypeService.java +++ b/src/main/java/yes1sir/yessir/service/SkinTypeService.java @@ -3,22 +3,21 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import yes1sir.yessir.model.SkinType; -import yes1sir.yessir.repository.UserRepository; +import yes1sir.yessir.repository.SkinTypeRepository; import java.util.Optional; @Service public class SkinTypeService { - private final UserRepository userRepository; + private final SkinTypeRepository skinTypeRepository; @Autowired - public SkinTypeService(UserRepository userRepository) { - this.userRepository = userRepository; + public SkinTypeService(SkinTypeRepository skinTypeRepository) { + this.skinTypeRepository = skinTypeRepository; } - public Optional getSkinTypeByUserId(Long userId) { - return userRepository.findById(userId) - .flatMap(user -> Optional.ofNullable(user.getSkinType())); + public Optional getSkinTypeByTypeName(String typeName) { + return skinTypeRepository.findByTypeName(typeName); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 8619244..43e303a 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -24,3 +24,7 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect # Base URL ?? (??) app.base.url=https://api.yessir.site + +# ?? ??? ?? +spring.mvc.view.prefix=/templates/ +spring.mvc.view.suffix=.html diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..53b0263 --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,48 @@ + + + + + + Skin Type Recommendations + + +

Skin Type Recommendations

+
+ + + +
+

Recommendations

+
+ + + + diff --git a/src/test/java/yes1sir/yessir/SkinTypeControllerTest.java b/src/test/java/yes1sir/yessir/SkinTypeControllerTest.java index a1d06fb..b222145 100644 --- a/src/test/java/yes1sir/yessir/SkinTypeControllerTest.java +++ b/src/test/java/yes1sir/yessir/SkinTypeControllerTest.java @@ -12,7 +12,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; -import yes1sir.yessir.controller.SkinTypeController; import yes1sir.yessir.model.SkinType; import yes1sir.yessir.service.SkinTypeService; From 44e6b409f4079d58ec5428a93c8a3312f6ff117e Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 15:41:32 +0900 Subject: [PATCH 5/6] =?UTF-8?q?feat:=20=EC=B6=94=EC=B2=9C=20=EC=A0=9C?= =?UTF-8?q?=ED=92=88=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/yes1sir/yessir/SecurityConfig.java | 24 ++++++ .../controller/RecommendationController.java | 27 +++++-- .../yessir/dto/ProductResponseDTO.java | 79 +++++++++++++++++++ .../java/yes1sir/yessir/model/Product.java | 10 +-- .../java/yes1sir/yessir/model/SkinType.java | 17 +--- .../yessir/repository/ProductRepository.java | 4 - .../yessir/repository/SkinTypeRepository.java | 5 +- .../service/DataInitializationService.java | 5 +- .../yessir/service/ProductService.java | 5 +- .../yessir/service/SkinTypeService.java | 2 +- src/main/resources/application.properties | 6 +- 11 files changed, 149 insertions(+), 35 deletions(-) create mode 100644 src/main/java/yes1sir/yessir/SecurityConfig.java create mode 100644 src/main/java/yes1sir/yessir/dto/ProductResponseDTO.java diff --git a/src/main/java/yes1sir/yessir/SecurityConfig.java b/src/main/java/yes1sir/yessir/SecurityConfig.java new file mode 100644 index 0000000..321d5eb --- /dev/null +++ b/src/main/java/yes1sir/yessir/SecurityConfig.java @@ -0,0 +1,24 @@ +package yes1sir.yessir; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + .authorizeHttpRequests((requests) -> requests + .requestMatchers("/api/**").permitAll() // /api/** 경로에 대한 접근 허용 + .anyRequest().authenticated() + ) + .csrf(csrf -> csrf.disable()); // CSRF 비활성화 + + return http.build(); + } +} diff --git a/src/main/java/yes1sir/yessir/controller/RecommendationController.java b/src/main/java/yes1sir/yessir/controller/RecommendationController.java index 2116068..95bb19a 100644 --- a/src/main/java/yes1sir/yessir/controller/RecommendationController.java +++ b/src/main/java/yes1sir/yessir/controller/RecommendationController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import yes1sir.yessir.dto.ProductResponseDTO; import yes1sir.yessir.model.Product; import yes1sir.yessir.model.SkinType; import yes1sir.yessir.service.ProductService; @@ -12,9 +13,10 @@ import java.util.List; import java.util.Optional; +import java.util.stream.Collectors; @RestController -@RequestMapping("/api") +@RequestMapping("/api/recommendations") public class RecommendationController { private final SkinTypeService skinTypeService; @@ -26,9 +28,24 @@ public RecommendationController(SkinTypeService skinTypeService, ProductService this.productService = productService; } - @GetMapping("/{typeName}") - public List getRecommendationsBySkinType(@PathVariable String typeName) { - Optional skinType = skinTypeService.getSkinTypeByTypeName(typeName); - return skinType.map(productService::getProductsBySkinType).orElse(null); // 적절한 에러 처리를 추가할 수 있습니다. + @GetMapping("/{skinTypeName}") + public List getRecommendationsBySkinType(@PathVariable String skinTypeName) { + Optional skinType = skinTypeService.getSkinTypeByTypeName(skinTypeName); + if (skinType.isPresent()) { + List products = productService.getProductsBySkinType(skinType.get()); + return products.stream().map(product -> new ProductResponseDTO( + product.getProductName(), + product.getBrandName(), + product.getRecommendedType(), + product.getApplicableSkinTypes().stream() + .map(SkinType::getTypeName) + .collect(Collectors.joining(", ")), + product.getPrice().doubleValue(), + product.getPurpose(), + product.getImage() + )).collect(Collectors.toList()); + } else { + return null; // 또는 적절한 에러 처리를 추가할 수 있습니다. + } } } diff --git a/src/main/java/yes1sir/yessir/dto/ProductResponseDTO.java b/src/main/java/yes1sir/yessir/dto/ProductResponseDTO.java new file mode 100644 index 0000000..2bd47c7 --- /dev/null +++ b/src/main/java/yes1sir/yessir/dto/ProductResponseDTO.java @@ -0,0 +1,79 @@ +package yes1sir.yessir.dto; + +public class ProductResponseDTO { + private String productName; + private String brandName; + private String recommendedType; + private String applicableTypes; + private double price; + private String purpose; + private String image; + + public ProductResponseDTO(String productName, String brandName, String recommendedType, String applicableTypes, double price, String purpose, String image) { + this.productName = productName; + this.brandName = brandName; + this.recommendedType = recommendedType; + this.applicableTypes = applicableTypes; + this.price = price; + this.purpose = purpose; + this.image = image; + } + + // Getters and setters + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public String getBrandName() { + return brandName; + } + + public void setBrandName(String brandName) { + this.brandName = brandName; + } + + public String getRecommendedType() { + return recommendedType; + } + + public void setRecommendedType(String recommendedType) { + this.recommendedType = recommendedType; + } + + public String getApplicableTypes() { + return applicableTypes; + } + + public void setApplicableTypes(String applicableTypes) { + this.applicableTypes = applicableTypes; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + public String getPurpose() { + return purpose; + } + + public void setPurpose(String purpose) { + this.purpose = purpose; + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } +} diff --git a/src/main/java/yes1sir/yessir/model/Product.java b/src/main/java/yes1sir/yessir/model/Product.java index 69c4e3f..e2198fb 100644 --- a/src/main/java/yes1sir/yessir/model/Product.java +++ b/src/main/java/yes1sir/yessir/model/Product.java @@ -1,6 +1,7 @@ package yes1sir.yessir.model; import jakarta.persistence.*; +import java.math.BigDecimal; import java.util.Set; @Entity @@ -9,11 +10,10 @@ public class Product { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - private String productName; private String brandName; private String recommendedType; - private double price; + private BigDecimal price; private String purpose; private String image; @@ -25,7 +25,7 @@ public class Product { ) private Set applicableSkinTypes; - // Getters and Setters + // getters and setters public Long getId() { return id; } @@ -58,11 +58,11 @@ public void setRecommendedType(String recommendedType) { this.recommendedType = recommendedType; } - public double getPrice() { + public BigDecimal getPrice() { return price; } - public void setPrice(double price) { + public void setPrice(BigDecimal price) { this.price = price; } diff --git a/src/main/java/yes1sir/yessir/model/SkinType.java b/src/main/java/yes1sir/yessir/model/SkinType.java index e2ad757..957d062 100644 --- a/src/main/java/yes1sir/yessir/model/SkinType.java +++ b/src/main/java/yes1sir/yessir/model/SkinType.java @@ -1,29 +1,20 @@ package yes1sir.yessir.model; -import jakarta.persistence.*; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; import java.util.Set; @Entity public class SkinType { @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - private String typeName; @ManyToMany(mappedBy = "applicableSkinTypes") private Set products; - // Getters and Setters - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - + // getters and setters public String getTypeName() { return typeName; } diff --git a/src/main/java/yes1sir/yessir/repository/ProductRepository.java b/src/main/java/yes1sir/yessir/repository/ProductRepository.java index ab9ad72..4643f6a 100644 --- a/src/main/java/yes1sir/yessir/repository/ProductRepository.java +++ b/src/main/java/yes1sir/yessir/repository/ProductRepository.java @@ -2,10 +2,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import yes1sir.yessir.model.Product; -import yes1sir.yessir.model.SkinType; - -import java.util.List; public interface ProductRepository extends JpaRepository { - List findByApplicableSkinTypesContaining(SkinType skinType); } diff --git a/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java b/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java index 9295e59..0248799 100644 --- a/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java +++ b/src/main/java/yes1sir/yessir/repository/SkinTypeRepository.java @@ -3,8 +3,5 @@ import org.springframework.data.jpa.repository.JpaRepository; import yes1sir.yessir.model.SkinType; -import java.util.Optional; - -public interface SkinTypeRepository extends JpaRepository { - Optional findByTypeName(String typeName); +public interface SkinTypeRepository extends JpaRepository { } diff --git a/src/main/java/yes1sir/yessir/service/DataInitializationService.java b/src/main/java/yes1sir/yessir/service/DataInitializationService.java index 54dbc61..7b5d98a 100644 --- a/src/main/java/yes1sir/yessir/service/DataInitializationService.java +++ b/src/main/java/yes1sir/yessir/service/DataInitializationService.java @@ -8,6 +8,8 @@ import yes1sir.yessir.repository.SkinTypeRepository; import jakarta.annotation.PostConstruct; + +import java.math.BigDecimal; import java.util.HashSet; import java.util.Set; @@ -39,13 +41,14 @@ public void init() { // 제품 저장 Set applicableSkinTypes1 = new HashSet<>(); applicableSkinTypes1.add(OSPT); + applicableSkinTypes1.add(DRPT); Product product1 = new Product(); product1.setProductName("[키링증정] 원오브뎀 드 뎀 쿠션 12g 2종 택 1"); product1.setBrandName("원오브뎀"); product1.setRecommendedType("O, S"); product1.setApplicableSkinTypes(applicableSkinTypes1); - product1.setPrice(23600); + product1.setPrice(new BigDecimal(23600)); product1.setPurpose("여드름 억제, 반점 제거"); product1.setImage("https://image.oliveyoung.co.kr/uploads/images/goods/400/10/0000/0020/A00000020657314ko.jpg?l=ko"); diff --git a/src/main/java/yes1sir/yessir/service/ProductService.java b/src/main/java/yes1sir/yessir/service/ProductService.java index 804acf1..6e556af 100644 --- a/src/main/java/yes1sir/yessir/service/ProductService.java +++ b/src/main/java/yes1sir/yessir/service/ProductService.java @@ -7,6 +7,7 @@ import yes1sir.yessir.repository.ProductRepository; import java.util.List; +import java.util.Set; @Service public class ProductService { @@ -19,6 +20,8 @@ public ProductService(ProductRepository productRepository) { } public List getProductsBySkinType(SkinType skinType) { - return productRepository.findByApplicableSkinTypesContaining(skinType); + return productRepository.findAll().stream() + .filter(product -> product.getApplicableSkinTypes().contains(skinType)) + .toList(); } } diff --git a/src/main/java/yes1sir/yessir/service/SkinTypeService.java b/src/main/java/yes1sir/yessir/service/SkinTypeService.java index cf2bcba..037fce5 100644 --- a/src/main/java/yes1sir/yessir/service/SkinTypeService.java +++ b/src/main/java/yes1sir/yessir/service/SkinTypeService.java @@ -18,6 +18,6 @@ public SkinTypeService(SkinTypeRepository skinTypeRepository) { } public Optional getSkinTypeByTypeName(String typeName) { - return skinTypeRepository.findByTypeName(typeName); + return skinTypeRepository.findById(typeName); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 43e303a..2820e68 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -25,6 +25,10 @@ spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect # Base URL ?? (??) app.base.url=https://api.yessir.site -# ?? ??? ?? spring.mvc.view.prefix=/templates/ spring.mvc.view.suffix=.html + +# ??? ???? OAuth2 ?? ?? ?? ?? ?? +# spring.security.oauth2.client.registration.my-client-registration.client-id= +# spring.security.oauth2.client.registration.my-client-registration.client-secret= + From 84ca59b8589c30bea7b658d3b2f2e6434f9c247c Mon Sep 17 00:00:00 2001 From: shinminkyoung1 Date: Sun, 4 Aug 2024 15:44:15 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20base=20url=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application.properties | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/application.properties b/application.properties index 6f94f56..792eacf 100644 --- a/application.properties +++ b/application.properties @@ -1,9 +1,9 @@ -gitspring.application.name=yessir +spring.application.name=yessir # Google OAuth2 settings spring.security.oauth2.client.registration.google.client-id=722806291043-dd66qtm2niho4o4kdraeuisi8qj0q3.apps.googleusercontent.com spring.security.oauth2.client.registration.google.client-secret=G0CSPX-FY2pqQbeE_YP2ilAXtVvSY5YX7 -spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/google +spring.security.oauth2.client.registration.google.redirect-uri=https://api.yessir.site/login/oauth2/code/google # JWT settings jwt.secret-key=JDSFHJ435kjh43i5y9348urdfskjdhf9832ur4fsdjfhskdjfh3498r @@ -13,11 +13,17 @@ jwt.expire-length=3600000 url.access-token=https://oauth2.googleapis.com/token url.profile=https://www.googleapis.com/userinfo/v2/me -# db ?? +# Database settings spring.datasource.url=jdbc:mysql://localhost:3306/yessir_db spring.datasource.username=yessir_user spring.datasource.password=mk0702!! spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true -spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect +spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect + +# Base URL +app.base.url=https://api.yessir.site + +spring.mvc.view.prefix=/templates/ +spring.mvc.view.suffix=.html