From 902b8246dfe96b11b4d650cc00eae65f52eee57d Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 15:39:14 +0900 Subject: [PATCH 01/45] chore: build setting modification --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index df7db9334..ebac4d980 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ version = '0.0.1-SNAPSHOT' java { toolchain { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(17) } } From 4e8d336d010f2a3cbe5a1723ff28b76e50e2a3d8 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 15:40:07 +0900 Subject: [PATCH 02/45] docs: post README.md --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cafde8a2c..b04256372 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -# spring-gift-product \ No newline at end of file +# spring-gift-product + +## 기능 목록 +- 상품 클래스 생성 +- 상품 추가 기능 +- 상품 조회 기능 +- 상품 수정 기능 +- 상품 삭제 기능 +- 상품 테스트 코드 작성 +- 리팩토링 \ No newline at end of file From b8a1e9b85d0dc6bf9497c4aed463eaa9fb5bd92e Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 15:46:22 +0900 Subject: [PATCH 03/45] feat: create Product class --- src/main/java/gift/model/Product.java | 55 +++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 src/main/java/gift/model/Product.java diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java new file mode 100644 index 000000000..1a62aa527 --- /dev/null +++ b/src/main/java/gift/model/Product.java @@ -0,0 +1,55 @@ +package gift.model; + +public class Product { + + //id 값을 위해 정적 변수 선언 + private static Long id = 1L; + + private String name; + private int price; + private String imageUrl; + + public Product(Long id, String name, int price, String imageUrl) { + this.id = id; + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + // id 값 증가 + public void increase() { + this.id += 1; + } + + public static Long getId() { + return id; + } + + public static void setId(Long id) { + Product.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } +} From 1bb950dd7cba36b156222a990e13bbc3eb863a19 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 16:53:29 +0900 Subject: [PATCH 04/45] feat: create Product DTO --- src/main/java/gift/dto/ProductDTO.java | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/java/gift/dto/ProductDTO.java diff --git a/src/main/java/gift/dto/ProductDTO.java b/src/main/java/gift/dto/ProductDTO.java new file mode 100644 index 000000000..d41a0b1f3 --- /dev/null +++ b/src/main/java/gift/dto/ProductDTO.java @@ -0,0 +1,38 @@ +package gift.dto; + +public class ProductDTO { + + private String name; + private int price; + private String imageUrl; + + public ProductDTO(String name, int price, String imageUrl) { + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPrice() { + return price; + } + + public void setPrice(int price) { + this.price = price; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } +} From ddd17eee63dff45a21e211ecb23475e3705c2f6f Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 16:55:54 +0900 Subject: [PATCH 05/45] refactor: Product --- src/main/java/gift/model/Product.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java index 1a62aa527..ab6d4080d 100644 --- a/src/main/java/gift/model/Product.java +++ b/src/main/java/gift/model/Product.java @@ -9,20 +9,20 @@ public class Product { private int price; private String imageUrl; - public Product(Long id, String name, int price, String imageUrl) { - this.id = id; + public Product(String name, int price, String imageUrl) { + this.id = Product.id; // 정적 변수 ID this.name = name; this.price = price; this.imageUrl = imageUrl; } // id 값 증가 - public void increase() { - this.id += 1; + public static void increase() { + id += 1; } - public static Long getId() { - return id; + public Long getId() { + return this.id; } public static void setId(Long id) { From 5cdd9db010878d771b706da5564d161e7e56b502 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 16:56:38 +0900 Subject: [PATCH 06/45] feat: add product --- .../gift/Controller/ProductController.java | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/main/java/gift/Controller/ProductController.java diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java new file mode 100644 index 000000000..65de363b4 --- /dev/null +++ b/src/main/java/gift/Controller/ProductController.java @@ -0,0 +1,53 @@ +package gift.Controller; + +import gift.dto.ProductDTO; +import gift.model.Product; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import jdk.jfr.Description; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; + +@Controller +public class ProductController { + + // 상품 저장소 + private static final Map products = new HashMap<>(); + + /** + * 상품 추가 기능 + * + * @return Product 객체의 JSON 정보를 담은 ResponseEntity + */ + @PostMapping("/products") + public ResponseEntity postProduct(ProductDTO productDTO) { + Product product = new Product( + productDTO.getName(), + productDTO.getPrice(), + productDTO.getImageUrl() + ); + if (!existSameProduct(product)){ + products.put(product.getId(), product); + return ResponseEntity.ok(product); + } + return ResponseEntity.status(HttpStatus.CONFLICT).body("해당 이름의 상품이 이미 존재합니다."); + } + + /** + * @param product + * @return 동일한 이름을 가진 product 가 이미 존재하면 false, 그렇지 않으면 true + */ + public static boolean existSameProduct(Product product) { + for (Product p : products.values()) { + if (Objects.equals(product.getName(), p.getName())) { + System.out.println("p Name = " + p.getName() + " product name: "+ product.getName()); + return true; + } + } + return false; + } +} From 9e860bf8ab3bcd26294415dffefe3ed9ef84d956 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 17:12:33 +0900 Subject: [PATCH 07/45] feat: get product(s) --- .../gift/Controller/ProductController.java | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 65de363b4..dbd8285d0 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -10,6 +10,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @Controller @@ -24,7 +25,7 @@ public class ProductController { * @return Product 객체의 JSON 정보를 담은 ResponseEntity */ @PostMapping("/products") - public ResponseEntity postProduct(ProductDTO productDTO) { + public ResponseEntity postProduct(ProductDTO productDTO) { Product product = new Product( productDTO.getName(), productDTO.getPrice(), @@ -32,11 +33,39 @@ public ResponseEntity postProduct(ProductDTO productDTO) { ); if (!existSameProduct(product)){ products.put(product.getId(), product); + Product.increase(); return ResponseEntity.ok(product); } return ResponseEntity.status(HttpStatus.CONFLICT).body("해당 이름의 상품이 이미 존재합니다."); } + /** + * 상품 목록 전체 조회 + * @return products (상품 목록) + */ + @GetMapping("/products") + public ResponseEntity getProducts() { + if(products.size() == 0){ + return ResponseEntity.ok("상품이 존재하지 않습니다."); + } + return ResponseEntity.ok(products); + } + + /** + * 특정 ID 값의 상품 조회 + * @param id + * @return product (해당 ID 를 가진 상품) + */ + @GetMapping("/products/{id}") + public ResponseEntity getProduct(@PathVariable Long id) { + Product product = products.get(id); + if(product == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + return ResponseEntity.ok(product); + } + + /** * @param product * @return 동일한 이름을 가진 product 가 이미 존재하면 false, 그렇지 않으면 true From d6fcb53d0ca6a27bc62eb8237b95220f176f49b2 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 17:57:14 +0900 Subject: [PATCH 08/45] =?UTF-8?q?refactor:=20=EC=83=81=ED=92=88=EC=9D=98?= =?UTF-8?q?=20id=20=EC=A0=95=EC=A0=81=20=EB=B3=80=EC=88=98=20->=20?= =?UTF-8?q?=EC=A7=80=EC=97=AD=20=EB=B3=80=EC=88=98=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/model/Product.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java index ab6d4080d..a329ffeda 100644 --- a/src/main/java/gift/model/Product.java +++ b/src/main/java/gift/model/Product.java @@ -3,14 +3,15 @@ public class Product { //id 값을 위해 정적 변수 선언 - private static Long id = 1L; + private static Long productId = 1L; + private Long id; private String name; private int price; private String imageUrl; public Product(String name, int price, String imageUrl) { - this.id = Product.id; // 정적 변수 ID + this.id = Product.productId; // 정적 변수 ID this.name = name; this.price = price; this.imageUrl = imageUrl; @@ -18,7 +19,7 @@ public Product(String name, int price, String imageUrl) { // id 값 증가 public static void increase() { - id += 1; + productId += 1; } public Long getId() { @@ -26,7 +27,7 @@ public Long getId() { } public static void setId(Long id) { - Product.id = id; + Product.productId = id; } public String getName() { From 5e3b595715a1f2a565f20974b216e8efff82a97e Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 17:57:57 +0900 Subject: [PATCH 09/45] feat: modify product --- .../gift/Controller/ProductController.java | 56 ++++++++++++++++--- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index dbd8285d0..772b17e92 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -12,6 +12,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; @Controller public class ProductController { @@ -20,9 +22,9 @@ public class ProductController { private static final Map products = new HashMap<>(); /** - * 상품 추가 기능 - * - * @return Product 객체의 JSON 정보를 담은 ResponseEntity + * 상품 추가 + * @param productDTO + * @return */ @PostMapping("/products") public ResponseEntity postProduct(ProductDTO productDTO) { @@ -31,7 +33,7 @@ public ResponseEntity postProduct(ProductDTO productDTO) { productDTO.getPrice(), productDTO.getImageUrl() ); - if (!existSameProduct(product)){ + if (!existProduct(productDTO.getName())){ products.put(product.getId(), product); Product.increase(); return ResponseEntity.ok(product); @@ -65,18 +67,54 @@ public ResponseEntity getProduct(@PathVariable Long id) { return ResponseEntity.ok(product); } + /** + * 상품 내용 수정 + * @param id + * @param productDTO + * @return product (수정된 상품 정보) + */ + @PutMapping("/products/{id}") + public ResponseEntity updateProduct(@PathVariable Long id, ProductDTO productDTO) { + Product product = products.get(id); + if(product == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + if(existSameName(id, productDTO.getName())){ + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); + } + product.setName(productDTO.getName()); + product.setPrice(productDTO.getPrice()); + product.setImageUrl(productDTO.getImageUrl()); + products.put(product.getId(), product); + + return ResponseEntity.ok(product); + } /** - * @param product - * @return 동일한 이름을 가진 product 가 이미 존재하면 false, 그렇지 않으면 true + * @param name + * @return 해당 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true */ - public static boolean existSameProduct(Product product) { + public static boolean existProduct(String name) { for (Product p : products.values()) { - if (Objects.equals(product.getName(), p.getName())) { - System.out.println("p Name = " + p.getName() + " product name: "+ product.getName()); + if (Objects.equals(name, p.getName())) { return true; } } return false; } + + /** + * 상품 이름 수정 시, 다른 상품들 중 해당 이름을 가진 상품이 있는지 확인 + * @param id, name + * @return 상품 동일한 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true + */ + public static boolean existSameName(Long id, String name) { + for (Product p : products.values()) { + if (Objects.equals(name, p.getName()) && p.getId() != id) { + return true; + } + } + return false; + } + } From 22320ceba65d507c03338d9eafb776449a6c6ef8 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 18:04:02 +0900 Subject: [PATCH 10/45] feat: delete product --- .../gift/Controller/ProductController.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 772b17e92..47bbdbead 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -9,6 +9,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -90,6 +91,30 @@ public ResponseEntity updateProduct(@PathVariable Long id, ProductDTO pr return ResponseEntity.ok(product); } + /** + * 모든 상품 삭제 + * @return 삭제 완료 메시지 + */ + @DeleteMapping("/products") + public ResponseEntity deleteAllProducts(){ + products.clear(); + return ResponseEntity.ok("모든 상품을 삭제했습니다."); + } + + /** + * 해당 ID 를 가진 상품 삭제 + * @param id + * @return product (삭제된 상품 정보) + */ + @DeleteMapping("/products/{id}") + public ResponseEntity deleteProduct(@PathVariable Long id) { + if(products.get(id) == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + Product removedProduct = products.remove(id); + return ResponseEntity.ok(removedProduct); + } + /** * @param name * @return 해당 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true From b260e4a39ae261d8acd81c43abc5888363a7f0d4 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 18:18:36 +0900 Subject: [PATCH 11/45] =?UTF-8?q?refactor:=20=EB=AA=A8=EB=93=A0=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20=EB=B0=A9=EC=8B=9D=20form-data=20->=20raw-?= =?UTF-8?q?json=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Controller/ProductController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 47bbdbead..1662929ad 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -28,7 +28,7 @@ public class ProductController { * @return */ @PostMapping("/products") - public ResponseEntity postProduct(ProductDTO productDTO) { + public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { Product product = new Product( productDTO.getName(), productDTO.getPrice(), @@ -75,7 +75,7 @@ public ResponseEntity getProduct(@PathVariable Long id) { * @return product (수정된 상품 정보) */ @PutMapping("/products/{id}") - public ResponseEntity updateProduct(@PathVariable Long id, ProductDTO productDTO) { + public ResponseEntity updateProduct(@PathVariable Long id, @RequestBody ProductDTO productDTO) { Product product = products.get(id); if(product == null){ return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); @@ -117,7 +117,7 @@ public ResponseEntity deleteProduct(@PathVariable Long id) { /** * @param name - * @return 해당 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true + * @return 해당 이름을 가진 product 가 상품 목록에 존재하면 true, 그렇지 않으면 false */ public static boolean existProduct(String name) { for (Product p : products.values()) { From c937c179fc8c32897169efe2f67048d518fa0c6c Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 18:39:32 +0900 Subject: [PATCH 12/45] =?UTF-8?q?refactor:=20controller=20->=20controller?= =?UTF-8?q?=20+=20service=20=EA=B8=B0=EC=A1=B4=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=EC=9D=98=20=EC=97=AD=ED=95=A0=EC=9D=84=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=81=B4=EB=9E=98=EC=8A=A4?= =?UTF-8?q?=EB=A5=BC=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=97=AC=20MVC=20?= =?UTF-8?q?=ED=8C=A8=ED=84=B4=EC=97=90=20=EB=A7=9E=EA=B2=8C=20=EC=97=AD?= =?UTF-8?q?=ED=95=A0=20=EB=B6=84=EB=8B=B4=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift/Controller/ProductController.java | 86 +++-------- .../java/gift/Service/ProductService.java | 136 ++++++++++++++++++ 2 files changed, 153 insertions(+), 69 deletions(-) create mode 100644 src/main/java/gift/Service/ProductService.java diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 1662929ad..25f3d7740 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -1,27 +1,35 @@ package gift.Controller; +import gift.Service.ProductService; import gift.dto.ProductDTO; import gift.model.Product; import java.util.HashMap; import java.util.Map; import java.util.Objects; -import jdk.jfr.Description; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; -@Controller +@RestController public class ProductController { + private final ProductService productService; + // 상품 저장소 private static final Map products = new HashMap<>(); + @Autowired + public ProductController(ProductService productService) { + this.productService = productService; + } + /** * 상품 추가 * @param productDTO @@ -29,17 +37,7 @@ public class ProductController { */ @PostMapping("/products") public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { - Product product = new Product( - productDTO.getName(), - productDTO.getPrice(), - productDTO.getImageUrl() - ); - if (!existProduct(productDTO.getName())){ - products.put(product.getId(), product); - Product.increase(); - return ResponseEntity.ok(product); - } - return ResponseEntity.status(HttpStatus.CONFLICT).body("해당 이름의 상품이 이미 존재합니다."); + return productService.postProduct(productDTO); } /** @@ -48,10 +46,7 @@ public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { */ @GetMapping("/products") public ResponseEntity getProducts() { - if(products.size() == 0){ - return ResponseEntity.ok("상품이 존재하지 않습니다."); - } - return ResponseEntity.ok(products); + return productService.getProducts(); } /** @@ -61,11 +56,7 @@ public ResponseEntity getProducts() { */ @GetMapping("/products/{id}") public ResponseEntity getProduct(@PathVariable Long id) { - Product product = products.get(id); - if(product == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); - } - return ResponseEntity.ok(product); + return productService.getProduct(id); } /** @@ -76,19 +67,7 @@ public ResponseEntity getProduct(@PathVariable Long id) { */ @PutMapping("/products/{id}") public ResponseEntity updateProduct(@PathVariable Long id, @RequestBody ProductDTO productDTO) { - Product product = products.get(id); - if(product == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); - } - if(existSameName(id, productDTO.getName())){ - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); - } - product.setName(productDTO.getName()); - product.setPrice(productDTO.getPrice()); - product.setImageUrl(productDTO.getImageUrl()); - products.put(product.getId(), product); - - return ResponseEntity.ok(product); + return productService.updateProduct(id, productDTO); } /** @@ -97,8 +76,7 @@ public ResponseEntity updateProduct(@PathVariable Long id, @RequestBody */ @DeleteMapping("/products") public ResponseEntity deleteAllProducts(){ - products.clear(); - return ResponseEntity.ok("모든 상품을 삭제했습니다."); + return productService.deleteAllProducts(); } /** @@ -108,38 +86,8 @@ public ResponseEntity deleteAllProducts(){ */ @DeleteMapping("/products/{id}") public ResponseEntity deleteProduct(@PathVariable Long id) { - if(products.get(id) == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); - } - Product removedProduct = products.remove(id); - return ResponseEntity.ok(removedProduct); + return productService.deleteProduct(id); } - /** - * @param name - * @return 해당 이름을 가진 product 가 상품 목록에 존재하면 true, 그렇지 않으면 false - */ - public static boolean existProduct(String name) { - for (Product p : products.values()) { - if (Objects.equals(name, p.getName())) { - return true; - } - } - return false; - } - - /** - * 상품 이름 수정 시, 다른 상품들 중 해당 이름을 가진 상품이 있는지 확인 - * @param id, name - * @return 상품 동일한 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true - */ - public static boolean existSameName(Long id, String name) { - for (Product p : products.values()) { - if (Objects.equals(name, p.getName()) && p.getId() != id) { - return true; - } - } - return false; - } } diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java new file mode 100644 index 000000000..67512a1a8 --- /dev/null +++ b/src/main/java/gift/Service/ProductService.java @@ -0,0 +1,136 @@ +package gift.Service; + +import gift.dto.ProductDTO; +import gift.model.Product; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; + +@Service +public class ProductService { + + // 상품 저장소 + private static final Map products = new HashMap<>(); + + /** + * 상품 추가 + * @param productDTO + * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 + */ + public ResponseEntity postProduct(ProductDTO productDTO) { + Product product = new Product( + productDTO.getName(), + productDTO.getPrice(), + productDTO.getImageUrl() + ); + if (!existProduct(productDTO.getName())){ + products.put(product.getId(), product); + Product.increase(); + return ResponseEntity.ok(product); + } + return ResponseEntity.status(HttpStatus.CONFLICT).body("해당 이름의 상품이 이미 존재합니다."); + } + + /** + * 상품 목록 전체 조회 + * @return products (상품 목록) + */ + public ResponseEntity getProducts() { + if(products.size() == 0){ + return ResponseEntity.ok("상품이 존재하지 않습니다."); + } + return ResponseEntity.ok(products); + } + + /** + * 특정 ID 값의 상품 조회 + * @param id + * @return product (해당 ID 를 가진 상품) + */ + public ResponseEntity getProduct(Long id) { + Product product = products.get(id); + if(product == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + return ResponseEntity.ok(product); + } + + /** + * 상품 내용 수정 + * @param id + * @param productDTO + * @return product (수정된 상품 정보) + */ + public ResponseEntity updateProduct(Long id, ProductDTO productDTO) { + Product product = products.get(id); + if(product == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + if(existSameName(id, productDTO.getName())){ + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); + } + product.setName(productDTO.getName()); + product.setPrice(productDTO.getPrice()); + product.setImageUrl(productDTO.getImageUrl()); + products.put(product.getId(), product); + + return ResponseEntity.ok(product); + } + + /** + * 모든 상품 삭제 + * @return 삭제 완료 메시지 + */ + public ResponseEntity deleteAllProducts(){ + products.clear(); + return ResponseEntity.ok("모든 상품을 삭제했습니다."); + } + + /** + * 해당 ID 를 가진 상품 삭제 + * @param id + * @return product (삭제된 상품 정보) + */ + public ResponseEntity deleteProduct(Long id) { + if(products.get(id) == null){ + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + } + Product removedProduct = products.remove(id); + return ResponseEntity.ok(removedProduct); + } + + /** + * @param name + * @return 해당 이름을 가진 product 가 상품 목록에 존재하면 true, 그렇지 않으면 false + */ + public static boolean existProduct(String name) { + for (Product p : products.values()) { + if (Objects.equals(name, p.getName())) { + return true; + } + } + return false; + } + + /** + * 상품 이름 수정 시, 다른 상품들 중 해당 이름을 가진 상품이 있는지 확인 + * @param id, name + * @return 상품 동일한 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true + */ + public static boolean existSameName(Long id, String name) { + for (Product p : products.values()) { + if (Objects.equals(name, p.getName()) && p.getId() != id) { + return true; + } + } + return false; + } +} From ceb052affeb70a6664b6ca2fdb2fb8e42e8346d6 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Wed, 26 Jun 2024 21:42:16 +0900 Subject: [PATCH 13/45] =?UTF-8?q?feat:=20post,=20get=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift/Controller/ProductController.java | 4 +- .../java/gift/Service/ProductService.java | 4 +- src/main/java/gift/dto/ProductDTO.java | 3 + src/main/java/gift/model/Product.java | 13 +++ src/test/java/gift/ProductTest.java | 93 +++++++++++++++++++ 5 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 src/test/java/gift/ProductTest.java diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 25f3d7740..41480c6fd 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -33,7 +33,7 @@ public ProductController(ProductService productService) { /** * 상품 추가 * @param productDTO - * @return +git * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 */ @PostMapping("/products") public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { @@ -66,7 +66,7 @@ public ResponseEntity getProduct(@PathVariable Long id) { * @return product (수정된 상품 정보) */ @PutMapping("/products/{id}") - public ResponseEntity updateProduct(@PathVariable Long id, @RequestBody ProductDTO productDTO) { + public ResponseEntity updateProduct(@PathVariable("id") Long id, @RequestBody ProductDTO productDTO) { return productService.updateProduct(id, productDTO); } diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 67512a1a8..746725492 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -111,7 +111,7 @@ public ResponseEntity deleteProduct(Long id) { * @param name * @return 해당 이름을 가진 product 가 상품 목록에 존재하면 true, 그렇지 않으면 false */ - public static boolean existProduct(String name) { + public boolean existProduct(String name) { for (Product p : products.values()) { if (Objects.equals(name, p.getName())) { return true; @@ -125,7 +125,7 @@ public static boolean existProduct(String name) { * @param id, name * @return 상품 동일한 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true */ - public static boolean existSameName(Long id, String name) { + public boolean existSameName(Long id, String name) { for (Product p : products.values()) { if (Objects.equals(name, p.getName()) && p.getId() != id) { return true; diff --git a/src/main/java/gift/dto/ProductDTO.java b/src/main/java/gift/dto/ProductDTO.java index d41a0b1f3..d20f05a9f 100644 --- a/src/main/java/gift/dto/ProductDTO.java +++ b/src/main/java/gift/dto/ProductDTO.java @@ -6,6 +6,9 @@ public class ProductDTO { private int price; private String imageUrl; + public ProductDTO() { + } + public ProductDTO(String name, int price, String imageUrl) { this.name = name; this.price = price; diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java index a329ffeda..1a7a4c7d4 100644 --- a/src/main/java/gift/model/Product.java +++ b/src/main/java/gift/model/Product.java @@ -10,6 +10,9 @@ public class Product { private int price; private String imageUrl; + public Product() { + } + public Product(String name, int price, String imageUrl) { this.id = Product.productId; // 정적 변수 ID this.name = name; @@ -53,4 +56,14 @@ public String getImageUrl() { public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } + + @Override + public String toString() { + return "Product{" + + "id=" + id + + ", name='" + name + '\'' + + ", price=" + price + + ", imageUrl='" + imageUrl + '\'' + + '}'; + } } diff --git a/src/test/java/gift/ProductTest.java b/src/test/java/gift/ProductTest.java new file mode 100644 index 000000000..19dc188bd --- /dev/null +++ b/src/test/java/gift/ProductTest.java @@ -0,0 +1,93 @@ +package gift; + +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; + +import com.fasterxml.jackson.databind.ObjectMapper; +import gift.dto.ProductDTO; +import gift.model.Product; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class ProductTest { + + @LocalServerPort + private int port; + @Autowired + private TestRestTemplate restTemplate; + @Autowired + private ObjectMapper objectMapper; + + private Map products; + + @BeforeEach + void setUp() { + products = new HashMap<>(); + } + + /** + * 싱품 추가 테스트 + */ + @Test + void postProductTest() { + //given + String name = "아이스 아메리카노 T"; + int price = 4500; + String imageUrl = "testImageUrl.com"; + + ProductDTO productDTO = new ProductDTO(name, price, imageUrl); + String url = "http://localhost:"+port+"/products"; + + //when + ResponseEntity responseEntity = restTemplate.postForEntity(url, productDTO, Object.class); + + //then + assertEquals(responseEntity.getStatusCode(), HttpStatus.OK); + Product product = objectMapper.convertValue(responseEntity.getBody(), Product.class); + + assertThat(product.getName()).isEqualTo("아이스 아메리카노 T"); + assertThat(product.getPrice()).isEqualTo(4500); + assertThat(product.getImageUrl()).isEqualTo("testImageUrl.com"); + } + + @Test + void getProductTest() { + //given + String name = "아이스 아메리카노 T"; + int price = 4500; + String imageUrl = "testImageUrl.com"; + + ProductDTO productDTO = new ProductDTO(name, price, imageUrl); + String url = "http://localhost:"+port+"/products"; + ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, + Object.class); + Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); + Long postId = postProduct.getId(); + System.out.println("postProduct = " + postProduct); + + //when + url = "http://localhost:"+port+"/products/"+postId; + ResponseEntity getResponseEntity = restTemplate.getForEntity(url, Object.class); + Product getProduct = objectMapper.convertValue(getResponseEntity.getBody(), Product.class); + Long getId = getProduct.getId(); + System.out.println("getProduct = " + getProduct); + + //then + assertThat(getResponseEntity.getStatusCode()).isEqualTo(HttpStatus.OK); + assertThat(getProduct.getId()).isEqualTo(postId); + assertThat(getProduct.getName()).isEqualTo(name); + assertThat(getProduct.getPrice()).isEqualTo(price); + assertThat(getProduct.getImageUrl()).isEqualTo(imageUrl); + } + +} From 29d8bebe400cd15d6034a54af4d4713d01f661a2 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Thu, 27 Jun 2024 02:24:49 +0900 Subject: [PATCH 14/45] =?UTF-8?q?fix:=20@PathVariable=20=EC=97=90=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EB=B3=80=EC=88=98=20=EC=9D=B4=EB=A6=84=20?= =?UTF-8?q?=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Controller/ProductController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 41480c6fd..4b83f9f2e 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -55,7 +55,7 @@ public ResponseEntity getProducts() { * @return product (해당 ID 를 가진 상품) */ @GetMapping("/products/{id}") - public ResponseEntity getProduct(@PathVariable Long id) { + public ResponseEntity getProduct(@PathVariable("id") Long id) { return productService.getProduct(id); } @@ -85,7 +85,7 @@ public ResponseEntity deleteAllProducts(){ * @return product (삭제된 상품 정보) */ @DeleteMapping("/products/{id}") - public ResponseEntity deleteProduct(@PathVariable Long id) { + public ResponseEntity deleteProduct(@PathVariable("id") Long id) { return productService.deleteProduct(id); } From 7d6874f275fc292b749c57faee3f31809f491acb Mon Sep 17 00:00:00 2001 From: donghyuun Date: Thu, 27 Jun 2024 02:25:55 +0900 Subject: [PATCH 15/45] =?UTF-8?q?feat:=20update,=20delete=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/gift/ProductTest.java | 75 +++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/src/test/java/gift/ProductTest.java b/src/test/java/gift/ProductTest.java index 19dc188bd..b4f26010e 100644 --- a/src/test/java/gift/ProductTest.java +++ b/src/test/java/gift/ProductTest.java @@ -46,10 +46,11 @@ void postProductTest() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:"+port+"/products"; + String url = "http://localhost:" + port + "/products"; //when - ResponseEntity responseEntity = restTemplate.postForEntity(url, productDTO, Object.class); + ResponseEntity responseEntity = restTemplate.postForEntity(url, productDTO, + Object.class); //then assertEquals(responseEntity.getStatusCode(), HttpStatus.OK); @@ -60,6 +61,9 @@ void postProductTest() { assertThat(product.getImageUrl()).isEqualTo("testImageUrl.com"); } + /** + * 상품 조회 테스트 + */ @Test void getProductTest() { //given @@ -68,15 +72,16 @@ void getProductTest() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:"+port+"/products"; + String url = "http://localhost:" + port + "/products"; ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, Object.class); - Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); + Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), + Product.class); Long postId = postProduct.getId(); System.out.println("postProduct = " + postProduct); //when - url = "http://localhost:"+port+"/products/"+postId; + url = "http://localhost:" + port + "/products/" + postId; ResponseEntity getResponseEntity = restTemplate.getForEntity(url, Object.class); Product getProduct = objectMapper.convertValue(getResponseEntity.getBody(), Product.class); Long getId = getProduct.getId(); @@ -90,4 +95,64 @@ void getProductTest() { assertThat(getProduct.getImageUrl()).isEqualTo(imageUrl); } + /** + * 상품 수정 테스트 + */ + @Test + void updateProductTest() { + //given + String name = "아이스 아메리카노 T"; + int price = 4500; + String imageUrl = "testImageUrl.com"; + + ProductDTO productDTO = new ProductDTO(name, price, imageUrl); + String url = "http://localhost:" + port + "/products"; + ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, + Object.class); + Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); + Long postId = postProduct.getId(); + + //when + ProductDTO updateProductDTO = new ProductDTO(postProduct.getName(), 4700, + postProduct.getImageUrl()); + String updateUrl = "http://localhost:" + port + "/products/" + postId; + restTemplate.put(updateUrl, updateProductDTO, Object.class); + + String getUrl = updateUrl; + ResponseEntity getResponseEntity = restTemplate.getForEntity(getUrl, Object.class); + Product getProduct = objectMapper.convertValue(getResponseEntity.getBody(), Product.class); + + //then + assertThat(getProduct.getId()).isEqualTo(postId); + assertThat(getProduct.getName()).isEqualTo(name); + assertThat(getProduct.getPrice()).isEqualTo(4700); + assertThat(getProduct.getImageUrl()).isEqualTo(imageUrl); + } + + /** + * 상품 삭제 테스트 + */ + @Test + void deleteProduct() { + //given + String name = "아이스 아메리카노 T"; + int price = 4500; + String imageUrl = "testImageUrl.com"; + + ProductDTO productDTO = new ProductDTO(name, price, imageUrl); + String url = "http://localhost:" + port + "/products"; + ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, + Object.class); + Product product = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); + Long id = product.getId(); + + //when + String deleteUrl = "http://localhost:" + port + "/products/" + id; + restTemplate.delete(url); + + //then + String getUrl = "http://localhost:" + port + "/products/" + id; + ResponseEntity getResponseEntity = restTemplate.getForEntity(getUrl, String.class); + assertThat(getResponseEntity.getBody()).isEqualTo("해당 ID의 상품이 존재하지 않습니다."); + } } From 5a6d0d3711ab3fd9225d26a46368a343a9d5584d Mon Sep 17 00:00:00 2001 From: donghyuun Date: Thu, 27 Jun 2024 04:05:14 +0900 Subject: [PATCH 16/45] =?UTF-8?q?fix:=20javadoc=20=EC=9D=98=20=EC=84=A4?= =?UTF-8?q?=EB=AA=85=20=EB=B6=80=EB=B6=84=20=ED=95=9C=EC=B9=B8=20=EB=9D=84?= =?UTF-8?q?=EC=9B=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/gift/Service/ProductService.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 746725492..a422a68f2 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -22,6 +22,7 @@ public class ProductService { /** * 상품 추가 + * * @param productDTO * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 */ @@ -31,7 +32,7 @@ public ResponseEntity postProduct(ProductDTO productDTO) { productDTO.getPrice(), productDTO.getImageUrl() ); - if (!existProduct(productDTO.getName())){ + if (!existProduct(productDTO.getName())) { products.put(product.getId(), product); Product.increase(); return ResponseEntity.ok(product); @@ -41,10 +42,11 @@ public ResponseEntity postProduct(ProductDTO productDTO) { /** * 상품 목록 전체 조회 + * * @return products (상품 목록) */ public ResponseEntity getProducts() { - if(products.size() == 0){ + if (products.size() == 0) { return ResponseEntity.ok("상품이 존재하지 않습니다."); } return ResponseEntity.ok(products); @@ -52,30 +54,33 @@ public ResponseEntity getProducts() { /** * 특정 ID 값의 상품 조회 + * * @param id * @return product (해당 ID 를 가진 상품) */ public ResponseEntity getProduct(Long id) { Product product = products.get(id); - if(product == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + if (product == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); } return ResponseEntity.ok(product); } /** * 상품 내용 수정 + * * @param id * @param productDTO * @return product (수정된 상품 정보) */ public ResponseEntity updateProduct(Long id, ProductDTO productDTO) { Product product = products.get(id); - if(product == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + if (product == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); } - if(existSameName(id, productDTO.getName())){ - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); + if (existSameName(id, productDTO.getName())) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); } product.setName(productDTO.getName()); product.setPrice(productDTO.getPrice()); @@ -87,21 +92,23 @@ public ResponseEntity updateProduct(Long id, ProductDTO productDTO) { /** * 모든 상품 삭제 + * * @return 삭제 완료 메시지 */ - public ResponseEntity deleteAllProducts(){ + public ResponseEntity deleteAllProducts() { products.clear(); return ResponseEntity.ok("모든 상품을 삭제했습니다."); } /** * 해당 ID 를 가진 상품 삭제 + * * @param id * @return product (삭제된 상품 정보) */ public ResponseEntity deleteProduct(Long id) { - if(products.get(id) == null){ - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + if (products.get(id) == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); } Product removedProduct = products.remove(id); return ResponseEntity.ok(removedProduct); @@ -122,6 +129,7 @@ public boolean existProduct(String name) { /** * 상품 이름 수정 시, 다른 상품들 중 해당 이름을 가진 상품이 있는지 확인 + * * @param id, name * @return 상품 동일한 이름을 가진 product 가 이미 상품 목록에 존재하면 false, 그렇지 않으면 true */ From 35718a5e91880421e660a623b3b3570b77edf4fe Mon Sep 17 00:00:00 2001 From: donghyuun Date: Thu, 27 Jun 2024 04:05:40 +0900 Subject: [PATCH 17/45] =?UTF-8?q?chore:=20java=20=EB=B2=84=EC=A0=84=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=2017=20->=2021?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ebac4d980..df7db9334 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ version = '0.0.1-SNAPSHOT' java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) } } From 93d2b81dcea68292ce54dfe32d961c2d7db8ad56 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Thu, 27 Jun 2024 04:06:20 +0900 Subject: [PATCH 18/45] =?UTF-8?q?fix:=20API=20=EC=88=98=EC=A0=95=20"/produ?= =?UTF-8?q?cts"=20->=20"/api/products"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift/Controller/ProductController.java | 28 ++++++++++++------- src/test/java/gift/ProductTest.java | 23 +++++++-------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 4b83f9f2e..d11373c89 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -15,9 +15,11 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController +@RequestMapping(value = "/api/products") public class ProductController { private final ProductService productService; @@ -32,59 +34,65 @@ public ProductController(ProductService productService) { /** * 상품 추가 - * @param productDTO -git * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 + * + * @param productDTO git * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 */ - @PostMapping("/products") + @PostMapping public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { return productService.postProduct(productDTO); } /** * 상품 목록 전체 조회 + * * @return products (상품 목록) */ - @GetMapping("/products") + @GetMapping public ResponseEntity getProducts() { return productService.getProducts(); } /** * 특정 ID 값의 상품 조회 + * * @param id * @return product (해당 ID 를 가진 상품) */ - @GetMapping("/products/{id}") + @GetMapping("/{id}") public ResponseEntity getProduct(@PathVariable("id") Long id) { return productService.getProduct(id); } /** * 상품 내용 수정 + * * @param id * @param productDTO * @return product (수정된 상품 정보) */ - @PutMapping("/products/{id}") - public ResponseEntity updateProduct(@PathVariable("id") Long id, @RequestBody ProductDTO productDTO) { + @PutMapping("/{id}") + public ResponseEntity updateProduct(@PathVariable("id") Long id, + @RequestBody ProductDTO productDTO) { return productService.updateProduct(id, productDTO); } /** * 모든 상품 삭제 + * * @return 삭제 완료 메시지 */ - @DeleteMapping("/products") - public ResponseEntity deleteAllProducts(){ + @DeleteMapping + public ResponseEntity deleteAllProducts() { return productService.deleteAllProducts(); } /** * 해당 ID 를 가진 상품 삭제 + * * @param id * @return product (삭제된 상품 정보) */ - @DeleteMapping("/products/{id}") + @DeleteMapping("/{id}") public ResponseEntity deleteProduct(@PathVariable("id") Long id) { return productService.deleteProduct(id); } diff --git a/src/test/java/gift/ProductTest.java b/src/test/java/gift/ProductTest.java index b4f26010e..052cd71a9 100644 --- a/src/test/java/gift/ProductTest.java +++ b/src/test/java/gift/ProductTest.java @@ -8,7 +8,6 @@ import gift.model.Product; import java.util.HashMap; import java.util.Map; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -46,7 +45,7 @@ void postProductTest() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:" + port + "/products"; + String url = "http://localhost:" + port + "/api/products"; //when ResponseEntity responseEntity = restTemplate.postForEntity(url, productDTO, @@ -72,7 +71,7 @@ void getProductTest() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:" + port + "/products"; + String url = "http://localhost:" + port + "/api/products"; ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, Object.class); Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), @@ -81,7 +80,7 @@ void getProductTest() { System.out.println("postProduct = " + postProduct); //when - url = "http://localhost:" + port + "/products/" + postId; + url = "http://localhost:" + port + "/api/products/" + postId; ResponseEntity getResponseEntity = restTemplate.getForEntity(url, Object.class); Product getProduct = objectMapper.convertValue(getResponseEntity.getBody(), Product.class); Long getId = getProduct.getId(); @@ -106,16 +105,17 @@ void updateProductTest() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:" + port + "/products"; + String url = "http://localhost:" + port + "/api/products"; ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, Object.class); - Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); + Product postProduct = objectMapper.convertValue(postResponseEntity.getBody(), + Product.class); Long postId = postProduct.getId(); //when ProductDTO updateProductDTO = new ProductDTO(postProduct.getName(), 4700, postProduct.getImageUrl()); - String updateUrl = "http://localhost:" + port + "/products/" + postId; + String updateUrl = "http://localhost:" + port + "/api/products/" + postId; restTemplate.put(updateUrl, updateProductDTO, Object.class); String getUrl = updateUrl; @@ -140,19 +140,20 @@ void deleteProduct() { String imageUrl = "testImageUrl.com"; ProductDTO productDTO = new ProductDTO(name, price, imageUrl); - String url = "http://localhost:" + port + "/products"; + String url = "http://localhost:" + port + "/api/products"; ResponseEntity postResponseEntity = restTemplate.postForEntity(url, productDTO, Object.class); Product product = objectMapper.convertValue(postResponseEntity.getBody(), Product.class); Long id = product.getId(); //when - String deleteUrl = "http://localhost:" + port + "/products/" + id; - restTemplate.delete(url); + String deleteUrl = "http://localhost:" + port + "/api/products/" + id; + restTemplate.delete(deleteUrl); //then - String getUrl = "http://localhost:" + port + "/products/" + id; + String getUrl = "http://localhost:" + port + "/api/products/" + id; ResponseEntity getResponseEntity = restTemplate.getForEntity(getUrl, String.class); + assertThat(getResponseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); assertThat(getResponseEntity.getBody()).isEqualTo("해당 ID의 상품이 존재하지 않습니다."); } } From 43d6adcaf1d56301516608a581861e9a8216e1a3 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 13:32:37 +0900 Subject: [PATCH 19/45] docs(README): add step2 README --- README.md | 1 - src/main/java/gift/Controller/BasicController.java | 2 ++ src/main/java/gift/Repository/ProductRepository.java | 2 ++ src/main/resources/templates/index.html | 10 ++++++++++ 4 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 src/main/java/gift/Controller/BasicController.java create mode 100644 src/main/java/gift/Repository/ProductRepository.java create mode 100644 src/main/resources/templates/index.html diff --git a/README.md b/README.md index b04256372..1991ea826 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # spring-gift-product ## 기능 목록 -- 상품 클래스 생성 - 상품 추가 기능 - 상품 조회 기능 - 상품 수정 기능 diff --git a/src/main/java/gift/Controller/BasicController.java b/src/main/java/gift/Controller/BasicController.java new file mode 100644 index 000000000..98dc6555b --- /dev/null +++ b/src/main/java/gift/Controller/BasicController.java @@ -0,0 +1,2 @@ +package gift.Controller;public class BasicController { +} diff --git a/src/main/java/gift/Repository/ProductRepository.java b/src/main/java/gift/Repository/ProductRepository.java new file mode 100644 index 000000000..5ff52cbc5 --- /dev/null +++ b/src/main/java/gift/Repository/ProductRepository.java @@ -0,0 +1,2 @@ +package gift.Repository;public class ProductRepository { +} diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 000000000..4bdcfcb8d --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,10 @@ + + + + + $Title$ + + +$END$ + + \ No newline at end of file From e104facc75abac71485507deded86dd0fceea20b Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 13:35:20 +0900 Subject: [PATCH 20/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5(=ED=99=88=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=EC=9D=98=20=EC=9D=BC=EB=B6=80=20=EA=B8=B0=EB=8A=A5)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/templates/index.html | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index 4bdcfcb8d..e85f8f0bf 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -1,10 +1,27 @@ - + - $Title$ + Product Management System -$END$ +

