From ccfe6d699c932f3e6fdfd587cc53ccefa0f2639d Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 11:18:47 +0900 Subject: [PATCH 01/45] =?UTF-8?q?docs:=20=EA=B5=AC=ED=98=84=ED=95=A0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EB=AA=A9=EB=A1=9D=20=EB=B0=8F=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cafde8a2c..bcf9abdc9 100644 --- a/README.md +++ b/README.md @@ -1 +1,72 @@ -# spring-gift-product \ No newline at end of file +# spring-gift-product +상품을 조회, 추가, 수정, 삭제할 수 있는 간단한 HTTP API를 구현한다. + +* HTTP 요청과 응답은 JSON 형식으로 주고받는다. +* 현재는 별도의 데이터베이스가 없으므로 적절한 자바 컬렉션 프레임워크를 사용하여 메모리에 저장한다. + +## 상품 조회 API +### Request +GET /api/products HTTP/1.1 +### Response +HTTP/1.1 200 +Content-Type: application/json + +[ +{ +"id": 8146027, +"name": "아이스 카페 아메리카노 T", +"price": 4500, +"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} +] + +## 상품 추가 API +### Request +POST /api/products HTTP/1.1 +Content-Type: application/json + +{ +"name": "아이스 카페 아메리카노 T", +"price": 4500, +"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +### Response +HTTP/1.1 200 +Content-Type: application/json + +{ +"id": 1, +"name": "아이스 카페 아메리카노 T", +"price": 4500, +"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +## 상품 수정 API +### Request +PUT /api/products/1 HTTP/1.1 +Content-Type: application/json + +{ +"name": "핫 카페 아메리카노 T", +"price": 5000, +"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +### Response +HTTP/1.1 200 +Content-Type: application/json + +{ +"id": 1, +"name": "핫 카페 아메리카노 T", +"price": 5000, +"imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +## 상품 삭제 API +### Request +DELETE /api/products/1 HTTP/1.1 + +### Response +HTTP/1.1 200 From 6e6ec3990e3b64a1e92ee95af027644d9db17e7a Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 11:36:33 +0900 Subject: [PATCH 02/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EC=A0=80=EC=9E=A5=ED=95=A0=20Product=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EC=83=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Product.java | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/main/java/gift/Product.java diff --git a/src/main/java/gift/Product.java b/src/main/java/gift/Product.java new file mode 100644 index 000000000..816557a43 --- /dev/null +++ b/src/main/java/gift/Product.java @@ -0,0 +1,40 @@ +public class Product { + private int id; + private String name; + private int price; + private String imageUrl; + + // Getters, Setters + public int getId() { + return id; + } + + public void setId(int id) { + this.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; + } + +} \ No newline at end of file From 9794a1430128e15643441373addddf6402f6abd5 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 11:59:15 +0900 Subject: [PATCH 03/45] =?UTF-8?q?fix:=20=ED=8C=A8=ED=82=A4=EC=A7=80=20?= =?UTF-8?q?=EB=8B=A4=EC=8B=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/Product.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/gift/Product.java b/src/main/java/gift/Product.java index 816557a43..2060bc423 100644 --- a/src/main/java/gift/Product.java +++ b/src/main/java/gift/Product.java @@ -1,3 +1,5 @@ +package src.main.java.gift; + public class Product { private int id; private String name; From 7fe78e47db81643d69d8f6ac694bb02ee57b3e00 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 18:34:49 +0900 Subject: [PATCH 04/45] =?UTF-8?q?fix:=20=EB=AC=B8=EC=A0=9C=20=EC=A1=B0?= =?UTF-8?q?=EA=B1=B4=EB=8C=80=EB=A1=9C=20=EC=9E=90=EB=A3=8C=ED=98=95=20?= =?UTF-8?q?=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/Product.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/gift/Product.java b/src/main/java/gift/Product.java index 2060bc423..5402d592f 100644 --- a/src/main/java/gift/Product.java +++ b/src/main/java/gift/Product.java @@ -1,17 +1,17 @@ -package src.main.java.gift; +package gift; public class Product { - private int id; + private long id; private String name; private int price; private String imageUrl; // Getters, Setters - public int getId() { + public long getId() { return id; } - public void setId(int id) { + public void setId(long id) { this.id = id; } From 86b5f04f5cc076a5b5548afd3c77992904b131da Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 18:38:00 +0900 Subject: [PATCH 05/45] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/main/java/gift/ProductController.java diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java new file mode 100644 index 000000000..0d1f438d3 --- /dev/null +++ b/src/main/java/gift/ProductController.java @@ -0,0 +1,28 @@ +package gift; + +import jakarta.annotation.PostConstruct; +import java.util.ArrayList; +import java.util.List; +import java.util.NoSuchElementException; +import org.springframework.web.bind.annotation.*; +import java.util.HashMap; +import java.util.Map; + + +@RestController +@RequestMapping("/api/products") +public class ProductController { + private final Map products = new HashMap<>(); + private long nextId = 1L; + + @PostConstruct + public void init() { + Product product1 = new Product(); + product1.setId(8146027); + product1.setName("아이스 카페 아메리카노 T"); + product1.setPrice(4500); + product1.setImageUrl("https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg"); + products.put(product1.getId(), product1); + + } +} From 190fc0bf4ca26235c0abc3a51b62ae8276d1884b Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 18:59:23 +0900 Subject: [PATCH 06/45] =?UTF-8?q?feat:=20GET=EC=9C=BC=EB=A1=9C=20=EC=A0=84?= =?UTF-8?q?=EC=B2=B4=EC=83=81=ED=92=88=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 0d1f438d3..762b13bdf 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -25,4 +25,10 @@ public void init() { products.put(product1.getId(), product1); } + + @GetMapping + public List getProducts() { + return new ArrayList<>(products.values()); + } + } From 8c419a50dd00b364c539a19b749b98ac16c972ff Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 19:01:10 +0900 Subject: [PATCH 07/45] =?UTF-8?q?feat:=20POST=EB=A1=9C=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EB=AA=A9=EB=A1=9D=EC=97=90=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 762b13bdf..1296f1e5d 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -31,4 +31,11 @@ public List getProducts() { return new ArrayList<>(products.values()); } + @PostMapping + public Product addProduct(@RequestBody Product product) { + product.setId(nextId++); + products.put(product.getId(), product); + return product; + } + } From f87feba53a9f28a3f5a36a389d1d3046158f612f Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 19:01:46 +0900 Subject: [PATCH 08/45] =?UTF-8?q?feat:=20PUT=EC=9C=BC=EB=A1=9C=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=88=98=EC=A0=95=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 1296f1e5d..d3ef04bdf 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -38,4 +38,14 @@ public Product addProduct(@RequestBody Product product) { return product; } + @PutMapping("/{id}") + public Product updateProduct(@PathVariable Long id, @RequestBody Product product) { + if (!products.containsKey(id)) { + throw new NoSuchElementException("상품이 없습니다."); + } + product.setId(id); + products.put(id, product); + return product; + } + } From be225fb940738d5124c6056a297a43f0a17a1cdd Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 19:02:14 +0900 Subject: [PATCH 09/45] =?UTF-8?q?feat:=20Delete=EB=A1=9C=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=82=AD=EC=A0=9C=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index d3ef04bdf..e63226302 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -48,4 +48,9 @@ public Product updateProduct(@PathVariable Long id, @RequestBody Product product return product; } + @DeleteMapping("/{id}") + public void deleteProduct(@PathVariable Long id) { + products.remove(id); + } + } From 6984f31e3d3addfc3d44f37dd2fd632a85d6542c Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 19:02:51 +0900 Subject: [PATCH 10/45] =?UTF-8?q?feat:=20GET=EC=9C=BC=EB=A1=9C=20=ED=8A=B9?= =?UTF-8?q?=EC=A0=95=20=EC=83=81=ED=92=88=EB=A7=8C=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index e63226302..29bfc3701 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; +import java.util.Optional; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @@ -53,4 +55,11 @@ public void deleteProduct(@PathVariable Long id) { products.remove(id); } + @GetMapping("/{id}") + public ResponseEntity getProductById(@PathVariable("id") Long id) { + Optional product = Optional.ofNullable(products.get(id)); + return product.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()); + } + + } From 8eec380c1e67592b6812d175047bd02554bc7636 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Tue, 25 Jun 2024 19:03:30 +0900 Subject: [PATCH 11/45] =?UTF-8?q?feat:=20API=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/cafe.http | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/cafe.http diff --git a/src/main/cafe.http b/src/main/cafe.http new file mode 100644 index 000000000..9842e59ac --- /dev/null +++ b/src/main/cafe.http @@ -0,0 +1,27 @@ +### GET request to example server +GET http://localhost:8080/api/products + +### 올리기 API +POST http://localhost:8080/api/products +Content-Type: application/json + +{ + "name": "아이스 카페 아메리카노 T", + "price": 4500, + "imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +### 상품 수정 API +### Request +PUT http://localhost:8080/api/products/1 HTTP/1.1 +Content-Type: application/json + +{ + "name": "핫 카페 아메리카노 T", + "price": 5000, + "imageUrl": "https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg" +} + +### 상품 삭제 API +### Request +DELETE http://localhost:8080/api/products/3 HTTP/1.1 \ No newline at end of file From 2ec0bcb1be53b9a71200b39cc68db6bf8b056152 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Wed, 26 Jun 2024 16:04:28 +0900 Subject: [PATCH 12/45] =?UTF-8?q?fix:=20=EB=8B=A4=EB=A5=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=97=90=EC=84=9C=EC=9D=98=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 29bfc3701..2b90308cc 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -3,9 +3,6 @@ import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; -import java.util.NoSuchElementException; -import java.util.Optional; -import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; @@ -43,7 +40,7 @@ public Product addProduct(@RequestBody Product product) { @PutMapping("/{id}") public Product updateProduct(@PathVariable Long id, @RequestBody Product product) { if (!products.containsKey(id)) { - throw new NoSuchElementException("상품이 없습니다."); + throw new IllegalArgumentException("상품이 없습니다."); } product.setId(id); products.put(id, product); @@ -52,13 +49,18 @@ public Product updateProduct(@PathVariable Long id, @RequestBody Product product @DeleteMapping("/{id}") public void deleteProduct(@PathVariable Long id) { + if (!products.containsKey(id)) { + throw new IllegalArgumentException("상품이 없습니다."); + } products.remove(id); } @GetMapping("/{id}") - public ResponseEntity getProductById(@PathVariable("id") Long id) { - Optional product = Optional.ofNullable(products.get(id)); - return product.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build()); + public Object getProductById(@PathVariable("id") Long id) { + if (!products.containsKey(id)) { + throw new IllegalArgumentException("상품이 없습니다."); + } + return products.get(id); } From 04e5f3391d4739477fe424fe876886459062b620 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:06:34 +0900 Subject: [PATCH 13/45] =?UTF-8?q?style:=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @RestController를 @Controller로 수정하고 맵핑할 url 주소 수정 --- src/main/java/gift/ProductController.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 2b90308cc..027f66d09 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -4,12 +4,13 @@ import java.util.ArrayList; import java.util.List; import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; - -@RestController -@RequestMapping("/api/products") +@Controller +@RequestMapping("/products") public class ProductController { private final Map products = new HashMap<>(); private long nextId = 1L; @@ -22,7 +23,6 @@ public void init() { product1.setPrice(4500); product1.setImageUrl("https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg"); products.put(product1.getId(), product1); - } @GetMapping From 3a7e1c043e9d1945035a9f269e842efc2e0ff128 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:09:12 +0900 Subject: [PATCH 14/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 뷰에 데이터를 전달하기 위한 객체 'Model' 생성 31번 라인에서 새로운 상품을 추가하기 위한 빈 Product 객체를 모델에 추가 --- src/main/java/gift/ProductController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 027f66d09..1d930129d 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -3,6 +3,8 @@ import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; @@ -26,8 +28,10 @@ public void init() { } @GetMapping - public List getProducts() { - return new ArrayList<>(products.values()); + public String getProducts(Model model) { + model.addAttribute("products", new ArrayList<>(products.values())); + model.addAttribute("product", new Product()); // Add empty product object for the form + return "product-list"; } @PostMapping From b43278b43f5ddb46d50981bb337ea18fd0d306a9 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:12:32 +0900 Subject: [PATCH 15/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @ModelAttribute로 요청에서 Product 객체를 바인딩 --- src/main/java/gift/ProductController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 1d930129d..b7376ea61 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -35,10 +35,10 @@ public String getProducts(Model model) { } @PostMapping - public Product addProduct(@RequestBody Product product) { + public String addProduct(@ModelAttribute Product product) { product.setId(nextId++); products.put(product.getId(), product); - return product; + return "redirect:/products"; } @PutMapping("/{id}") From 58012c5edb7f4cce3ae719541acd3eb5015855d5 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:20:20 +0900 Subject: [PATCH 16/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=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/ProductController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index b7376ea61..2da8170c4 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -41,14 +41,14 @@ public String addProduct(@ModelAttribute Product product) { return "redirect:/products"; } - @PutMapping("/{id}") - public Product updateProduct(@PathVariable Long id, @RequestBody Product product) { + @PostMapping("/{id}") + public String updateProduct(@PathVariable Long id, @ModelAttribute Product product) { if (!products.containsKey(id)) { throw new IllegalArgumentException("상품이 없습니다."); } product.setId(id); products.put(id, product); - return product; + return "redirect:/products"; } @DeleteMapping("/{id}") From f193ebc4985b3c983b7f8089c35a16b1d2b86b74 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:25:58 +0900 Subject: [PATCH 17/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 2da8170c4..028b4d4fe 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -51,12 +51,13 @@ public String updateProduct(@PathVariable Long id, @ModelAttribute Product produ return "redirect:/products"; } - @DeleteMapping("/{id}") - public void deleteProduct(@PathVariable Long id) { + @PostMapping("/delete/{id}") + public String deleteProduct(@PathVariable Long id) { if (!products.containsKey(id)) { throw new IllegalArgumentException("상품이 없습니다."); } products.remove(id); + return "redirect:/products"; } @GetMapping("/{id}") From f8fdd7d43f7fcd4dc1cf57f315284c9ca1a05f1b Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:28:19 +0900 Subject: [PATCH 18/45] =?UTF-8?q?fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 028b4d4fe..649b5a69c 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -1,8 +1,6 @@ package gift; import jakarta.annotation.PostConstruct; -import java.util.ArrayList; -import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; @@ -59,14 +57,5 @@ public String deleteProduct(@PathVariable Long id) { products.remove(id); return "redirect:/products"; } - - @GetMapping("/{id}") - public Object getProductById(@PathVariable("id") Long id) { - if (!products.containsKey(id)) { - throw new IllegalArgumentException("상품이 없습니다."); - } - return products.get(id); - } - - + } From 42809266704be4cfae4a36208ef40a958b05f798 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:33:02 +0900 Subject: [PATCH 19/45] =?UTF-8?q?feat:=20=EA=B4=80=EB=A6=AC=EC=9E=90=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=9D=B4=EB=A6=84'Manage=20Products'=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/gift/ProductController.java | 2 +- src/main/resources/templates/product-list.html | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/templates/product-list.html diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 649b5a69c..04799dae2 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -57,5 +57,5 @@ public String deleteProduct(@PathVariable Long id) { products.remove(id); return "redirect:/products"; } - + } diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html new file mode 100644 index 000000000..787f44001 --- /dev/null +++ b/src/main/resources/templates/product-list.html @@ -0,0 +1,9 @@ + + + + Product Management + + + +
+

Manage Products

From 0d8334d31a9779c30e83f603341afa39e5f1bc02 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:37:09 +0900 Subject: [PATCH 20/45] =?UTF-8?q?feat:=20=EC=83=88=20=EC=83=81=ED=92=88?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80=ED=95=98=EB=8A=94=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상품을 추가하는 모달 창을 띄우는 버튼 생성 --- src/main/resources/templates/product-list.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index 787f44001..0f2f6da05 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -7,3 +7,7 @@

Manage Products

+ +
+ +
From 3dfdd2cfededb77265f409acfab838397f3bf36b Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:40:11 +0900 Subject: [PATCH 21/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=ED=85=8C=EC=9D=B4=EB=B8=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/templates/product-list.html | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index 0f2f6da05..b34629441 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -11,3 +11,29 @@

Manage Products

+ + + + + + + + + + + + + + + + + + + + +
IDNamePriceImageActions
Product Image + +
+ +
+
From 735479ed490bd63d815d463ad1c8a70d6e964c50 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:41:27 +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=EC=88=98=EC=A0=95=20=EB=AA=A8=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/templates/product-list.html | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index b34629441..6be2a0e8c 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -37,3 +37,39 @@

Manage Products

+ + + +
From a7374f6964eaae2228e2fff00a1b2eb8d71008c1 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Thu, 27 Jun 2024 21:44:11 +0900 Subject: [PATCH 23/45] =?UTF-8?q?feat:=20Java=20Script=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 'fetch'로 특정 상품의 id 가져옴 'document.getElementById('name').value = product.name;': 폼 필드에 상품 데이터를 채움 'document.getElementById('productForm').action = /products/${id};': 폼의 액션 URL을 업데이트 '$('#productModal').modal('show');': 모달 창 열기 --- .../resources/templates/product-list.html | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index 6be2a0e8c..fbf389260 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -73,3 +73,22 @@
+ + + + + + + From 109bf780100be3bfcc942de9eaf11a774218886d Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 14:31:13 +0900 Subject: [PATCH 24/45] =?UTF-8?q?feat:=20=ED=94=84=EB=A1=9C=ED=8D=BC?= =?UTF-8?q?=ED=8B=B0=20=ED=8C=8C=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit H2 데이터베이스와 SQL 스크립트 실행을 설정 --- src/main/resources/application.properties | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 3d16b65f4..982e70a15 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,10 @@ spring.application.name=spring-gift +spring.datasource.url=jdbc:h2:mem:testdb +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password=password +spring.sql.init.mode=always +spring.sql.init.schema-locations=classpath:schema.sql +spring.sql.init.data-locations=classpath:data.sql +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console From f214d866ac44b1761084d65cb324baddd66286e9 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 14:31:44 +0900 Subject: [PATCH 25/45] =?UTF-8?q?feat:=20SQL=20=EC=8A=A4=ED=81=AC=EB=A6=BD?= =?UTF-8?q?=ED=8A=B8=20=ED=8C=8C=EC=9D=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/data.sql | 1 + src/main/resources/schema.sql | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 src/main/resources/data.sql create mode 100644 src/main/resources/schema.sql diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql new file mode 100644 index 000000000..71f67572a --- /dev/null +++ b/src/main/resources/data.sql @@ -0,0 +1 @@ +INSERT INTO products (name, price, image_url) VALUES ('아이스 카페 아메리카노 T', 4500, 'https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg'); diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 000000000..aec0f8e77 --- /dev/null +++ b/src/main/resources/schema.sql @@ -0,0 +1,6 @@ +CREATE TABLE products ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + name VARCHAR(255) NOT NULL, + price INT NOT NULL, + image_url VARCHAR(255) +); \ No newline at end of file From 37f382b31cf627d10d58844f3f6199459be514b1 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 14:36:38 +0900 Subject: [PATCH 26/45] =?UTF-8?q?feat:=20Product=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=20=ED=81=B4=EB=9E=98=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0을 null로 해석하지 않도록 long을 Long으로 변환 --- src/main/java/gift/Product.java | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/java/gift/Product.java b/src/main/java/gift/Product.java index 5402d592f..50bef83f4 100644 --- a/src/main/java/gift/Product.java +++ b/src/main/java/gift/Product.java @@ -1,17 +1,29 @@ package gift; public class Product { - private long id; + private Long id; private String name; private int price; private String imageUrl; - // Getters, Setters - public long getId() { + // 기본 생성자 + public Product() { + } + + // 매개변수가 있는 생성자 + public Product(Long id, String name, int price, String imageUrl) { + this.id = id; + this.name = name; + this.price = price; + this.imageUrl = imageUrl; + } + + // Getter와 Setter 메서드 + public Long getId() { return id; } - public void setId(long id) { + public void setId(Long id) { this.id = id; } @@ -38,5 +50,4 @@ public String getImageUrl() { public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; } - } \ No newline at end of file From b265c2b83ca234341ffe81d8cd94da8f49f01b91 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 14:47:47 +0900 Subject: [PATCH 27/45] =?UTF-8?q?feat:=20=EC=83=9D=EC=84=B1=EC=9E=90=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JdbcTemplate 및 SimpleJdbcInsert를 사용하여 데이터베이스와 상호작용하고 SimpleJdbcInsert를 초기화하여, 삽입할 테이블 이름("products")과 자동 생성될 키 열("id")을 설정 --- src/main/java/gift/ProductRepository.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/gift/ProductRepository.java diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java new file mode 100644 index 000000000..4fe9835df --- /dev/null +++ b/src/main/java/gift/ProductRepository.java @@ -0,0 +1,23 @@ +package gift; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Repository; + +//import javax.annotation.PostConstruct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class ProductRepository { + private final JdbcTemplate jdbcTemplate; + private final SimpleJdbcInsert simpleJdbcInsert; + + public ProductRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("products") + .usingGeneratedKeyColumns("id"); + } + From 0b1731b9e511deec20674591fa8d2aea41f8d9dc Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 14:50:00 +0900 Subject: [PATCH 28/45] =?UTF-8?q?feat:=20=EB=AA=A8=EB=93=A0=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=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 데이터베이스에서 모든 상품을 조회 jdbcTemplate.query를 사용하여 SQL 쿼리를 실행하고, 결과를 Product 객체로 매핑 --- src/main/java/gift/ProductRepository.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java index 4fe9835df..a38523c20 100644 --- a/src/main/java/gift/ProductRepository.java +++ b/src/main/java/gift/ProductRepository.java @@ -21,3 +21,14 @@ public ProductRepository(JdbcTemplate jdbcTemplate) { .usingGeneratedKeyColumns("id"); } + public List findAll() { + return jdbcTemplate.query("SELECT * FROM products", (rs, rowNum) -> { + Product product = new Product(); + product.setId(rs.getLong("id")); + product.setName(rs.getString("name")); + product.setPrice(rs.getInt("price")); + product.setImageUrl(rs.getString("image_url")); + return product; + }); + } + From 3ea32e74d0551beb6bebbe976cb6a6894bdb9bc0 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 15:08:00 +0900 Subject: [PATCH 29/45] =?UTF-8?q?feat:=20=ED=8A=B9=EC=A0=95=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=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 주어진 id에 해당하는 상품을 조회 jdbcTemplate.queryForObject를 사용하여 SQL 쿼리를 실행하고, 결과를 Product 객체로 매핑 --- src/main/java/gift/ProductRepository.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java index a38523c20..920bd737a 100644 --- a/src/main/java/gift/ProductRepository.java +++ b/src/main/java/gift/ProductRepository.java @@ -32,3 +32,14 @@ public List findAll() { }); } + public Product findById(Long id) { + return jdbcTemplate.queryForObject("SELECT * FROM products WHERE id = ?", new Object[]{id}, (rs, rowNum) -> { + Product product = new Product(); + product.setId(rs.getLong("id")); + product.setName(rs.getString("name")); + product.setPrice(rs.getInt("price")); + product.setImageUrl(rs.getString("image_url")); + return product; + }); + } + From c322714609feba06c2520a0dcffd01e468ea3a31 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 15:08:48 +0900 Subject: [PATCH 30/45] =?UTF-8?q?feat:=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EC=A0=80=EC=9E=A5=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 새로운 상품을 데이터베이스에 삽입 SimpleJdbcInsert를 사용하여 삽입할 데이터를 설정하고, 새로운 레코드의 생성된 키 값을 반환 받아 Product 객체에 설정 --- src/main/java/gift/ProductRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java index 920bd737a..cf0108855 100644 --- a/src/main/java/gift/ProductRepository.java +++ b/src/main/java/gift/ProductRepository.java @@ -43,3 +43,13 @@ public Product findById(Long id) { }); } + public Product save(Product product) { + Map parameters = new HashMap<>(); + parameters.put("name", product.getName()); + parameters.put("price", product.getPrice()); + parameters.put("image_url", product.getImageUrl()); + Number newId = simpleJdbcInsert.executeAndReturnKey(parameters); + product.setId(newId.longValue()); + return product; + } + From 2a00fcca54970116f152efa635c99f90f627b83a Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 15:09:31 +0900 Subject: [PATCH 31/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=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 주어진 Product 객체의 데이터를 사용하여 데이터베이스의 기존 레코드를 업데이트 jdbcTemplate.update를 사용하여 SQL 쿼리를 실행 --- src/main/java/gift/ProductRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java index cf0108855..937a4ea0f 100644 --- a/src/main/java/gift/ProductRepository.java +++ b/src/main/java/gift/ProductRepository.java @@ -53,3 +53,8 @@ public Product save(Product product) { return product; } + public void update(Product product) { + jdbcTemplate.update("UPDATE products SET name = ?, price = ?, image_url = ? WHERE id = ?", + product.getName(), product.getPrice(), product.getImageUrl(), product.getId()); + } + From f2719b6d52d394091a2e9d4545d675322297cf0e Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 15:10:11 +0900 Subject: [PATCH 32/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=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 주어진 id에 해당하는 상품을 데이터베이스에서 삭제 jdbcTemplate.update를 사용하여 SQL 쿼리를 실행 --- src/main/java/gift/ProductRepository.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/gift/ProductRepository.java b/src/main/java/gift/ProductRepository.java index 937a4ea0f..a8bc4c49a 100644 --- a/src/main/java/gift/ProductRepository.java +++ b/src/main/java/gift/ProductRepository.java @@ -58,3 +58,7 @@ public void update(Product product) { product.getName(), product.getPrice(), product.getImageUrl(), product.getId()); } + public void deleteById(Long id) { + jdbcTemplate.update("DELETE FROM products WHERE id = ?", id); + } +} From a2da3387164a2f9d74755d1f2665d6b63765db18 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:16:35 +0900 Subject: [PATCH 33/45] =?UTF-8?q?feat:=20ProductRepository=EB=A5=BC=20?= =?UTF-8?q?=EC=A3=BC=EC=9E=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ProductRepository를 주입받아 데이터베이스와 상호작용 --- src/main/java/gift/ProductController.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 04799dae2..37248b08b 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -23,6 +23,10 @@ public void init() { product1.setPrice(4500); product1.setImageUrl("https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg"); products.put(product1.getId(), product1); + private final ProductRepository productRepository; + + public ProductController(ProductRepository productRepository) { + this.productRepository = productRepository; } @GetMapping From 5147fd8ee74f438247e01b6ec34c46e0d30aed51 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:17:51 +0900 Subject: [PATCH 34/45] =?UTF-8?q?feat:=20=EB=AA=A8=EB=93=A0=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=9B=84?= =?UTF-8?q?=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Model 객체를 사용해 조회된 상품 목록(products)과 새로운 상품 객체(product)를 뷰로 전달 --- src/main/java/gift/ProductController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 37248b08b..5dfa4081d 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -31,8 +31,8 @@ public ProductController(ProductRepository productRepository) { @GetMapping public String getProducts(Model model) { - model.addAttribute("products", new ArrayList<>(products.values())); - model.addAttribute("product", new Product()); // Add empty product object for the form + model.addAttribute("products", productRepository.findAll()); + model.addAttribute("product", new Product()); return "product-list"; } From c1a303f752821643ee07c4d8b31f879cfac3ad26 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:20:23 +0900 Subject: [PATCH 35/45] =?UTF-8?q?feat:=20=EC=83=88=EB=A1=9C=EC=9A=B4=20?= =?UTF-8?q?=EC=83=81=ED=92=88=EC=9D=84=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=EB=B2=A0=EC=9D=B4=EC=8A=A4=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit @ModelAttribute를 사용해 폼 데이터로부터 Product 객체를 생성, 상품을 저장하고, 예외 발생 시 RedirectAttributes를 통해 에러 메시지를 플래시 속성으로 설정 --- src/main/java/gift/ProductController.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 5dfa4081d..c3a955c81 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -37,9 +37,12 @@ public String getProducts(Model model) { } @PostMapping - public String addProduct(@ModelAttribute Product product) { - product.setId(nextId++); - products.put(product.getId(), product); + public String addProduct(@ModelAttribute Product product, RedirectAttributes redirectAttributes) { + try { + productRepository.save(product); + } catch (Exception e) { + redirectAttributes.addFlashAttribute("errorMessage", "Error adding product: " + e.getMessage()); + } return "redirect:/products"; } From 01ee909fb075e1c3a5ff04cf8d6f885c6feb2424 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:21:15 +0900 Subject: [PATCH 36/45] =?UTF-8?q?feat:=20=EA=B8=B0=EC=A1=B4=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL 경로에서 id를 받아와 수정할 상품의 ID로 설정 상품을 업데이트하고, 예외 발생 시 에러 메시지를 설정 --- src/main/java/gift/ProductController.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index c3a955c81..c5c9e3d23 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -47,12 +47,13 @@ public String addProduct(@ModelAttribute Product product, RedirectAttributes red } @PostMapping("/{id}") - public String updateProduct(@PathVariable Long id, @ModelAttribute Product product) { - if (!products.containsKey(id)) { - throw new IllegalArgumentException("상품이 없습니다."); + public String updateProduct(@PathVariable Long id, @ModelAttribute Product product, RedirectAttributes redirectAttributes) { + try { + product.setId(id); + productRepository.update(product); + } catch (Exception e) { + redirectAttributes.addFlashAttribute("errorMessage", "Error updating product: " + e.getMessage()); } - product.setId(id); - products.put(id, product); return "redirect:/products"; } From f97352b34eb0dfed4e0b8b54e19667d5be1cc35a Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:21:52 +0900 Subject: [PATCH 37/45] =?UTF-8?q?feat:=20=EC=A7=80=EC=A0=95=EB=90=9C=20ID?= =?UTF-8?q?=EC=9D=98=20=EC=83=81=ED=92=88=EC=9D=84=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit URL 경로에서 id를 받아와 해당 상품을 삭제하고, 예외 발생 시 에러 메시지를 설정 --- src/main/java/gift/ProductController.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index c5c9e3d23..f6318d886 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -58,11 +58,12 @@ public String updateProduct(@PathVariable Long id, @ModelAttribute Product produ } @PostMapping("/delete/{id}") - public String deleteProduct(@PathVariable Long id) { - if (!products.containsKey(id)) { - throw new IllegalArgumentException("상품이 없습니다."); + public String deleteProduct(@PathVariable Long id, RedirectAttributes redirectAttributes) { + try { + productRepository.deleteById(id); + } catch (Exception e) { + redirectAttributes.addFlashAttribute("errorMessage", "Error deleting product: " + e.getMessage()); } - products.remove(id); return "redirect:/products"; } From 3d8bacc5643f0ad1de19da5c611e74abd123fe08 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:23:10 +0900 Subject: [PATCH 38/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A0=95=EB=B3=B4=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지정된 ID의 상품 상세 정보를 조회하여 product-detail.html 페이지에 전달 URL 경로에서 id를 받아와 해당 상품을 조회 조회된 상품을 뷰로 전달하고, 예외 발생 시 에러 메시지를 설정하고 상품 목록 페이지로 리다이렉트 --- src/main/java/gift/ProductController.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index f6318d886..28dc9cc94 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -68,3 +68,15 @@ public String deleteProduct(@PathVariable Long id, RedirectAttributes redirectAt } } + @GetMapping("/view/{id}") + public String getProductDetails(@PathVariable("id") Long id, Model model, RedirectAttributes redirectAttributes) { + try { + Product product = productRepository.findById(id); + model.addAttribute("product", product); + } catch (Exception e) { + redirectAttributes.addFlashAttribute("errorMessage", "Product not found: " + e.getMessage()); + return "redirect:/products"; + } + return "product-detail"; + } + From d421418e882733cdf1bc8a57098d4b01f7ee4012 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:24:24 +0900 Subject: [PATCH 39/45] =?UTF-8?q?feat:=20=ED=8A=B9=EC=A0=95=20=EC=83=81?= =?UTF-8?q?=ED=92=88=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 지정된 ID의 상품을 JSON 형식으로 반환 URL 경로에서 id를 받아와 해당 상품을 조회 조회된 상품을 반환하고, 예외 발생 시 IllegalArgumentException을 던짐 --- src/main/java/gift/ProductController.java | 28 +++++++++-------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/main/java/gift/ProductController.java b/src/main/java/gift/ProductController.java index 28dc9cc94..fe165c5bc 100644 --- a/src/main/java/gift/ProductController.java +++ b/src/main/java/gift/ProductController.java @@ -1,28 +1,13 @@ package gift; -import jakarta.annotation.PostConstruct; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.*; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller @RequestMapping("/products") public class ProductController { - private final Map products = new HashMap<>(); - private long nextId = 1L; - - @PostConstruct - public void init() { - Product product1 = new Product(); - product1.setId(8146027); - product1.setName("아이스 카페 아메리카노 T"); - product1.setPrice(4500); - product1.setImageUrl("https://st.kakaocdn.net/product/gift/product/20231010111814_9a667f9eccc943648797925498bdd8a3.jpg"); - products.put(product1.getId(), product1); private final ProductRepository productRepository; public ProductController(ProductRepository productRepository) { @@ -67,7 +52,6 @@ public String deleteProduct(@PathVariable Long id, RedirectAttributes redirectAt return "redirect:/products"; } -} @GetMapping("/view/{id}") public String getProductDetails(@PathVariable("id") Long id, Model model, RedirectAttributes redirectAttributes) { try { @@ -80,3 +64,13 @@ public String getProductDetails(@PathVariable("id") Long id, Model model, Redire return "product-detail"; } + @GetMapping("/{id}") + @ResponseBody + public Product getProductById(@PathVariable("id") Long id) { + try { + return productRepository.findById(id); + } catch (Exception e) { + throw new IllegalArgumentException("Product not found: " + e.getMessage()); + } + } +} \ No newline at end of file From 729d5cc8d20de62b306da3855515582badc79c78 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:26:09 +0900 Subject: [PATCH 40/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=ED=95=B4=EC=84=9C=20=EC=A1=B0=ED=9A=8C=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 특정 ID를 입력해 상품을 조회 할 수 있는 버튼 추가하고 버튼 내용 한글로 변경 --- src/main/resources/templates/product-list.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index fbf389260..ba03b1739 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -9,7 +9,13 @@

Manage Products

- + + + +
+ + From 7e2b2a4fc8cc23602522e3e7399bdbff965bfe1e Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:29:13 +0900 Subject: [PATCH 41/45] =?UTF-8?q?fix:=20=EC=98=81=EC=96=B4=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=95=9C=EA=B8=80=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/resources/templates/product-list.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index ba03b1739..e1885ad8d 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -35,9 +35,9 @@

Manage Products

From a2a57be529a8279887b2b73fd7dc6b3297526a6f Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:29:41 +0900 Subject: [PATCH 42/45] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=EB=A7=88?= =?UTF-8?q?=EB=8B=A4=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/templates/product-list.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index e1885ad8d..a77ba19a1 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -39,6 +39,7 @@

Manage Products

+ 조회
From 163dbd0172920da9340e8856b14c08715a4e938b Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:30:37 +0900 Subject: [PATCH 43/45] =?UTF-8?q?feat:=20=EC=A1=B4=EC=9E=AC=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20ID=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EC=8B=9C=20=EC=97=90=EB=9F=AC=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/templates/product-list.html | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/resources/templates/product-list.html b/src/main/resources/templates/product-list.html index a77ba19a1..3b336ad6d 100644 --- a/src/main/resources/templates/product-list.html +++ b/src/main/resources/templates/product-list.html @@ -87,15 +87,39 @@ From 9fb6ca736fba5484933e3c8495203fc877ff49a6 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:31:15 +0900 Subject: [PATCH 44/45] =?UTF-8?q?feat:=20=EC=83=81=EC=84=B8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=ED=91=9C=EC=8B=9C=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/templates/product-detail.html | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/resources/templates/product-detail.html diff --git a/src/main/resources/templates/product-detail.html b/src/main/resources/templates/product-detail.html new file mode 100644 index 000000000..6ca8c51a3 --- /dev/null +++ b/src/main/resources/templates/product-detail.html @@ -0,0 +1,41 @@ + + + + Product Details + + + +
+

Product Details

+ + + +
Product Image - +
- +
+ + + + + + + + + + + + + + + + +
ID
Name
Price
ImageProduct Image
+ + Back to Products + + + + + + + From f1966ddc0d6ab72a5687e11b65c85a3b11429fc2 Mon Sep 17 00:00:00 2001 From: Dalsungmin Date: Fri, 28 Jun 2024 16:39:53 +0900 Subject: [PATCH 45/45] =?UTF-8?q?README=20=EC=97=85=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit step1 이후로 README를 추가해가며 작성하는 것을 깜박했습니다. 죄송합니다. 그래서 부득이하게 마지막에 업데이트 합니다. 다음부터는 신경 써서 작성하겠습니다. --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index bcf9abdc9..158236659 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ * HTTP 요청과 응답은 JSON 형식으로 주고받는다. * 현재는 별도의 데이터베이스가 없으므로 적절한 자바 컬렉션 프레임워크를 사용하여 메모리에 저장한다. + +# step1 ## 상품 조회 API ### Request GET /api/products HTTP/1.1 @@ -70,3 +72,18 @@ DELETE /api/products/1 HTTP/1.1 ### Response HTTP/1.1 200 + +# step2 +* 상품을 조회, 추가, 수정, 삭제할 수 있는 관리자 화면을 구현한다. +* Thymeleaf를 사용하여 서버 사이드 렌더링을 구현한다. +* 기본적으로는 HTML 폼 전송 등을 이용한 페이지 이동을 기반으로 하지만, 자바스크립트를 이용한 비동기 작업에 관심이 있다면 이미 만든 상품 API를 이용하여 AJAX 등의 방식을 적용할 수 있다. +* 상품 이미지의 경우, 파일을 업로드하지 않고 URL을 직접 입력한다. +* 상품을 추가하는 버튼을 누르면 모달창이 뜨면서 상세 정보를 입력하도록 생성 + +# step3 +* 자바 컬렉션 프레임워크를 사용하여 메모리에 저장하던 상품 정보를 데이터베이스에 저장한다. +* 메모리에 저장하고 있던 모든 코드를 제거하고 H2 데이터베이스를 사용하도록 변경한다. +* 사용하는 테이블은 애플리케이션이 실행될 때 구축되어야 한다. +* step2 에서 사용했던 html에서 id를 이용해 특정 상품을 검색 할 수 있는 버튼 추가 +* 각 상품마다도 버튼을 누르면 상세정보를 보여주는 페이지로 넘어가도록 구현 +* 상세정보를 보여주는 product-detail.html 추가 \ No newline at end of file