Products List

+ + + + + + + + + + + + + + + + +
IDNameDescription
\ No newline at end of file From b99a57cb6374b395eb9afd260bacc777c0c9f318 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 14:25:14 +0900 Subject: [PATCH 21/45] =?UTF-8?q?refactor:=20controller=20=EB=82=B4=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EC=A0=80=EC=9E=A5=EC=86=8C=20->=20Reposit?= =?UTF-8?q?ory=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift/Repository/ProductRepository.java | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/main/java/gift/Repository/ProductRepository.java b/src/main/java/gift/Repository/ProductRepository.java index 5ff52cbc5..d4267e265 100644 --- a/src/main/java/gift/Repository/ProductRepository.java +++ b/src/main/java/gift/Repository/ProductRepository.java @@ -1,2 +1,24 @@ -package gift.Repository;public class ProductRepository { +package gift.Repository; + +import gift.Service.ProductService; +import gift.model.Product; +import java.util.HashMap; +import java.util.Map; +import org.springframework.stereotype.Repository; + +@Repository +public class ProductRepository { + + // 상품 저장소 + public static final Map products = new HashMap<>(); + + public ProductRepository() { + Product product1 = new Product("아이스 아메리카노 T", 5500, "testImageUrl.com"); + Product product2 = new Product("아이스 카푸치노 M", 5200, "testImageUrl.com"); + Product product3 = new Product("핫 초코 프라푸치노 M", 6000, "testImageUrl.com"); + + products.put(product1.getId(), product1); + products.put(product2.getId(), product2); + products.put(product3.getId(), product3); + } } From 19f022938254151fac294bc9d334b119b59f5c19 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 14:32:30 +0900 Subject: [PATCH 22/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/gift/Controller/BasicController.java | 33 +++++- .../gift/Controller/ProductController.java | 23 ++-- .../java/gift/Service/ProductService.java | 23 ++-- src/main/java/gift/model/Product.java | 3 + src/main/resources/templates/index.html | 102 ++++++++++++++---- 5 files changed, 147 insertions(+), 37 deletions(-) diff --git a/src/main/java/gift/Controller/BasicController.java b/src/main/java/gift/Controller/BasicController.java index 98dc6555b..a3974a5e4 100644 --- a/src/main/java/gift/Controller/BasicController.java +++ b/src/main/java/gift/Controller/BasicController.java @@ -1,2 +1,33 @@ -package gift.Controller;public class BasicController { +package gift.Controller; + +import gift.Service.ProductService; +import gift.model.Product; +import java.util.Map; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +@RequestMapping(value = "/api") +public class BasicController { + + private final ProductService productService; + @Autowired + public BasicController(ProductService productService) { + this.productService = productService; + } + @GetMapping + String homePage(Model model) { + // 현재 상품 목록 조회 + Map products = productService.getProducts(); + for (Product value : products.values()) { + System.out.println("value = " + value); + } + System.out.println("products.size() = " + products.size()); + model.addAttribute("products", products); + return "index"; + } } diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index d11373c89..4c10a2764 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -1,35 +1,42 @@ package gift.Controller; +import gift.Repository.ProductRepository; import gift.Service.ProductService; import gift.dto.ProductDTO; import gift.model.Product; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; -@RestController +@Controller @RequestMapping(value = "/api/products") public class ProductController { - private final ProductService productService; - // 상품 저장소 - private static final Map products = new HashMap<>(); + private final ProductService productService; + private final Map products; @Autowired public ProductController(ProductService productService) { this.productService = productService; + this.products = ProductRepository.products; } /** @@ -38,8 +45,10 @@ public ProductController(ProductService productService) { * @param productDTO git * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 */ @PostMapping - public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { - return productService.postProduct(productDTO); + @ResponseBody + public String postProduct(@ModelAttribute ProductDTO productDTO) { + String query = productService.postProduct(productDTO); + return query; } /** @@ -48,7 +57,7 @@ public ResponseEntity postProduct(@RequestBody ProductDTO productDTO) { * @return products (상품 목록) */ @GetMapping - public ResponseEntity getProducts() { + public Map getProducts() { return productService.getProducts(); } diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index a422a68f2..45d174005 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -1,10 +1,12 @@ package gift.Service; +import gift.Repository.ProductRepository; import gift.dto.ProductDTO; import gift.model.Product; import java.util.HashMap; import java.util.Map; import java.util.Objects; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; @@ -17,8 +19,12 @@ @Service public class ProductService { - // 상품 저장소 - private static final Map products = new HashMap<>(); + private final Map products; + + @Autowired + public ProductService(ProductRepository productRepository) { + this.products = productRepository.products; + } /** * 상품 추가 @@ -26,7 +32,7 @@ public class ProductService { * @param productDTO * @return 추가 성공 시 추가된 상품 정보, 실패 시 실패 메시지 */ - public ResponseEntity postProduct(ProductDTO productDTO) { + public String postProduct(ProductDTO productDTO) { Product product = new Product( productDTO.getName(), productDTO.getPrice(), @@ -35,9 +41,9 @@ public ResponseEntity postProduct(ProductDTO productDTO) { if (!existProduct(productDTO.getName())) { products.put(product.getId(), product); Product.increase(); - return ResponseEntity.ok(product); + return "상품이 성공적으로 추가되었습니다."; } - return ResponseEntity.status(HttpStatus.CONFLICT).body("해당 이름의 상품이 이미 존재합니다."); + return "해당 이름의 상품이 이미 존재합니다."; } /** @@ -45,11 +51,8 @@ public ResponseEntity postProduct(ProductDTO productDTO) { * * @return products (상품 목록) */ - public ResponseEntity getProducts() { - if (products.size() == 0) { - return ResponseEntity.ok("상품이 존재하지 않습니다."); - } - return ResponseEntity.ok(products); + public Map getProducts() { + return products; } /** diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/model/Product.java index 1a7a4c7d4..ee15b1bce 100644 --- a/src/main/java/gift/model/Product.java +++ b/src/main/java/gift/model/Product.java @@ -11,6 +11,8 @@ public class Product { private String imageUrl; public Product() { + this.id = Product.productId; + increase(); // 객체 생성 시 id 값 증가 } public Product(String name, int price, String imageUrl) { @@ -18,6 +20,7 @@ public Product(String name, int price, String imageUrl) { this.name = name; this.price = price; this.imageUrl = imageUrl; + increase(); // 객체 생성 시 id 값 증가 } // id 값 증가 diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index e85f8f0bf..c092630a5 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -3,25 +3,89 @@ Product Management System + + -

Products List

- - - - - - - - - - - - - - - - -
IDNameDescription
+
+

Products List

+ + + + + + + + + + + + + + + + + + +
IDNamePriceImage URL
+
+ + + + + + + + + + + + - \ No newline at end of file + From 0eafb22dc16479625da3ef934f4a3e19dbe16aff Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 16:00:44 +0900 Subject: [PATCH 23/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C,=20=EC=88=98=EC=A0=95=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../gift/Controller/ProductController.java | 24 ++- .../java/gift/Service/ProductService.java | 25 ++- src/main/resources/templates/index.html | 188 ++++++++++++++++++ 3 files changed, 224 insertions(+), 13 deletions(-) diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index 4c10a2764..a32dbbfc1 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -7,6 +7,7 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; @@ -80,9 +81,11 @@ public ResponseEntity getProduct(@PathVariable("id") Long id) { * @return product (수정된 상품 정보) */ @PutMapping("/{id}") - public ResponseEntity updateProduct(@PathVariable("id") Long id, + @ResponseBody + public String updateProduct(@PathVariable("id") Long id, @RequestBody ProductDTO productDTO) { - return productService.updateProduct(id, productDTO); + String message = productService.updateProduct(id, productDTO); + return message; } /** @@ -90,11 +93,23 @@ public ResponseEntity updateProduct(@PathVariable("id") Long id, * * @return 삭제 완료 메시지 */ - @DeleteMapping + @DeleteMapping("/all") public ResponseEntity deleteAllProducts() { return productService.deleteAllProducts(); } + /** + * 해당 ID 리스트에 속한 상품 삭제 + * @param productIds + * @return + */ + @DeleteMapping + @ResponseBody + public String deleteSelectedProducts(@RequestBody List productIds) { + String message = productService.deleteProductsByIds(productIds); + return message; + } + /** * 해당 ID 를 가진 상품 삭제 * @@ -102,7 +117,8 @@ public ResponseEntity deleteAllProducts() { * @return product (삭제된 상품 정보) */ @DeleteMapping("/{id}") - public ResponseEntity deleteProduct(@PathVariable("id") Long id) { + @ResponseBody + public String deleteProduct(@PathVariable("id") Long id) { return productService.deleteProduct(id); } diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 45d174005..7cea986ab 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -4,6 +4,7 @@ import gift.dto.ProductDTO; import gift.model.Product; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; @@ -76,21 +77,20 @@ public ResponseEntity getProduct(Long id) { * @param productDTO * @return product (수정된 상품 정보) */ - public ResponseEntity updateProduct(Long id, ProductDTO productDTO) { + public String updateProduct(Long id, ProductDTO productDTO) { Product product = products.get(id); if (product == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + return "해당 ID의 상품이 존재하지 않습니다."; } if (existSameName(id, productDTO.getName())) { - return ResponseEntity.status(HttpStatus.BAD_REQUEST) - .body("수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."); + return "수정할 이름을 가진 상품이 이미 존재합니다. 다른 이름을 입력하세요."; } product.setName(productDTO.getName()); product.setPrice(productDTO.getPrice()); product.setImageUrl(productDTO.getImageUrl()); products.put(product.getId(), product); - return ResponseEntity.ok(product); + return "상품이 수정되었습니다."; } /** @@ -109,12 +109,12 @@ public ResponseEntity deleteAllProducts() { * @param id * @return product (삭제된 상품 정보) */ - public ResponseEntity deleteProduct(Long id) { + public String deleteProduct(Long id) { if (products.get(id) == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("해당 ID의 상품이 존재하지 않습니다."); + return "해당 ID의 상품이 존재하지 않습니다"; } - Product removedProduct = products.remove(id); - return ResponseEntity.ok(removedProduct); + products.remove(id); + return "상품이 삭제되었습니다."; } /** @@ -144,4 +144,11 @@ public boolean existSameName(Long id, String name) { } return false; } + + public String deleteProductsByIds(List productIds) { + for (Long productId : productIds) { + products.remove(productId); + } + return "상품들이 성공적으로 제거되었습니다."; + } } diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index c092630a5..daa2169e1 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -10,9 +10,11 @@

Products List

+ + @@ -21,10 +23,19 @@

Products List

+ +
Select ID Name Price
+ + + + + + +
@@ -61,6 +72,87 @@
+ + + + + + + +
+ +
+ @@ -86,6 +178,102 @@ alert('Error adding product: ' + error.response.data.message); }); } + + function confirmDelete(productId, productName) { + // 삭제 모달에 상품 이름 설정 + $('#deleteProductName').text('상품 이름: ' + productName); + // 모달 열기 + $('#deleteProductModal').modal('show'); + // 삭제 확인 버튼에 삭제 함수 연결 + $('#deleteProductModal').find('.btn-danger').on('click', function() { + deleteProduct(productId); + }); + } + + function deleteProduct(productId) { + axios.delete('/api/products/' + productId) + .then(function (response) { + alert(response.data); + // 모달 닫기 + $('#deleteProductModal').modal('hide'); + // 페이지 리로드 + location.reload(); + }) + .catch(function (error) { + alert('Error deleting product: ' + error.response.data.message); + }); + } + + function showDeleteSelectedModal() { + var selectedIds = []; + var selectedNames = []; + + // 선택된 상품들의 ID와 이름을 배열에 추가 + $('input[type="checkbox"]:checked').each(function() { + var id = $(this).val(); + selectedIds.push(id); + }); + + if (selectedIds.length === 0) { + alert('삭제할 상품을 한 개 이상 선택하세요.'); + return; + } + + // 삭제 모달에 선택된 상품 이름들 설정 + $('#selectedProductsMessage').text('삭제할 상품의 갯수: ' + selectedIds.length + "개"); + // 모달 열기 + $('#deleteSelectedProductModal').modal('show'); + } + + function deleteSelectedConfirmed() { + var selectedIds = []; + + // 선택된 상품들의 ID를 배열에 추가 + $('input[type="checkbox"]:checked').each(function() { + selectedIds.push($(this).val()); + }); + + if (selectedIds.length === 0) { + alert('Please select at least one product to delete.'); + return; + } + + axios.delete('/api/products', { data: selectedIds }) + .then(function (response) { + alert(response.data); + // 모달 닫기 + $('#deleteSelectedProductModal').modal('hide'); + // 페이지 리로드 + location.reload(); + }) + .catch(function (error) { + alert('Error deleting selected products: ' + error.response.data.message); + }); + } + + function updateProduct(productId) { + // Form에서 변경된 데이터 가져오기 + var productName = $('#editProductName_' + productId).val(); + var productPrice = $('#editProductPrice_' + productId).val(); + var productImageUrl = $('#editProductImageUrl_' + productId).val(); + + // PUT 또는 PATCH 요청 보내기 + axios.put('/api/products/' + productId, { + name: productName, + price: productPrice, + imageUrl: productImageUrl + }) + .then(function (response) { + alert(response.data); + // 모달 닫기 + $('#editProductModal_' + productId).modal('hide'); + // 페이지 리로드 + location.reload(); + }) + .catch(function (error) { + alert('상품 수정 중 문제가 발생했습니다. ' + error.response.data.message); + }); + } From 60171d0a28f1961a5994482e81e35b90cb6393c2 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 16:07:24 +0900 Subject: [PATCH 24/45] =?UTF-8?q?docs(JavaDoc):=20javadoc=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Service/ProductService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 7cea986ab..1701b22f3 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -145,6 +145,11 @@ public boolean existSameName(Long id, String name) { return false; } + /** + * 해당 ID 리스트에 속한 상품들 삭제 + * @param productIds + * @return 성공 여부 메시지 + */ public String deleteProductsByIds(List productIds) { for (Long productId : productIds) { products.remove(productId); From a4469359f9e6c8b0a6e216d16f042915666b87f8 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 16:44:27 +0900 Subject: [PATCH 25/45] =?UTF-8?q?refactor:=20=ED=8C=8C=EC=9D=BC=EB=AA=85?= =?UTF-8?q?=20=EB=8C=80=EB=AC=B8=EC=9E=90=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Application.java | 2 ++ .../java/gift/Controller/BasicController.java | 3 +-- .../java/gift/Controller/ProductController.java | 11 ++--------- src/main/java/gift/{dto => DTO}/ProductDTO.java | 2 +- src/main/java/gift/{model => Model}/Product.java | 2 +- .../java/gift/Repository/ProductRepository.java | 3 +-- src/main/java/gift/Service/ProductService.java | 15 +++++---------- src/test/java/gift/ProductTest.java | 4 ++-- 8 files changed, 15 insertions(+), 27 deletions(-) rename src/main/java/gift/{dto => DTO}/ProductDTO.java (97%) rename src/main/java/gift/{model => Model}/Product.java (98%) diff --git a/src/main/java/gift/Application.java b/src/main/java/gift/Application.java index 61603cca0..6084d34ae 100644 --- a/src/main/java/gift/Application.java +++ b/src/main/java/gift/Application.java @@ -8,4 +8,6 @@ public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + + } diff --git a/src/main/java/gift/Controller/BasicController.java b/src/main/java/gift/Controller/BasicController.java index a3974a5e4..3577713db 100644 --- a/src/main/java/gift/Controller/BasicController.java +++ b/src/main/java/gift/Controller/BasicController.java @@ -1,10 +1,9 @@ package gift.Controller; import gift.Service.ProductService; -import gift.model.Product; +import gift.Model.Product; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index a32dbbfc1..d4ae413b6 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -2,19 +2,13 @@ import gift.Repository.ProductRepository; import gift.Service.ProductService; -import gift.dto.ProductDTO; -import gift.model.Product; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; +import gift.DTO.ProductDTO; +import gift.Model.Product; import java.util.List; import java.util.Map; -import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; @@ -24,7 +18,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; @Controller @RequestMapping(value = "/api/products") diff --git a/src/main/java/gift/dto/ProductDTO.java b/src/main/java/gift/DTO/ProductDTO.java similarity index 97% rename from src/main/java/gift/dto/ProductDTO.java rename to src/main/java/gift/DTO/ProductDTO.java index d20f05a9f..9df294cc4 100644 --- a/src/main/java/gift/dto/ProductDTO.java +++ b/src/main/java/gift/DTO/ProductDTO.java @@ -1,4 +1,4 @@ -package gift.dto; +package gift.DTO; public class ProductDTO { diff --git a/src/main/java/gift/model/Product.java b/src/main/java/gift/Model/Product.java similarity index 98% rename from src/main/java/gift/model/Product.java rename to src/main/java/gift/Model/Product.java index ee15b1bce..3ebce479f 100644 --- a/src/main/java/gift/model/Product.java +++ b/src/main/java/gift/Model/Product.java @@ -1,4 +1,4 @@ -package gift.model; +package gift.Model; public class Product { diff --git a/src/main/java/gift/Repository/ProductRepository.java b/src/main/java/gift/Repository/ProductRepository.java index d4267e265..d7f9d5e6b 100644 --- a/src/main/java/gift/Repository/ProductRepository.java +++ b/src/main/java/gift/Repository/ProductRepository.java @@ -1,7 +1,6 @@ package gift.Repository; -import gift.Service.ProductService; -import gift.model.Product; +import gift.Model.Product; import java.util.HashMap; import java.util.Map; import org.springframework.stereotype.Repository; diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 1701b22f3..5cb5ae6b2 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -1,29 +1,24 @@ package gift.Service; import gift.Repository.ProductRepository; -import gift.dto.ProductDTO; -import gift.model.Product; -import java.util.HashMap; +import gift.DTO.ProductDTO; +import gift.Model.Product; import java.util.List; import java.util.Map; import java.util.Objects; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; @Service public class ProductService { - private final Map products; + private final Map products; // 클래스 내 메모리 저장 방식 @Autowired - public ProductService(ProductRepository productRepository) { + public ProductService(ProductRepository productRepository, JdbcTemplate jdbcTemplate) { this.products = productRepository.products; } diff --git a/src/test/java/gift/ProductTest.java b/src/test/java/gift/ProductTest.java index 052cd71a9..8c46b57ee 100644 --- a/src/test/java/gift/ProductTest.java +++ b/src/test/java/gift/ProductTest.java @@ -4,8 +4,8 @@ import static org.junit.jupiter.api.Assertions.*; import com.fasterxml.jackson.databind.ObjectMapper; -import gift.dto.ProductDTO; -import gift.model.Product; +import gift.DTO.ProductDTO; +import gift.Model.Product; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.BeforeEach; From 304c9dbafab8548bb600d497a91cf1880c33432a Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 16:45:13 +0900 Subject: [PATCH 26/45] =?UTF-8?q?feat:=20JdbcTemplate=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=20=EB=B0=8F=20Product=20=ED=85=8C=EC=9D=B4=EB=B8=94=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/gift/DB/ProductTableCreator.java | 33 +++++++++++++++++++ src/main/resources/application.properties | 5 +++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/gift/DB/ProductTableCreator.java diff --git a/src/main/java/gift/DB/ProductTableCreator.java b/src/main/java/gift/DB/ProductTableCreator.java new file mode 100644 index 000000000..8315b3435 --- /dev/null +++ b/src/main/java/gift/DB/ProductTableCreator.java @@ -0,0 +1,33 @@ +package gift.DB; + +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; + +@Component +public class ProductTableCreator { + + private final JdbcTemplate jdbcTemplate; + + @Autowired + public ProductTableCreator(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @PostConstruct + public void init() { + createProductTable(); + } + + public void createProductTable() { + String sql = "CREATE TABLE IF NOT EXISTS product (" + + "id INT AUTO_INCREMENT PRIMARY KEY," + + "name VARCHAR(255) NOT NULL," + + "price DECIMAL(10, 2) NOT NULL," + + "image_url VARCHAR(255)" + + ")"; + + jdbcTemplate.execute(sql); + } +} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3d16b65f4..b0370a33c 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,6 @@ spring.application.name=spring-gift + +# h2-console ??? ?? +spring.h2.console.enabled=true +# db url +spring.datasource.url=jdbc:h2:mem:test From 0c195c727c5c73d3d0117e58c5f8999933467397 Mon Sep 17 00:00:00 2001 From: donghyuun Date: Fri, 28 Jun 2024 17:03:36 +0900 Subject: [PATCH 27/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/gift/Controller/BasicController.java | 5 +-- .../gift/Controller/ProductController.java | 2 +- .../java/gift/DB/ProductTableCreator.java | 11 ++++++ .../java/gift/Service/ProductService.java | 9 +++-- src/main/resources/templates/index.html | 36 +++++++++---------- 5 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/main/java/gift/Controller/BasicController.java b/src/main/java/gift/Controller/BasicController.java index 3577713db..d7f20b87d 100644 --- a/src/main/java/gift/Controller/BasicController.java +++ b/src/main/java/gift/Controller/BasicController.java @@ -2,6 +2,7 @@ import gift.Service.ProductService; import gift.Model.Product; +import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @@ -21,8 +22,8 @@ public BasicController(ProductService productService) { @GetMapping String homePage(Model model) { // 현재 상품 목록 조회 - Map products = productService.getProducts(); - for (Product value : products.values()) { + List products = productService.getProducts(); + for (Product value : products) { System.out.println("value = " + value); } System.out.println("products.size() = " + products.size()); diff --git a/src/main/java/gift/Controller/ProductController.java b/src/main/java/gift/Controller/ProductController.java index d4ae413b6..e0dcdcd48 100644 --- a/src/main/java/gift/Controller/ProductController.java +++ b/src/main/java/gift/Controller/ProductController.java @@ -51,7 +51,7 @@ public String postProduct(@ModelAttribute ProductDTO productDTO) { * @return products (상품 목록) */ @GetMapping - public Map getProducts() { + public List getProducts() { return productService.getProducts(); } diff --git a/src/main/java/gift/DB/ProductTableCreator.java b/src/main/java/gift/DB/ProductTableCreator.java index 8315b3435..0bd146dcf 100644 --- a/src/main/java/gift/DB/ProductTableCreator.java +++ b/src/main/java/gift/DB/ProductTableCreator.java @@ -18,6 +18,7 @@ public ProductTableCreator(JdbcTemplate jdbcTemplate) { @PostConstruct public void init() { createProductTable(); + insertInitialData(); } public void createProductTable() { @@ -30,4 +31,14 @@ public void createProductTable() { jdbcTemplate.execute(sql); } + + public void insertInitialData() { + String insert1 = "INSERT INTO product (name, price, image_url) VALUES ('아이스 아메리카노 T', 4500, 'https://example.com/image.jpg')"; + String insert2 = "INSERT INTO product (name, price, image_url) VALUES ('아이스 카푸치노 M', 4700, 'https://example.com/image.jpg')"; + String insert3 = "INSERT INTO product (name, price, image_url) VALUES ('핫 말차라떼 L', 6800, 'https://example.com/image.jpg')"; + + jdbcTemplate.execute(insert1); + jdbcTemplate.execute(insert2); + jdbcTemplate.execute(insert3); + } } diff --git a/src/main/java/gift/Service/ProductService.java b/src/main/java/gift/Service/ProductService.java index 5cb5ae6b2..480e1eae6 100644 --- a/src/main/java/gift/Service/ProductService.java +++ b/src/main/java/gift/Service/ProductService.java @@ -9,6 +9,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -16,10 +17,11 @@ public class ProductService { private final Map products; // 클래스 내 메모리 저장 방식 - + private final JdbcTemplate jdbcTemplate; // h2 DB 사용한 메모리 저장 방식 @Autowired public ProductService(ProductRepository productRepository, JdbcTemplate jdbcTemplate) { this.products = productRepository.products; + this.jdbcTemplate = jdbcTemplate; } /** @@ -47,8 +49,9 @@ public String postProduct(ProductDTO productDTO) { * * @return products (상품 목록) */ - public Map getProducts() { - return products; + public List getProducts() { + String sql = "SELECT * FROM product"; + return jdbcTemplate.query(sql, BeanPropertyRowMapper.newInstance(Product.class)); } /** diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html index daa2169e1..aa9fb9084 100644 --- a/src/main/resources/templates/index.html +++ b/src/main/resources/templates/index.html @@ -24,17 +24,17 @@

Products List

- + - - - - + + + + - + - + @@ -118,35 +118,35 @@