From 2be66592d1074ea6a308826db1bac5cc2a445af3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 17:08:36 +0900 Subject: [PATCH 01/72] =?UTF-8?q?feat:=201.=20/introduce/html=EB=A1=9C=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/HelloController.java | 11 +++------- .../com/example/bcsd/IntroduceController.java | 20 +++++++++++++++++++ src/main/resources/templates/hello.html | 9 +++++---- src/main/resources/templates/introduce.html | 12 +++++++++++ 4 files changed, 40 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/example/bcsd/IntroduceController.java create mode 100644 src/main/resources/templates/introduce.html diff --git a/src/main/java/com/example/bcsd/HelloController.java b/src/main/java/com/example/bcsd/HelloController.java index 9559e2f1..77da1c18 100644 --- a/src/main/java/com/example/bcsd/HelloController.java +++ b/src/main/java/com/example/bcsd/HelloController.java @@ -6,15 +6,10 @@ @Controller public class HelloController { - - @ResponseBody + // @ResponseBody @GetMapping("/hello") public String hello() { - return "Hello World!!!!!"; - } - - @GetMapping("/hello2") - public String hello2() { - return "hello"; +// return "Hello World"; //Hello World 라는 문자열을 반환 + return "hello"; //templates/hello.html 을 반환 } } diff --git a/src/main/java/com/example/bcsd/IntroduceController.java b/src/main/java/com/example/bcsd/IntroduceController.java new file mode 100644 index 00000000..0d960b59 --- /dev/null +++ b/src/main/java/com/example/bcsd/IntroduceController.java @@ -0,0 +1,20 @@ +package com.example.bcsd; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.ui.Model; + +@Controller +public class IntroduceController { + @GetMapping("/introduce/html") + public String introduce() { + return "introduce"; + } + // @GetMapping은 /greeting에 대한 HTTP GET 요청이 greeting() 메서드에 매핑되도록 합니다. + @GetMapping("/greeting") + public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { + model.addAttribute("name", name); + return "greeting"; + } +} diff --git a/src/main/resources/templates/hello.html b/src/main/resources/templates/hello.html index 09349e2d..3bb05bfd 100644 --- a/src/main/resources/templates/hello.html +++ b/src/main/resources/templates/hello.html @@ -1,9 +1,10 @@ - + - 안녕하세요 + + hello -

안녕!!!

+

hi hello~~~~~~

- \ No newline at end of file + diff --git a/src/main/resources/templates/introduce.html b/src/main/resources/templates/introduce.html new file mode 100644 index 00000000..d043d575 --- /dev/null +++ b/src/main/resources/templates/introduce.html @@ -0,0 +1,12 @@ + + + + + + +

안녕. 내 이름은 윤해인이야.

+

나는 컴퓨터공학부 4학년이야.

+

만나서 반가워. 잘 부탁해!

+ + + From ef40bb1182680262253955210570619436e8fd1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 18:04:51 +0900 Subject: [PATCH 02/72] =?UTF-8?q?feat:=202.=20/introduce/string=3Fname=3D?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EC=B6=9C=EB=A0=A5=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/HelloController.java | 4 +--- .../java/com/example/bcsd/IntroduceController.java | 11 +++++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/bcsd/HelloController.java b/src/main/java/com/example/bcsd/HelloController.java index 77da1c18..c7476b30 100644 --- a/src/main/java/com/example/bcsd/HelloController.java +++ b/src/main/java/com/example/bcsd/HelloController.java @@ -2,14 +2,12 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; @Controller public class HelloController { - // @ResponseBody + @GetMapping("/hello") public String hello() { -// return "Hello World"; //Hello World 라는 문자열을 반환 return "hello"; //templates/hello.html 을 반환 } } diff --git a/src/main/java/com/example/bcsd/IntroduceController.java b/src/main/java/com/example/bcsd/IntroduceController.java index 0d960b59..bfb985b8 100644 --- a/src/main/java/com/example/bcsd/IntroduceController.java +++ b/src/main/java/com/example/bcsd/IntroduceController.java @@ -4,17 +4,20 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RestController; +@RestController @Controller public class IntroduceController { @GetMapping("/introduce/html") public String introduce() { return "introduce"; } - // @GetMapping은 /greeting에 대한 HTTP GET 요청이 greeting() 메서드에 매핑되도록 합니다. - @GetMapping("/greeting") - public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { + + // @GetMapping은 /introduce/에 대한 HTTP GET 요청이 introduce() 메서드에 매핑되도록 합니다. + @GetMapping("/introduce/string") // 쿼리는 여기에 미포함 + public String introduce2(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { model.addAttribute("name", name); - return "greeting"; + return "hello " + name + "!"; } } From f91348e46ae93573e4dc97bca3f75d88a00f893f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 18:57:49 +0900 Subject: [PATCH 03/72] =?UTF-8?q?feat:=203.=20JSON=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/IntroduceController.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/IntroduceController.java b/src/main/java/com/example/bcsd/IntroduceController.java index bfb985b8..dbc26be5 100644 --- a/src/main/java/com/example/bcsd/IntroduceController.java +++ b/src/main/java/com/example/bcsd/IntroduceController.java @@ -4,10 +4,14 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; +import java.util.HashMap; +import java.util.Map; + @RestController -@Controller +//@Controller public class IntroduceController { @GetMapping("/introduce/html") public String introduce() { @@ -20,4 +24,18 @@ public String introduce2(@RequestParam(name="name", required=false, defaultValue model.addAttribute("name", name); return "hello " + name + "!"; } +// <1> +// @GetMapping("/introduce/json") // 쿼리는 여기에 미포함 +// @ResponseBody +// public String introduce3(){ +// return "{\"name\":\"해인\",\"age\":24}"; +// } +// <2> 객체를 json으로 자동 반환하기 + @GetMapping("/introduce/json") + public Map introduce3() { + Map response = new HashMap<>(); + response.put("name", "윤해인"); + response.put("age", 24); + return response; + } } From 8c85ccdd599ee8984183624ccf4ee4888bc98dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 20:57:15 +0900 Subject: [PATCH 04/72] =?UTF-8?q?feat:=20CRUP=20API=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/ArticleController.java | 64 +++++++++++++++++++ .../com/example/bcsd/IntroduceController.java | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/bcsd/ArticleController.java diff --git a/src/main/java/com/example/bcsd/ArticleController.java b/src/main/java/com/example/bcsd/ArticleController.java new file mode 100644 index 00000000..5770c36a --- /dev/null +++ b/src/main/java/com/example/bcsd/ArticleController.java @@ -0,0 +1,64 @@ +package com.example.bcsd; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ResponseStatusException; + +import java.util.HashMap; +import java.util.Map; + +@RestController +@RequestMapping("/articles") //getMapping, PostMapping, PutMapping, DeleteMapping 전부 포함! +public class ArticleController { + + // data가 들어있는 객체 map 생성. key-value 구조(Java의 딕셔너리 격) + private Map articles = new HashMap<>(); + private int nextId = 1; + + static class Article { + public int id; + public String title; + public String content; + + public Article() {} // JSON 파싱용 기본 생성자 + + // article은 id(글 번호), title(글 제목), content(글 내용)으로 이루어짐 + // new 사용해서 새로 생성하지 않는 것이 순수 java와의 차이점임! + public Article(int id, String title, String content) { + this.id = id; + this.title = title; + this.content = content; + } + } + // Create (POST) + @PostMapping + public Article create(@RequestBody Article article) { + article.id = nextId++; + articles.put(article.id, article); + return article; + } + + // Read (GET) + @GetMapping("/{id}") + public Article read(@PathVariable int id) { + Article article = articles.get(id); + return article; + } + + // Update (PUT) + @PutMapping("/{id}") + public Article update(@PathVariable int id, @RequestBody Article updated) { + Article old = articles.get(id); + if (old == null) return null; + old.title = updated.title; + old.content = updated.content; + return old; + } + + // Delete (DELETE) + @DeleteMapping("/{id}") + public String delete(@PathVariable int id) { + articles.remove(id); + return "Deleted article " + id; + } +} diff --git a/src/main/java/com/example/bcsd/IntroduceController.java b/src/main/java/com/example/bcsd/IntroduceController.java index dbc26be5..7aed523f 100644 --- a/src/main/java/com/example/bcsd/IntroduceController.java +++ b/src/main/java/com/example/bcsd/IntroduceController.java @@ -25,7 +25,7 @@ public String introduce2(@RequestParam(name="name", required=false, defaultValue return "hello " + name + "!"; } // <1> -// @GetMapping("/introduce/json") // 쿼리는 여기에 미포함 +// @GetMapping("/introduce/json") // @ResponseBody // public String introduce3(){ // return "{\"name\":\"해인\",\"age\":24}"; From 1929b230ee093fdc979d601bbde97533431aa2f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 20:58:46 +0900 Subject: [PATCH 05/72] =?UTF-8?q?feat:=20GET=20(404=20NOT=20FOUND)?= =?UTF-8?q?=EC=98=88=EC=99=B8=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/com/example/bcsd/ArticleController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/bcsd/ArticleController.java b/src/main/java/com/example/bcsd/ArticleController.java index 5770c36a..bf099145 100644 --- a/src/main/java/com/example/bcsd/ArticleController.java +++ b/src/main/java/com/example/bcsd/ArticleController.java @@ -42,6 +42,9 @@ public Article create(@RequestBody Article article) { @GetMapping("/{id}") public Article read(@PathVariable int id) { Article article = articles.get(id); + if (article == null) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Article not found"); + } return article; } From 3ca1877ef4d4ffac84ea2b0739f0e757bcdad0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 21:37:19 +0900 Subject: [PATCH 06/72] =?UTF-8?q?feat:=20PUT,=20DELETE=20ResponseEntity?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=ED=9B=84=20=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=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 --- .../com/example/bcsd/ArticleController.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/bcsd/ArticleController.java b/src/main/java/com/example/bcsd/ArticleController.java index bf099145..a8e46a86 100644 --- a/src/main/java/com/example/bcsd/ArticleController.java +++ b/src/main/java/com/example/bcsd/ArticleController.java @@ -1,6 +1,7 @@ package com.example.bcsd; import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; @@ -32,36 +33,38 @@ public Article(int id, String title, String content) { } // Create (POST) @PostMapping - public Article create(@RequestBody Article article) { + public ResponseEntity
create(@RequestBody Article article) { article.id = nextId++; articles.put(article.id, article); - return article; + return ResponseEntity.status(HttpStatus.CREATED).body(article); } // Read (GET) @GetMapping("/{id}") - public Article read(@PathVariable int id) { + public ResponseEntity
read(@PathVariable int id) { Article article = articles.get(id); - if (article == null) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Article not found"); - } - return article; + return ResponseEntity.ok(article); } // Update (PUT) @PutMapping("/{id}") - public Article update(@PathVariable int id, @RequestBody Article updated) { + public ResponseEntity
update(@PathVariable int id, @RequestBody Article updated) { Article old = articles.get(id); - if (old == null) return null; + if (old == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } old.title = updated.title; old.content = updated.content; - return old; + return ResponseEntity.ok(old); } // Delete (DELETE) @DeleteMapping("/{id}") - public String delete(@PathVariable int id) { + public ResponseEntity delete(@PathVariable int id) { + if (!articles.containsKey(id)) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Article not found"); + } articles.remove(id); - return "Deleted article " + id; + return ResponseEntity.status(HttpStatus.NO_CONTENT).body("Deleted article " + id); } } From bea25b71651cfd5bb8e64f1e47c53ae7d55fe537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 10 Nov 2025 21:38:53 +0900 Subject: [PATCH 07/72] =?UTF-8?q?feat:=20GET=20ResponseEntity=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=9B=84=20=EC=98=88=EC=99=B8=EC=B2=98?= =?UTF-8?q?=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/com/example/bcsd/ArticleController.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/example/bcsd/ArticleController.java b/src/main/java/com/example/bcsd/ArticleController.java index a8e46a86..d6b45e1f 100644 --- a/src/main/java/com/example/bcsd/ArticleController.java +++ b/src/main/java/com/example/bcsd/ArticleController.java @@ -43,6 +43,9 @@ public ResponseEntity
create(@RequestBody Article article) { @GetMapping("/{id}") public ResponseEntity
read(@PathVariable int id) { Article article = articles.get(id); + if (article == null) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } return ResponseEntity.ok(article); } From 421f6cf86c1c7cf248bf5496c60f23f6ac2b0292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 10:57:58 +0900 Subject: [PATCH 08/72] =?UTF-8?q?refactor:=20hello=20=EC=98=88=EC=A0=9C?= =?UTF-8?q?=EB=A5=BC=20MVC=EB=AA=A8=EB=8D=B8=EB=A1=9C=20=EB=A6=AC=ED=8C=A9?= =?UTF-8?q?=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/ArticleController.java | 73 ------------------- .../com/example/bcsd/HelloController.java | 13 ---- .../com/example/bcsd/IntroduceController.java | 41 ----------- .../bcsd/controller/HelloController.java | 45 ++++++++++++ .../bcsd/repository/HelloRepository.java | 15 ++++ .../example/bcsd/service/HelloService.java | 32 ++++++++ src/main/resources/templates/greeting.html | 6 ++ 7 files changed, 98 insertions(+), 127 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/ArticleController.java delete mode 100644 src/main/java/com/example/bcsd/HelloController.java delete mode 100644 src/main/java/com/example/bcsd/IntroduceController.java create mode 100644 src/main/java/com/example/bcsd/controller/HelloController.java create mode 100644 src/main/java/com/example/bcsd/repository/HelloRepository.java create mode 100644 src/main/java/com/example/bcsd/service/HelloService.java create mode 100644 src/main/resources/templates/greeting.html diff --git a/src/main/java/com/example/bcsd/ArticleController.java b/src/main/java/com/example/bcsd/ArticleController.java deleted file mode 100644 index d6b45e1f..00000000 --- a/src/main/java/com/example/bcsd/ArticleController.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.example.bcsd; - -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.server.ResponseStatusException; - -import java.util.HashMap; -import java.util.Map; - -@RestController -@RequestMapping("/articles") //getMapping, PostMapping, PutMapping, DeleteMapping 전부 포함! -public class ArticleController { - - // data가 들어있는 객체 map 생성. key-value 구조(Java의 딕셔너리 격) - private Map articles = new HashMap<>(); - private int nextId = 1; - - static class Article { - public int id; - public String title; - public String content; - - public Article() {} // JSON 파싱용 기본 생성자 - - // article은 id(글 번호), title(글 제목), content(글 내용)으로 이루어짐 - // new 사용해서 새로 생성하지 않는 것이 순수 java와의 차이점임! - public Article(int id, String title, String content) { - this.id = id; - this.title = title; - this.content = content; - } - } - // Create (POST) - @PostMapping - public ResponseEntity
create(@RequestBody Article article) { - article.id = nextId++; - articles.put(article.id, article); - return ResponseEntity.status(HttpStatus.CREATED).body(article); - } - - // Read (GET) - @GetMapping("/{id}") - public ResponseEntity
read(@PathVariable int id) { - Article article = articles.get(id); - if (article == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - return ResponseEntity.ok(article); - } - - // Update (PUT) - @PutMapping("/{id}") - public ResponseEntity
update(@PathVariable int id, @RequestBody Article updated) { - Article old = articles.get(id); - if (old == null) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); - } - old.title = updated.title; - old.content = updated.content; - return ResponseEntity.ok(old); - } - - // Delete (DELETE) - @DeleteMapping("/{id}") - public ResponseEntity delete(@PathVariable int id) { - if (!articles.containsKey(id)) { - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Article not found"); - } - articles.remove(id); - return ResponseEntity.status(HttpStatus.NO_CONTENT).body("Deleted article " + id); - } -} diff --git a/src/main/java/com/example/bcsd/HelloController.java b/src/main/java/com/example/bcsd/HelloController.java deleted file mode 100644 index c7476b30..00000000 --- a/src/main/java/com/example/bcsd/HelloController.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.bcsd; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -@Controller -public class HelloController { - - @GetMapping("/hello") - public String hello() { - return "hello"; //templates/hello.html 을 반환 - } -} diff --git a/src/main/java/com/example/bcsd/IntroduceController.java b/src/main/java/com/example/bcsd/IntroduceController.java deleted file mode 100644 index 7aed523f..00000000 --- a/src/main/java/com/example/bcsd/IntroduceController.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.example.bcsd; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import java.util.HashMap; -import java.util.Map; - -@RestController -//@Controller -public class IntroduceController { - @GetMapping("/introduce/html") - public String introduce() { - return "introduce"; - } - - // @GetMapping은 /introduce/에 대한 HTTP GET 요청이 introduce() 메서드에 매핑되도록 합니다. - @GetMapping("/introduce/string") // 쿼리는 여기에 미포함 - public String introduce2(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) { - model.addAttribute("name", name); - return "hello " + name + "!"; - } -// <1> -// @GetMapping("/introduce/json") -// @ResponseBody -// public String introduce3(){ -// return "{\"name\":\"해인\",\"age\":24}"; -// } -// <2> 객체를 json으로 자동 반환하기 - @GetMapping("/introduce/json") - public Map introduce3() { - Map response = new HashMap<>(); - response.put("name", "윤해인"); - response.put("age", 24); - return response; - } -} diff --git a/src/main/java/com/example/bcsd/controller/HelloController.java b/src/main/java/com/example/bcsd/controller/HelloController.java new file mode 100644 index 00000000..de3558fe --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/HelloController.java @@ -0,0 +1,45 @@ +// controller는 어떤 로직을 호출할건지 요청을 받는다. +// 즉, controller -> service + +package com.example.bcsd.controller; +import com.example.bcsd.service.HelloService; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.Map; + +@Controller +@RequestMapping("/introduce") +public class HelloController { + + private final HelloService helloService; + public HelloController(HelloService helloService){ + this.helloService = helloService; + } + + // 1) /introduce/html -> introduce.html 반환 + @GetMapping("/html") + public String hello(Model model) { + return "introduce"; + } + + // 2) /introduce/string?name=이름 -> "안녕하세요. 제 이름은 000 입니다." + @GetMapping("/string") + public String introduceString(@RequestParam String name, Model model) { + model.addAttribute("name", name); + return "greeting"; + } + + // 3) /json에 json형태로 반환 + @GetMapping("/json") + @ResponseBody + // <1> Map으로 JSON 수제로 만들기 + public Map introduceJson() { + return helloService.getHelloJson(); + } + +} diff --git a/src/main/java/com/example/bcsd/repository/HelloRepository.java b/src/main/java/com/example/bcsd/repository/HelloRepository.java new file mode 100644 index 00000000..47622012 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/HelloRepository.java @@ -0,0 +1,15 @@ +// (controller->) service -> db에 필요한 자료 요청 +// only 자료구조만 저장해놓자. +package com.example.bcsd.repository; +import org.springframework.stereotype.Repository; + +@Repository +public class HelloRepository { + public String getName() { + return "윤해인"; + } + + public int getAge() { + return 24; + } +} diff --git a/src/main/java/com/example/bcsd/service/HelloService.java b/src/main/java/com/example/bcsd/service/HelloService.java new file mode 100644 index 00000000..730960aa --- /dev/null +++ b/src/main/java/com/example/bcsd/service/HelloService.java @@ -0,0 +1,32 @@ +// service는 모델. 데이터 처리, 가공 등 실질적인 >로직<을 수행함 +// 모든 머리쓰는 것들은 service에게 맡겨주세요... + +package com.example.bcsd.service; +import com.example.bcsd.repository.HelloRepository; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class HelloService { + private final HelloRepository helloRepository; + + // 생성자 주입 + public HelloService(HelloRepository helloRepository){ + this.helloRepository = helloRepository; + } + // 1) /introduce에 html 반환 + // 필요없음 + + // 2) /introduce/string?name=이름 -> "안녕하세요. 제 이름은 000 입니다." + // 필요없음 + + // 3) /introduce/json -> {"name": "...", "age": ...} + public Map getHelloJson(){ + Map output = new HashMap<>(); + output.put("name", helloRepository.getName()); + output.put("age", helloRepository.getAge()); + return output; + } +} diff --git a/src/main/resources/templates/greeting.html b/src/main/resources/templates/greeting.html new file mode 100644 index 00000000..372bd551 --- /dev/null +++ b/src/main/resources/templates/greeting.html @@ -0,0 +1,6 @@ + + + +

+ + From bba018ea9ba2b295c7abad9cd3d131eb7b47331c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 11:08:02 +0900 Subject: [PATCH 09/72] =?UTF-8?q?refactor:=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/HelloController.java | 18 ++++++++++++------ .../java/com/example/bcsd/dto/HelloDTO.java | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/example/bcsd/dto/HelloDTO.java diff --git a/src/main/java/com/example/bcsd/controller/HelloController.java b/src/main/java/com/example/bcsd/controller/HelloController.java index de3558fe..2cacb7ac 100644 --- a/src/main/java/com/example/bcsd/controller/HelloController.java +++ b/src/main/java/com/example/bcsd/controller/HelloController.java @@ -1,7 +1,8 @@ // controller는 어떤 로직을 호출할건지 요청을 받는다. // 즉, controller -> service - package com.example.bcsd.controller; + +import com.example.bcsd.dto.HelloDTO; import com.example.bcsd.service.HelloService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; @@ -10,7 +11,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; -import java.util.Map; @Controller @RequestMapping("/introduce") @@ -37,9 +37,15 @@ public String introduceString(@RequestParam String name, Model model) { // 3) /json에 json형태로 반환 @GetMapping("/json") @ResponseBody - // <1> Map으로 JSON 수제로 만들기 - public Map introduceJson() { - return helloService.getHelloJson(); + // <1> Map으로 JSON 수제로 만들기 -- 권장되는 방법이 아님 +// public Map introduceJson() { +// return helloService.getHelloJson(); +// } + // <2> 객체를 통해 JSON 자동 반환하기★ + public HelloDTO getJson(){ + HelloDTO hello = new HelloDTO(); + hello.setAge(24); + hello.setName("윤해인"); + return hello; } - } diff --git a/src/main/java/com/example/bcsd/dto/HelloDTO.java b/src/main/java/com/example/bcsd/dto/HelloDTO.java new file mode 100644 index 00000000..7630a9c1 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/HelloDTO.java @@ -0,0 +1,19 @@ +package com.example.bcsd.dto; + +public class HelloDTO { + private int age; + private String name; + + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } +} From 685259a7388f3aa8bb0917b44b95c3e461fb2e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 11:49:54 +0900 Subject: [PATCH 10/72] =?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=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/controller/HelloController.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/HelloController.java b/src/main/java/com/example/bcsd/controller/HelloController.java index 2cacb7ac..98318b16 100644 --- a/src/main/java/com/example/bcsd/controller/HelloController.java +++ b/src/main/java/com/example/bcsd/controller/HelloController.java @@ -3,7 +3,6 @@ package com.example.bcsd.controller; import com.example.bcsd.dto.HelloDTO; -import com.example.bcsd.service.HelloService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -16,11 +15,6 @@ @RequestMapping("/introduce") public class HelloController { - private final HelloService helloService; - public HelloController(HelloService helloService){ - this.helloService = helloService; - } - // 1) /introduce/html -> introduce.html 반환 @GetMapping("/html") public String hello(Model model) { From 973e14186facb4665ea7b4b5600bd13ffed1ccd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 12:21:14 +0900 Subject: [PATCH 11/72] =?UTF-8?q?feat:=20Member=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=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 --- .../java/com/example/bcsd/domain/Member.java | 22 +++++++++++ .../bcsd/repository/MemberRepository.java | 12 ++++++ .../repository/MemoryMemberRepository.java | 37 +++++++++++++++++++ 3 files changed, 71 insertions(+) create mode 100644 src/main/java/com/example/bcsd/domain/Member.java create mode 100644 src/main/java/com/example/bcsd/repository/MemberRepository.java create mode 100644 src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java new file mode 100644 index 00000000..9fce6596 --- /dev/null +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -0,0 +1,22 @@ +package com.example.bcsd.domain; + +public class Member { + private Long id; + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java new file mode 100644 index 00000000..c5ce2efe --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -0,0 +1,12 @@ +package com.example.bcsd.repository; +import com.example.bcsd.domain.Member; + +import java.util.List; +import java.util.Optional; + +public interface MemberRepository { + Member save(Member member); + Optional findById(Long id); //ID로 회원 정보 가져오기 + Optional findByName(String name); // 이름으로 회원 정보 가져오기 + List findAll(); // 모든 회원 정보 가져오기 +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java new file mode 100644 index 00000000..1bf0c716 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -0,0 +1,37 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Member; + +import java.util.*; + +public class MemoryMemberRepository implements MemberRepository { + + // 실제 저장되는 곳 + private static Map store = new HashMap<>(); + private static long sequence = 0L; // key값 생성 + + @Override + public Member save(Member member) { + member.setId(++sequence); // id값 설정 + store.put(member.getId(), member); //id값+member 합치기 + return member; + } + + @Override + public Optional findById(Long id) { + // return store.get(id); // 없으면 null이 반환되기 때문에... + return Optional.ofNullable(store.get(id)); // Optional.ofNullable로 감싸면 클라이언트에서 대처 가능 + } + + @Override + public Optional findByName(String name) { + return store.values().stream() + .filter(member -> member.getName().equals(name)) // 두 값이 같은 경우에만 필터링 됨 + .findAny(); + } + + @Override + public List findAll() { + return new ArrayList<>(store.values()); // values가 member들임! + } +} From 832dabe14c4897d4f2fb1904994be3a8b70374a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 12:41:35 +0900 Subject: [PATCH 12/72] =?UTF-8?q?feat:=20MemberService.java=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MemoryMemberRepository.java | 1 - .../example/bcsd/service/MemberService.java | 57 +++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/bcsd/service/MemberService.java diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index 1bf0c716..a73d4537 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -1,7 +1,6 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Member; - import java.util.*; public class MemoryMemberRepository implements MemberRepository { diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java new file mode 100644 index 00000000..c6eb055b --- /dev/null +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -0,0 +1,57 @@ +// 모든 비즈니스 로직들을 작성한다. +package com.example.bcsd.service; + +import com.example.bcsd.domain.Member; +import com.example.bcsd.repository.MemberRepository; + +import java.util.List; +import java.util.Optional; + +public class MemberService { + // 우선 회원 리포지토리를 가져오자. + private final MemberRepository memberRepository; + + public MemberService(MemberRepository memberRepository) { + this.memberRepository = memberRepository; + } + + // 회원 가입 + public Long join(Member member){ + // 신규 회원 정보 저장 + // 만약 동명이인이 있다면, 불가능하다. +// // [1] 정직한 버전 +// Optional result = memberRepository.findByName(member.getName()); +// // 만약 값이 이미 존재한다면: 예외처리 +// result.ifPresent(m -> { +// throw new IllegalStateException("이미 존재하는 회원입니다"); +// }); + + // [2] 축약 버전 +// memberRepository.findByName(member.getName()); +// .ifPresent(m -> { +// throw new IllegalStateException("이미 존재하는 회원입니다"); +// }); + + // [3] 메서드로 추출한 버전 (길어져서) + validateDuplicateMember(member); + memberRepository.save(member); + return member.getId(); + } + + private void validateDuplicateMember(Member member) { + memberRepository.findByName(member.getName()) + .ifPresent(m -> { + throw new IllegalStateException("이미 존재하는 회원입니다"); + }); + } + + // 전체 회원 조회 + public List findMembers(){ + return memberRepository.findAll(); + } + + // id로 고객 찾기 + public Optional findOne(Long id){ + return memberRepository.findById(id); + } +} From 0e4a15fc8c81ea59af6298489d868cf4241e406e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 13:37:16 +0900 Subject: [PATCH 13/72] =?UTF-8?q?test:=20MemoryMemberRepositoryTest=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/repository/MemoryMemberRepository.java | 4 ++++ .../example/bcsd/repository/MemoryMemberRepositoryTest.java | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index a73d4537..f73ea33d 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -33,4 +33,8 @@ public Optional findByName(String name) { public List findAll() { return new ArrayList<>(store.values()); // values가 member들임! } + + public void clearStore(){ + store.clear(); // 초기화 + } } diff --git a/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java new file mode 100644 index 00000000..718346c1 --- /dev/null +++ b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java @@ -0,0 +1,4 @@ +package com.example.bcsd.repository; + +public class MemoryMemberRepositoryTest { +} From dd15a174e3babdbadecb29e8d174d899a3a8c3d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 19:40:38 +0900 Subject: [PATCH 14/72] =?UTF-8?q?fix:=20Member=20=ED=95=84=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/MemberController.java | 20 +++++++++++++++++++ .../java/com/example/bcsd/domain/Article.java | 4 ++++ .../java/com/example/bcsd/domain/Member.java | 3 +++ .../repository/MemoryMemberRepository.java | 3 +++ .../example/bcsd/service/MemberService.java | 4 ++++ 5 files changed, 34 insertions(+) create mode 100644 src/main/java/com/example/bcsd/controller/MemberController.java create mode 100644 src/main/java/com/example/bcsd/domain/Article.java diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java new file mode 100644 index 00000000..f3f80b52 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -0,0 +1,20 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.service.MemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; + +@Controller +public class MemberController { + + // private final MemberService memberService = new MemberService(); + // 이렇게 굳이 여러 개 생성할 필요 없음. + // 스프링 컨테이너에 bean으로 등록하면 한 번만 생성해도 된다. + + private final MemberService memberService; + + @Autowired + public MemberController(MemberService memberService) { + this.memberService = memberService; + } +} diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java new file mode 100644 index 00000000..6eac6e99 --- /dev/null +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -0,0 +1,4 @@ +package com.example.bcsd.domain; + +public class Article { +} diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 9fce6596..27c089db 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -3,6 +3,9 @@ public class Member { private Long id; private String name; + private String email; + private String password; + public String getName() { return name; diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index f73ea33d..200fa817 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -1,8 +1,11 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Member; +import org.springframework.stereotype.Repository; + import java.util.*; +@Repository public class MemoryMemberRepository implements MemberRepository { // 실제 저장되는 곳 diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index c6eb055b..c718ab82 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -3,14 +3,18 @@ import com.example.bcsd.domain.Member; import com.example.bcsd.repository.MemberRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; import java.util.List; import java.util.Optional; +@Service public class MemberService { // 우선 회원 리포지토리를 가져오자. private final MemberRepository memberRepository; + @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! public MemberService(MemberRepository memberRepository) { this.memberRepository = memberRepository; } From 6fcc41a8e17b0c976ceae78959ec177e46176c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 19:42:45 +0900 Subject: [PATCH 15/72] =?UTF-8?q?feat:=20Article=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/domain/Article.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index 6eac6e99..5f0c60cd 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -1,4 +1,15 @@ package com.example.bcsd.domain; +import java.time.LocalDateTime; + public class Article { + private long id; + private long authorId; + private long boardId; + private String title; + private String content; + private LocalDateTime updatedAt; + private LocalDateTime createdAt; + + public Article(){} } From 51378919ac768894776a00ad3a120d663f8328c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 19:43:32 +0900 Subject: [PATCH 16/72] =?UTF-8?q?feat:=20board=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/domain/Board.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/com/example/bcsd/domain/Board.java diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java new file mode 100644 index 00000000..d9f7f6c6 --- /dev/null +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -0,0 +1,6 @@ +package com.example.bcsd.domain; + +public class Board { + private long id; + private String title; // 게시판 이름 +} From e99147c71d0e786735496e7f900737b5adac09e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 20:59:02 +0900 Subject: [PATCH 17/72] =?UTF-8?q?feat:=20CRUD=20API=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 44 +++++++++++++++ .../java/com/example/bcsd/domain/Article.java | 56 +++++++++++++++++++ .../bcsd/repository/ArticleRepository.java | 17 ++++++ .../repository/MemoryArticleRepository.java | 36 ++++++++++++ .../example/bcsd/service/ArticleService.java | 35 ++++++++++++ 5 files changed, 188 insertions(+) create mode 100644 src/main/java/com/example/bcsd/controller/ArticleApiController.java create mode 100644 src/main/java/com/example/bcsd/repository/ArticleRepository.java create mode 100644 src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java create mode 100644 src/main/java/com/example/bcsd/service/ArticleService.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java new file mode 100644 index 00000000..caf18f38 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -0,0 +1,44 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.domain.Article; +import com.example.bcsd.service.ArticleService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/articles") +public class ArticleApiController { + private final ArticleService articleService; + + public ArticleApiController(ArticleService articleService) { + this.articleService = articleService; + } + + // 1. GET /articles/{id} : 아이디로 article 찾기 + @GetMapping("/{id}") + public Article getOne(@PathVariable Long id){ + return articleService.getOne(id); + } + + // 2. GET /articles : 모든 article 조회하기 + @GetMapping + public List

getAll(){ + return articleService.getAll(); + } + // 3. POST /articles : 게시글 저장하기 + @PostMapping("/{id}") + public Article create(@RequestBody Article article){ // ?? + return articleService.create(article); + } + // 4. PUT : 게시글 수정하기 + @PutMapping("/{id}") + public Article update(Article article){ + return articleService.update(article); + } + // 5. DELETE /articles/{id} : id로 삭제하기 + @DeleteMapping("/{id}") + public void delete(@PathVariable Long id){ + articleService.delete(id); + } +} diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index 5f0c60cd..b9cd1a04 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -12,4 +12,60 @@ public class Article { private LocalDateTime createdAt; public Article(){} + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public long getAuthorId() { + return authorId; + } + + public void setAuthorId(long authorId) { + this.authorId = authorId; + } + + public long getBoardId() { + return boardId; + } + + public void setBoardId(long boardId) { + this.boardId = boardId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public LocalDateTime getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(LocalDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + public LocalDateTime getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(LocalDateTime createdAt) { + this.createdAt = createdAt; + } } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java new file mode 100644 index 00000000..998a9b87 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -0,0 +1,17 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Article; + +import java.util.List; +import java.util.Optional; + +public interface ArticleRepository { + // 1. GET(조회) + Optional
findById(Long id); //ID로 회원 정보 가져오기 + List
findAll(); + // 2. POST(등록) + 3. PUT(수정) + Article save(Article article); + + // 4. DELETE(삭제) + void deleteById(Long id); +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java new file mode 100644 index 00000000..13bff428 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -0,0 +1,36 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Article; +import org.springframework.stereotype.Repository; + +import java.util.*; + +@Repository +public class MemoryArticleRepository implements ArticleRepository { + // 실제 구현부 + private static final Map articles = new HashMap<>(); + private static long sequence = 0L; + + // 1. GET(조회) + @Override + public Optional
findById(Long id){ //ID로 회원 정보 가져오기 + return Optional.ofNullable(articles.get(id)); + } + // 1-1. GET(모든 ARTICLE 조회) + public List
findAll(){ + return new ArrayList<>(articles.values()); + } + + // 2. POST(등록) + 3. PUT(수정) + @Override + public Article save(Article article){ + article.setId(++sequence); // id값 설정 + articles.put(article.getId(), article); //id값+member 합치기 + return article; + } + + // 4. DELETE(삭제) + public void deleteById(Long id){ + articles.remove(id); + } +} diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java new file mode 100644 index 00000000..21f14937 --- /dev/null +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -0,0 +1,35 @@ +package com.example.bcsd.service; + +import com.example.bcsd.domain.Article; +import com.example.bcsd.repository.MemoryArticleRepository; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ArticleService { + private MemoryArticleRepository articleRepository; + + // 1. CREATE + public Article create(Article article){ + // ★★★★★ sequence 할당해주기x repo에 함수 다 만들어뒀으니 갖다 쓰기만 하면됨!!!! + return articleRepository.save(article); + } + // 2. READ - 전체 article + public List
getAll(){ + return articleRepository.findAll(); + } + // 2. READ - 하나만 + public Article getOne(Long id){ + return articleRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("article not found: " + id)); + } + // 3. UPDATE + public Article update(Article article){ + return articleRepository.save(article); + } + // 4. DELETE + public void delete(Long id){ + articleRepository.deleteById(id); + } +} From 267f3491a5d3d7fb9bdae286d08569768d92b27c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 21:28:01 +0900 Subject: [PATCH 18/72] =?UTF-8?q?feat:=20CRUD=20API=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EC=84=B1=EA=B3=B5(/posts=20=EC=A0=9C?= =?UTF-8?q?=EC=99=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/BcsdApplication.java | 1 + .../java/com/example/bcsd/DataLoader.java | 44 +++++++++++++++++++ .../bcsd/controller/ArticleApiController.java | 1 + .../java/com/example/bcsd/domain/Article.java | 10 ++--- .../java/com/example/bcsd/domain/Board.java | 8 ++++ .../example/bcsd/service/ArticleService.java | 5 ++- 6 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/example/bcsd/DataLoader.java diff --git a/src/main/java/com/example/bcsd/BcsdApplication.java b/src/main/java/com/example/bcsd/BcsdApplication.java index 6e3ecb1b..922f0db4 100644 --- a/src/main/java/com/example/bcsd/BcsdApplication.java +++ b/src/main/java/com/example/bcsd/BcsdApplication.java @@ -1,5 +1,6 @@ package com.example.bcsd; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/com/example/bcsd/DataLoader.java b/src/main/java/com/example/bcsd/DataLoader.java new file mode 100644 index 00000000..2730eab8 --- /dev/null +++ b/src/main/java/com/example/bcsd/DataLoader.java @@ -0,0 +1,44 @@ +package com.example.bcsd; + +import com.example.bcsd.domain.Article; +import com.example.bcsd.repository.ArticleRepository; +import jakarta.annotation.PostConstruct; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +@Component +public class DataLoader { + + private final ArticleRepository articleRepository; + + public DataLoader(ArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } + + @PostConstruct + public void init() { + Article sample1 = new Article(); + + sample1.setTitle("제목1"); + sample1.setAuthor("회원1"); + sample1.setCreatedAt(LocalDateTime.now()); + sample1.setContent(""); + articleRepository.save(sample1); + + Article sample2 = new Article(); + sample2.setTitle("제목22"); + sample2.setAuthor("회원1"); + sample2.setCreatedAt(LocalDateTime.now()); + sample2.setContent("내용입니다~~~~~"); + articleRepository.save(sample2); + + Article sample3 = new Article(); + sample3.setTitle("제목333"); + sample3.setAuthor("회원333333"); + sample3.setCreatedAt(LocalDateTime.now()); + sample3.setContent("내용3입니다~!!!!!~~~~"); + + articleRepository.save(sample3); + } +} diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index caf18f38..74687946 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -41,4 +41,5 @@ public Article update(Article article){ public void delete(@PathVariable Long id){ articleService.delete(id); } + } diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index b9cd1a04..f2390725 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -4,7 +4,7 @@ public class Article { private long id; - private long authorId; + private String author; private long boardId; private String title; private String content; @@ -21,12 +21,12 @@ public void setId(long id) { this.id = id; } - public long getAuthorId() { - return authorId; + public String getAuthorId() { + return author; } - public void setAuthorId(long authorId) { - this.authorId = authorId; + public void setAuthor(String author) { + this.author = author; } public long getBoardId() { diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index d9f7f6c6..c0fd12a7 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -3,4 +3,12 @@ public class Board { private long id; private String title; // 게시판 이름 + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 21f14937..53350df9 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -8,8 +8,11 @@ @Service public class ArticleService { - private MemoryArticleRepository articleRepository; + private final MemoryArticleRepository articleRepository; + public ArticleService(MemoryArticleRepository articleRepository) { + this.articleRepository = articleRepository; + } // 1. CREATE public Article create(Article article){ // ★★★★★ sequence 할당해주기x repo에 함수 다 만들어뒀으니 갖다 쓰기만 하면됨!!!! From 8fc22c33e962c1b3bd956d81420557939fc9c303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 24 Nov 2025 21:46:07 +0900 Subject: [PATCH 19/72] =?UTF-8?q?feat:=20CRUD=20API=20=EB=B6=88=EB=9F=AC?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EC=84=B1=EA=B3=B5(=EC=A0=84=EB=B6=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/DataLoader.java | 1 - .../bcsd/controller/PostController.java | 22 +++++++++++++++++++ src/main/resources/templates/posts.html | 19 ++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/bcsd/controller/PostController.java create mode 100644 src/main/resources/templates/posts.html diff --git a/src/main/java/com/example/bcsd/DataLoader.java b/src/main/java/com/example/bcsd/DataLoader.java index 2730eab8..14fa58e8 100644 --- a/src/main/java/com/example/bcsd/DataLoader.java +++ b/src/main/java/com/example/bcsd/DataLoader.java @@ -38,7 +38,6 @@ public void init() { sample3.setAuthor("회원333333"); sample3.setCreatedAt(LocalDateTime.now()); sample3.setContent("내용3입니다~!!!!!~~~~"); - articleRepository.save(sample3); } } diff --git a/src/main/java/com/example/bcsd/controller/PostController.java b/src/main/java/com/example/bcsd/controller/PostController.java new file mode 100644 index 00000000..d9e913fe --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/PostController.java @@ -0,0 +1,22 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.service.ArticleService; +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("/posts") +public class PostController { + private final ArticleService articleService; + public PostController(ArticleService articleService) { + this.articleService = articleService; + } + @GetMapping + public String posts(Model model) { + model.addAttribute("boardName", "자유게시판"); + model.addAttribute("articles", articleService.getAll()); + return "posts"; + } +} diff --git a/src/main/resources/templates/posts.html b/src/main/resources/templates/posts.html new file mode 100644 index 00000000..4cf8cc2e --- /dev/null +++ b/src/main/resources/templates/posts.html @@ -0,0 +1,19 @@ + + + + + 게시판 + + +

게시판 이름

+
+

제목

+

+ 작성자 + | + 날짜 +

+

내용

+ + + From 39592fbefaaf451052fd7d409ad675bc3adeb05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 25 Nov 2025 16:46:46 +0900 Subject: [PATCH 20/72] =?UTF-8?q?feat:=20Jdbc=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80,=20MySQL=20=EC=A0=91=EA=B7=BC?= =?UTF-8?q?=EC=9D=84=20=EC=9C=84=ED=95=9C=20.yml=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 ++- .../com/example/bcsd/BcsdApplication.java | 4 +- .../controller/TestConnectionController.java | 20 +++++++ .../MemoryMemberRepositoryTest.java | 54 +++++++++++++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/example/bcsd/controller/TestConnectionController.java diff --git a/build.gradle b/build.gradle index db3ebcf1..0f03a25c 100644 --- a/build.gradle +++ b/build.gradle @@ -18,9 +18,12 @@ repositories { } dependencies { - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + implementation 'com.mysql:mysql-connector-j' + + testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } diff --git a/src/main/java/com/example/bcsd/BcsdApplication.java b/src/main/java/com/example/bcsd/BcsdApplication.java index 922f0db4..4c345470 100644 --- a/src/main/java/com/example/bcsd/BcsdApplication.java +++ b/src/main/java/com/example/bcsd/BcsdApplication.java @@ -1,6 +1,5 @@ package com.example.bcsd; - import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -8,7 +7,8 @@ public class BcsdApplication { public static void main(String[] args) { - SpringApplication.run(BcsdApplication.class, args); + + SpringApplication.run(BcsdApplication.class, args); } } diff --git a/src/main/java/com/example/bcsd/controller/TestConnectionController.java b/src/main/java/com/example/bcsd/controller/TestConnectionController.java new file mode 100644 index 00000000..adeef081 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/TestConnectionController.java @@ -0,0 +1,20 @@ +package com.example.bcsd.controller; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class TestConnectionController { + + private final JdbcTemplate jdbcTemplate; + + public TestConnectionController(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @GetMapping("/test-db") + public String testDb() { + Integer result = jdbcTemplate.queryForObject("SELECT 1", Integer.class); + return "DB 연결 성공: " + result; + } +} diff --git a/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java index 718346c1..f82e15a0 100644 --- a/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java +++ b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java @@ -1,4 +1,58 @@ package com.example.bcsd.repository; +import com.example.bcsd.domain.Member; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Optional; +import static org.assertj.core.api.Assertions.*; + public class MemoryMemberRepositoryTest { + MemoryMemberRepository repository = new MemoryMemberRepository(); + @AfterEach + public void afterEach() { + repository.clearStore(); + } + // save 테스트 + @Test + public void save(){ + Member member = new Member(); + member.setName("spring"); + + repository.save(member); // 저장 + + Member result = repository.findById(member.getId()).get(); // id가져오는지 보기 + // 같은 의미 + // Assertions.assertEquals(member, result); + assertThat(member).isEqualTo(result); + } + + @Test + public void findByName(){ + Member member1 = new Member(); + member1.setName("spring1"); + repository.save(member1); + + Member member2 = new Member(); + member2.setName("spring2"); + repository.save(member2); + + Member result = repository.findByName("spring1").get(); + assertThat(result).isEqualTo(member1); + } + @Test + public void findAll(){ + Member member1 = new Member(); + member1.setName("spring1"); + repository.save(member1); + + Member member2 = new Member(); + member2.setName("spring2"); + repository.save(member2); + + List result = repository.findAll(); + assertThat(result.size()).isEqualTo(2); + } } From 3102c7e9e46692a30e53db573c110cf54dd18050 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 25 Nov 2025 18:51:26 +0900 Subject: [PATCH 21/72] =?UTF-8?q?feat:=20CRUD=20-=20GET=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=ED=95=B4=EC=95=BC=ED=95=98=EB=8A=94=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=20=EC=A3=BC=EC=84=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/DataLoader.java | 1 + .../bcsd/repository/ArticleRepository.java | 10 ++++++- .../repository/MemoryArticleRepository.java | 30 ++++++++++++++----- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/bcsd/DataLoader.java b/src/main/java/com/example/bcsd/DataLoader.java index 14fa58e8..1139b493 100644 --- a/src/main/java/com/example/bcsd/DataLoader.java +++ b/src/main/java/com/example/bcsd/DataLoader.java @@ -18,6 +18,7 @@ public DataLoader(ArticleRepository articleRepository) { @PostConstruct public void init() { + Article sample1 = new Article(); sample1.setTitle("제목1"); diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index 998a9b87..f0a5e782 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -7,8 +7,16 @@ public interface ArticleRepository { // 1. GET(조회) + // a. boardId로 html 뷰 반환 + // /posts?boardId={boardId} + + // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 + // /articles?boardId={boardId} + + // c. article의 id로 해당 article 하나 조회 + Optional
findById(Long id); //ID로 회원 정보 가져오기 - List
findAll(); + // List
findAll(); -> findByBoardID로 변경 예정 // 2. POST(등록) + 3. PUT(수정) Article save(Article article); diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 13bff428..8e9dd6d1 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -1,26 +1,42 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Article; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.*; @Repository public class MemoryArticleRepository implements ArticleRepository { - // 실제 구현부 - private static final Map articles = new HashMap<>(); + // db 연결 + private final JdbcTemplate jdbctemplate; // jdbc 정의 + public MemoryArticleRepository(JdbcTemplate jdbctemplate) { + this.jdbctemplate = jdbctemplate; + } + private static long sequence = 0L; // 1. GET(조회) + // a. boardId로 html 뷰 반환 + // /posts?boardId={boardId} + + + // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 + // /articles?boardId={boardId} + // findByBoardId(); + + // c. article의 id로 해당 article 하나 조회 @Override public Optional
findById(Long id){ //ID로 회원 정보 가져오기 - return Optional.ofNullable(articles.get(id)); - } - // 1-1. GET(모든 ARTICLE 조회) - public List
findAll(){ - return new ArrayList<>(articles.values()); + String sql = "select * from article where id = ?"; + return jdbctemplate.query(sql, new ArticleRowMapper(), id); } +// // 1-1. GET(모든 ARTICLE 조회) +// public List
findAll(){ +// return new ArrayList<>(articles.values()); +// } + // 2. POST(등록) + 3. PUT(수정) @Override public Article save(Article article){ From bc42497a38744f191f4dba09071e5ca578c48e53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 25 Nov 2025 21:08:24 +0900 Subject: [PATCH 22/72] =?UTF-8?q?feat:=20ArticleRowMapper=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/DataLoader.java | 6 ++-- .../java/com/example/bcsd/domain/Article.java | 10 +++---- .../bcsd/repository/ArticleRepository.java | 4 +-- .../bcsd/repository/ArticleRowMapper.java | 29 +++++++++++++++++++ .../repository/MemoryArticleRepository.java | 18 ++++-------- 5 files changed, 45 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/example/bcsd/repository/ArticleRowMapper.java diff --git a/src/main/java/com/example/bcsd/DataLoader.java b/src/main/java/com/example/bcsd/DataLoader.java index 1139b493..96781ca0 100644 --- a/src/main/java/com/example/bcsd/DataLoader.java +++ b/src/main/java/com/example/bcsd/DataLoader.java @@ -22,21 +22,21 @@ public void init() { Article sample1 = new Article(); sample1.setTitle("제목1"); - sample1.setAuthor("회원1"); + sample1.setAuthorId("회원1"); sample1.setCreatedAt(LocalDateTime.now()); sample1.setContent(""); articleRepository.save(sample1); Article sample2 = new Article(); sample2.setTitle("제목22"); - sample2.setAuthor("회원1"); + sample2.setAuthorId("회원1"); sample2.setCreatedAt(LocalDateTime.now()); sample2.setContent("내용입니다~~~~~"); articleRepository.save(sample2); Article sample3 = new Article(); sample3.setTitle("제목333"); - sample3.setAuthor("회원333333"); + sample3.setAuthorId("회원333333"); sample3.setCreatedAt(LocalDateTime.now()); sample3.setContent("내용3입니다~!!!!!~~~~"); articleRepository.save(sample3); diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index f2390725..b9cd1a04 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -4,7 +4,7 @@ public class Article { private long id; - private String author; + private long authorId; private long boardId; private String title; private String content; @@ -21,12 +21,12 @@ public void setId(long id) { this.id = id; } - public String getAuthorId() { - return author; + public long getAuthorId() { + return authorId; } - public void setAuthor(String author) { - this.author = author; + public void setAuthorId(long authorId) { + this.authorId = authorId; } public long getBoardId() { diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index f0a5e782..b84127d9 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -12,11 +12,11 @@ public interface ArticleRepository { // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} + Article findByBoardId(Long id); // c. article의 id로 해당 article 하나 조회 - Optional
findById(Long id); //ID로 회원 정보 가져오기 - // List
findAll(); -> findByBoardID로 변경 예정 + // 2. POST(등록) + 3. PUT(수정) Article save(Article article); diff --git a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java new file mode 100644 index 00000000..555cfe9e --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java @@ -0,0 +1,29 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Article; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +//public interface RowMapper { +// T mapRow(ResultSet rs, int rowNum) throws SQLException; +//} +public class ArticleRowMapper implements RowMapper
{ + + @Override + public Article mapRow(ResultSet rs, int rowNum) throws SQLException { + Article article = new Article(); + + // setter + article.setId(rs.getLong("id")); + article.setAuthorId(rs.getLong("author")); + + article.setTitle(rs.getString("title")); + article.setContent(rs.getString("content")); + + article.setCreatedAt(rs.getTimestamp("created_date").toLocalDateTime()); + article.setUpdatedAt(rs.getTimestamp("updated_date").toLocalDateTime()); + return article; + } +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 8e9dd6d1..4f2d2a0d 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -14,29 +14,23 @@ public MemoryArticleRepository(JdbcTemplate jdbctemplate) { this.jdbctemplate = jdbctemplate; } - private static long sequence = 0L; - // 1. GET(조회) - // a. boardId로 html 뷰 반환 - // /posts?boardId={boardId} - - + // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} - // findByBoardId(); + public Article findByBoardId(Long id){ + String sql = "select * from articles where board_id = ?"; + return jdbctemplate.queryForObject(sql, new ArticleRowMapper(), ) + }; // c. article의 id로 해당 article 하나 조회 + // /articles/{id} @Override public Optional
findById(Long id){ //ID로 회원 정보 가져오기 String sql = "select * from article where id = ?"; return jdbctemplate.query(sql, new ArticleRowMapper(), id); } -// // 1-1. GET(모든 ARTICLE 조회) -// public List
findAll(){ -// return new ArrayList<>(articles.values()); -// } - // 2. POST(등록) + 3. PUT(수정) @Override public Article save(Article article){ From e0a827d8c53ec2f2e4d1d250d53892b00aec7329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 25 Nov 2025 21:53:57 +0900 Subject: [PATCH 23/72] =?UTF-8?q?feat:=20CRUD=20=E4=B8=AD=20GET=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=20Jdbc=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20=EC=99=84=EB=A3=8C.=20=EB=8B=A4=EB=A7=8C,=20?= =?UTF-8?q?=EC=83=98=ED=94=8C=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EC=A7=81=20=EC=97=86=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/DataLoader.java | 44 ------------------- .../bcsd/controller/ArticleApiController.java | 37 ++++++++-------- .../bcsd/controller/PostController.java | 10 +++-- .../java/com/example/bcsd/domain/Article.java | 1 + .../bcsd/repository/ArticleRepository.java | 14 +++--- .../repository/MemoryArticleRepository.java | 34 +++++++------- .../example/bcsd/service/ArticleService.java | 36 +++++++-------- 7 files changed, 68 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/DataLoader.java diff --git a/src/main/java/com/example/bcsd/DataLoader.java b/src/main/java/com/example/bcsd/DataLoader.java deleted file mode 100644 index 96781ca0..00000000 --- a/src/main/java/com/example/bcsd/DataLoader.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.example.bcsd; - -import com.example.bcsd.domain.Article; -import com.example.bcsd.repository.ArticleRepository; -import jakarta.annotation.PostConstruct; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; - -@Component -public class DataLoader { - - private final ArticleRepository articleRepository; - - public DataLoader(ArticleRepository articleRepository) { - this.articleRepository = articleRepository; - } - - @PostConstruct - public void init() { - - Article sample1 = new Article(); - - sample1.setTitle("제목1"); - sample1.setAuthorId("회원1"); - sample1.setCreatedAt(LocalDateTime.now()); - sample1.setContent(""); - articleRepository.save(sample1); - - Article sample2 = new Article(); - sample2.setTitle("제목22"); - sample2.setAuthorId("회원1"); - sample2.setCreatedAt(LocalDateTime.now()); - sample2.setContent("내용입니다~~~~~"); - articleRepository.save(sample2); - - Article sample3 = new Article(); - sample3.setTitle("제목333"); - sample3.setAuthorId("회원333333"); - sample3.setCreatedAt(LocalDateTime.now()); - sample3.setContent("내용3입니다~!!!!!~~~~"); - articleRepository.save(sample3); - } -} diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 74687946..50d6dba2 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -5,6 +5,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; +import java.util.Optional; @RestController @RequestMapping("/articles") @@ -21,25 +22,25 @@ public Article getOne(@PathVariable Long id){ return articleService.getOne(id); } - // 2. GET /articles : 모든 article 조회하기 + // 2. GET /articles?boardId={boardId} : 한 게시판의 모든 article 조회하기 @GetMapping - public List
getAll(){ - return articleService.getAll(); - } - // 3. POST /articles : 게시글 저장하기 - @PostMapping("/{id}") - public Article create(@RequestBody Article article){ // ?? - return articleService.create(article); - } - // 4. PUT : 게시글 수정하기 - @PutMapping("/{id}") - public Article update(Article article){ - return articleService.update(article); - } - // 5. DELETE /articles/{id} : id로 삭제하기 - @DeleteMapping("/{id}") - public void delete(@PathVariable Long id){ - articleService.delete(id); + public List
getAllArticlesByBoard(Long boardId){ + return articleService.getAllArticlesByBoard(boardId); } +// // 3. POST /articles : 게시글 저장하기 +// @PostMapping("/{id}") +// public Article create(@RequestBody Article article){ // ?? +// return articleService.create(article); +// } +// // 4. PUT : 게시글 수정하기 +// @PutMapping("/{id}") +// public Article update(Article article){ +// return articleService.update(article); +// } +// // 5. DELETE /articles/{id} : id로 삭제하기 +// @DeleteMapping("/{id}") +// public void delete(@PathVariable Long id){ +// articleService.delete(id); +// } } diff --git a/src/main/java/com/example/bcsd/controller/PostController.java b/src/main/java/com/example/bcsd/controller/PostController.java index d9e913fe..8204a01e 100644 --- a/src/main/java/com/example/bcsd/controller/PostController.java +++ b/src/main/java/com/example/bcsd/controller/PostController.java @@ -5,18 +5,20 @@ import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; @Controller -@RequestMapping("/posts") +@RequestMapping("/posts") // /posts?boardId={boardId} public class PostController { private final ArticleService articleService; public PostController(ArticleService articleService) { this.articleService = articleService; } + @GetMapping - public String posts(Model model) { - model.addAttribute("boardName", "자유게시판"); - model.addAttribute("articles", articleService.getAll()); + public String posts(@RequestParam Long boardId, Model model) { + model.addAttribute("boardName", boardId); + model.addAttribute("articles", articleService.getAllArticlesByBoard(boardId)); return "posts"; } } diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index b9cd1a04..778c3356 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -68,4 +68,5 @@ public LocalDateTime getCreatedAt() { public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; } + } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index b84127d9..e49fe89a 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -12,14 +12,14 @@ public interface ArticleRepository { // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} - Article findByBoardId(Long id); + List
findByBoardId(Long boardId); // c. article의 id로 해당 article 하나 조회 - Optional
findById(Long id); //ID로 회원 정보 가져오기 + Article findById(Long id); //ID로 회원 정보 가져오기 - // 2. POST(등록) + 3. PUT(수정) - Article save(Article article); - - // 4. DELETE(삭제) - void deleteById(Long id); +// // 2. POST(등록) + 3. PUT(수정) +// Article save(Article article); +// +// // 4. DELETE(삭제) +// void deleteById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 4f2d2a0d..d770f831 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -15,32 +15,32 @@ public MemoryArticleRepository(JdbcTemplate jdbctemplate) { } // 1. GET(조회) - + // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} - public Article findByBoardId(Long id){ + public List
findByBoardId(Long BoardId){ String sql = "select * from articles where board_id = ?"; - return jdbctemplate.queryForObject(sql, new ArticleRowMapper(), ) + return jdbctemplate.query(sql, new ArticleRowMapper(), BoardId); }; // c. article의 id로 해당 article 하나 조회 // /articles/{id} @Override - public Optional
findById(Long id){ //ID로 회원 정보 가져오기 + public Article findById(Long id){ //ID로 회원 정보 가져오기 String sql = "select * from article where id = ?"; - return jdbctemplate.query(sql, new ArticleRowMapper(), id); + return jdbctemplate.queryForObject(sql, new ArticleRowMapper(), id); } - // 2. POST(등록) + 3. PUT(수정) - @Override - public Article save(Article article){ - article.setId(++sequence); // id값 설정 - articles.put(article.getId(), article); //id값+member 합치기 - return article; - } - - // 4. DELETE(삭제) - public void deleteById(Long id){ - articles.remove(id); - } +// // 2. POST(등록) + 3. PUT(수정) +// @Override +// public Article save(Article article){ +// article.setId(++sequence); // id값 설정 +// articles.put(article.getId(), article); //id값+member 합치기 +// return article; +// } +// +// // 4. DELETE(삭제) +// public void deleteById(Long id){ +// articles.remove(id); +// } } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 53350df9..7d91b8e9 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -13,26 +13,26 @@ public class ArticleService { public ArticleService(MemoryArticleRepository articleRepository) { this.articleRepository = articleRepository; } - // 1. CREATE - public Article create(Article article){ - // ★★★★★ sequence 할당해주기x repo에 함수 다 만들어뒀으니 갖다 쓰기만 하면됨!!!! - return articleRepository.save(article); - } - // 2. READ - 전체 article - public List
getAll(){ - return articleRepository.findAll(); +// // 1. CREATE +// public Article create(Article article){ +// // ★★★★★ sequence 할당해주기x repo에 함수 다 만들어뒀으니 갖다 쓰기만 하면됨!!!! +// return articleRepository.save(article); +// } + // 2. READ - board의 전체 article + public List
getAllArticlesByBoard(Long boardId){ + return articleRepository.findByBoardId(boardId); } // 2. READ - 하나만 public Article getOne(Long id){ - return articleRepository.findById(id) - .orElseThrow(() -> new IllegalArgumentException("article not found: " + id)); - } - // 3. UPDATE - public Article update(Article article){ - return articleRepository.save(article); - } - // 4. DELETE - public void delete(Long id){ - articleRepository.deleteById(id); + return articleRepository.findById(id); +// .orElseThrow(() -> new IllegalArgumentException( id+"번 게시글이 없습니다.")); } +// // 3. UPDATE +// public Article update(Article article){ +// return articleRepository.save(article); +// } +// // 4. DELETE +// public void delete(Long id){ +// articleRepository.deleteById(id); +// } } From e63da7ea14ed2411acc3ad92927838cdfa2bb916 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 30 Nov 2025 21:55:16 +0900 Subject: [PATCH 24/72] =?UTF-8?q?feat:=20a.=20GET=20/posts=3FboardId=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/controller/ArticleApiController.java | 2 +- .../java/com/example/bcsd/controller/PostController.java | 4 ++-- src/main/java/com/example/bcsd/domain/Board.java | 7 +++++++ .../java/com/example/bcsd/repository/ArticleRowMapper.java | 5 +++-- .../example/bcsd/repository/MemoryArticleRepository.java | 6 +++--- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 50d6dba2..0450703d 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -16,7 +16,7 @@ public ArticleApiController(ArticleService articleService) { this.articleService = articleService; } - // 1. GET /articles/{id} : 아이디로 article 찾기 + // 3. GET /articles/{id} : 아이디로 article 찾기 @GetMapping("/{id}") public Article getOne(@PathVariable Long id){ return articleService.getOne(id); diff --git a/src/main/java/com/example/bcsd/controller/PostController.java b/src/main/java/com/example/bcsd/controller/PostController.java index 8204a01e..b7b850d2 100644 --- a/src/main/java/com/example/bcsd/controller/PostController.java +++ b/src/main/java/com/example/bcsd/controller/PostController.java @@ -16,8 +16,8 @@ public PostController(ArticleService articleService) { } @GetMapping - public String posts(@RequestParam Long boardId, Model model) { - model.addAttribute("boardName", boardId); + public String posts(@RequestParam("boardId") String boardName, Long boardId, Model model) { + model.addAttribute("boardName", boardName); model.addAttribute("articles", articleService.getAllArticlesByBoard(boardId)); return "posts"; } diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index c0fd12a7..02b6362a 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -11,4 +11,11 @@ public String getTitle() { public void setTitle(String title) { this.title = title; } + public Long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java index 555cfe9e..8f9fadd6 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java @@ -17,13 +17,14 @@ public Article mapRow(ResultSet rs, int rowNum) throws SQLException { // setter article.setId(rs.getLong("id")); - article.setAuthorId(rs.getLong("author")); + article.setAuthorId(rs.getLong("author_id")); + article.setAuthorId(rs.getLong("board_id")); article.setTitle(rs.getString("title")); article.setContent(rs.getString("content")); article.setCreatedAt(rs.getTimestamp("created_date").toLocalDateTime()); - article.setUpdatedAt(rs.getTimestamp("updated_date").toLocalDateTime()); + article.setUpdatedAt(rs.getTimestamp("modified_date").toLocalDateTime()); return article; } } diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index d770f831..ddf899d2 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -18,9 +18,9 @@ public MemoryArticleRepository(JdbcTemplate jdbctemplate) { // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} - public List
findByBoardId(Long BoardId){ - String sql = "select * from articles where board_id = ?"; - return jdbctemplate.query(sql, new ArticleRowMapper(), BoardId); + public List
findByBoardId(Long board_id){ + String sql = "select * from article where board_id = ?"; + return jdbctemplate.query(sql, new ArticleRowMapper(), board_id); }; // c. article의 id로 해당 article 하나 조회 From 04f2fb044b72f8d769d540a9861c83731e3bbdd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 30 Nov 2025 22:10:55 +0900 Subject: [PATCH 25/72] =?UTF-8?q?fix:=20a.=20GET=20/posts=3FboardId=20-?= =?UTF-8?q?=EA=B2=8C=EC=8B=9C=ED=8C=90=EC=9D=B4=EB=A6=84=EC=9D=B4=20?= =?UTF-8?q?=EB=82=98=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/PostController.java | 5 ++++- .../bcsd/repository/BoardRepository.java | 19 +++++++++++++++++++ .../example/bcsd/service/BoardService.java | 16 ++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/bcsd/repository/BoardRepository.java create mode 100644 src/main/java/com/example/bcsd/service/BoardService.java diff --git a/src/main/java/com/example/bcsd/controller/PostController.java b/src/main/java/com/example/bcsd/controller/PostController.java index b7b850d2..409e9e5c 100644 --- a/src/main/java/com/example/bcsd/controller/PostController.java +++ b/src/main/java/com/example/bcsd/controller/PostController.java @@ -1,6 +1,8 @@ package com.example.bcsd.controller; import com.example.bcsd.service.ArticleService; +import com.example.bcsd.service.BoardService; + import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -16,7 +18,8 @@ public PostController(ArticleService articleService) { } @GetMapping - public String posts(@RequestParam("boardId") String boardName, Long boardId, Model model) { + public String posts(@RequestParam("boardId") Long boardId, Model model) { + String boardName = BoardService.getBoardName(boardId); model.addAttribute("boardName", boardName); model.addAttribute("articles", articleService.getAllArticlesByBoard(boardId)); return "posts"; diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java new file mode 100644 index 00000000..2eb660bc --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -0,0 +1,19 @@ +package com.example.bcsd.repository; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +@Repository +public class BoardRepository { + + private final JdbcTemplate jdbcTemplate; + + public BoardRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public String findNameById(Long id) { + String sql = "SELECT name FROM board WHERE id = ?"; + return jdbcTemplate.queryForObject(sql, String.class, id); + } +} diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java new file mode 100644 index 00000000..628e245b --- /dev/null +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -0,0 +1,16 @@ +package com.example.bcsd.service; +import com.example.bcsd.repository.BoardRepository; +import org.springframework.stereotype.Service; + +@Service +public class BoardService { + private static BoardRepository boardRepository; + + public BoardService(BoardRepository boardRepository) { + this.boardRepository = boardRepository; + } + + public static String getBoardName(Long boardId) { + return boardRepository.findNameById(boardId); + } +} From 048b34fa30ce8edfeffc65e8937e997d4e54e39e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 15:25:03 +0900 Subject: [PATCH 26/72] =?UTF-8?q?feat:=20b.GET=20/articles=3FboardId=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/repository/MemoryArticleRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index ddf899d2..50d69da2 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -16,7 +16,7 @@ public MemoryArticleRepository(JdbcTemplate jdbctemplate) { // 1. GET(조회) - // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 + // a&b. boardId로 게시판의 게시물들을 모두 JSON 배열로 반환 // /articles?boardId={boardId} public List
findByBoardId(Long board_id){ String sql = "select * from article where board_id = ?"; From a0f0c629666ef04a5a0551c94ae7fedb1d285d19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 20:13:23 +0900 Subject: [PATCH 27/72] =?UTF-8?q?fix:=20d.=20POST=20/articles=20(long->Lon?= =?UTF-8?q?g=20=ED=83=80=EC=9E=85=20=EB=B3=80=EA=B2=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 21 +++++----- .../java/com/example/bcsd/domain/Article.java | 25 +++++++---- .../bcsd/repository/ArticleRepository.java | 13 +++--- .../repository/MemoryArticleRepository.java | 42 +++++++++++++++---- .../example/bcsd/service/ArticleService.java | 22 +++++----- 5 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 0450703d..a3794bb0 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -5,7 +5,6 @@ import org.springframework.web.bind.annotation.*; import java.util.List; -import java.util.Optional; @RestController @RequestMapping("/articles") @@ -27,16 +26,16 @@ public Article getOne(@PathVariable Long id){ public List
getAllArticlesByBoard(Long boardId){ return articleService.getAllArticlesByBoard(boardId); } -// // 3. POST /articles : 게시글 저장하기 -// @PostMapping("/{id}") -// public Article create(@RequestBody Article article){ // ?? -// return articleService.create(article); -// } -// // 4. PUT : 게시글 수정하기 -// @PutMapping("/{id}") -// public Article update(Article article){ -// return articleService.update(article); -// } + // 3. POST /articles : 게시글 저장하기 + @PostMapping + public Article create(@RequestBody Article article){ // ?? + return articleService.create(article); + } + // 4. PUT : 게시글 수정하기 + @PutMapping("/{id}") + public Article update(Article article){ + return articleService.update(article); + } // // 5. DELETE /articles/{id} : id로 삭제하기 // @DeleteMapping("/{id}") // public void delete(@PathVariable Long id){ diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index 778c3356..71b8a0c6 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -1,11 +1,18 @@ package com.example.bcsd.domain; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.time.LocalDateTime; + public class Article { - private long id; - private long authorId; - private long boardId; + private Long id; + @JsonProperty("author_id") + private Long authorId; + + @JsonProperty("board_id") + private Long boardId; + private String title; private String content; private LocalDateTime updatedAt; @@ -13,27 +20,27 @@ public class Article { public Article(){} - public long getId() { + public Long getId() { return id; } - public void setId(long id) { + public void setId(Long id) { this.id = id; } - public long getAuthorId() { + public Long getAuthorId() { return authorId; } - public void setAuthorId(long authorId) { + public void setAuthorId(Long authorId) { this.authorId = authorId; } - public long getBoardId() { + public Long getBoardId() { return boardId; } - public void setBoardId(long boardId) { + public void setBoardId(Long boardId) { this.boardId = boardId; } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index e49fe89a..dcb0f7e9 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -3,13 +3,9 @@ import com.example.bcsd.domain.Article; import java.util.List; -import java.util.Optional; public interface ArticleRepository { // 1. GET(조회) - // a. boardId로 html 뷰 반환 - // /posts?boardId={boardId} - // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 // /articles?boardId={boardId} List
findByBoardId(Long boardId); @@ -17,9 +13,12 @@ public interface ArticleRepository { // c. article의 id로 해당 article 하나 조회 Article findById(Long id); //ID로 회원 정보 가져오기 -// // 2. POST(등록) + 3. PUT(수정) -// Article save(Article article); -// + // 2. POST(등록) + Article insert(Article article); + + // 3. PUT(수정) + Article update(Article article); + // // 4. DELETE(삭제) // void deleteById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 50d69da2..b966cb5b 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -2,8 +2,11 @@ import com.example.bcsd.domain.Article; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; +import java.sql.PreparedStatement; import java.util.*; @Repository @@ -31,14 +34,37 @@ public Article findById(Long id){ //ID로 회원 정보 가져오기 return jdbctemplate.queryForObject(sql, new ArticleRowMapper(), id); } -// // 2. POST(등록) + 3. PUT(수정) -// @Override -// public Article save(Article article){ -// article.setId(++sequence); // id값 설정 -// articles.put(article.getId(), article); //id값+member 합치기 -// return article; -// } -// + // 2. POST(등록) + @Override + public Article insert(Article article){ + String sql = "INSERT INTO article(board_id, author_id, title, content)" + + "VALUES (?, ?, ?, ?)"; + + // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbctemplate.update(con-> { + PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); + ps.setLong(1, article.getBoardId()); + ps.setLong(2, article.getAuthorId()); + ps.setString(3, article.getTitle()); + ps.setString(4, article.getContent()); + return ps; + }, keyHolder); + + // 방금 insert된 row의 id 가져오기 + NULL 처리 + Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); + + // date까지 채워진 상태를 다시 조회해서 리턴해주기. + return findById(id); + } +// 3. PUT(수정) + @Override + public Article update(Article article){ + String sql = "UPDATE article SET title = ?, content = ? WHERE id = ?"; + jdbctemplate.update(sql, article.getTitle(), article.getContent(), article.getId()); + return findById(article.getId()); + } // // 4. DELETE(삭제) // public void deleteById(Long id){ // articles.remove(id); diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 7d91b8e9..b5853c20 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -13,24 +13,24 @@ public class ArticleService { public ArticleService(MemoryArticleRepository articleRepository) { this.articleRepository = articleRepository; } -// // 1. CREATE -// public Article create(Article article){ -// // ★★★★★ sequence 할당해주기x repo에 함수 다 만들어뒀으니 갖다 쓰기만 하면됨!!!! -// return articleRepository.save(article); -// } - // 2. READ - board의 전체 article + + // 1. READ - board의 전체 article public List
getAllArticlesByBoard(Long boardId){ return articleRepository.findByBoardId(boardId); } - // 2. READ - 하나만 + // 1. READ - 하나만 public Article getOne(Long id){ return articleRepository.findById(id); // .orElseThrow(() -> new IllegalArgumentException( id+"번 게시글이 없습니다.")); } -// // 3. UPDATE -// public Article update(Article article){ -// return articleRepository.save(article); -// } + // 2. CREATE + public Article create(Article article){ + return articleRepository.insert(article); + } + // 3. UPDATE + public Article update(Article article){ + return articleRepository.update(article); + } // // 4. DELETE // public void delete(Long id){ // articleRepository.deleteById(id); From 577d88cc20429d029849646124d4a2eda625ae4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 20:27:36 +0900 Subject: [PATCH 28/72] =?UTF-8?q?feat:=20e.=20PUT=20/articles/{id}=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/controller/ArticleApiController.java | 4 +++- .../com/example/bcsd/repository/MemoryArticleRepository.java | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index a3794bb0..857f44a6 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -33,7 +33,9 @@ public Article create(@RequestBody Article article){ // ?? } // 4. PUT : 게시글 수정하기 @PutMapping("/{id}") - public Article update(Article article){ + public Article update(@PathVariable Long id, + @RequestBody Article article){ + article.setId(id); // body에 id넣지 않아도 자동 세팅되도록 return articleService.update(article); } // // 5. DELETE /articles/{id} : id로 삭제하기 diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index b966cb5b..acc61d61 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -58,7 +58,7 @@ public Article insert(Article article){ // date까지 채워진 상태를 다시 조회해서 리턴해주기. return findById(id); } -// 3. PUT(수정) + // 3. PUT(수정) @Override public Article update(Article article){ String sql = "UPDATE article SET title = ?, content = ? WHERE id = ?"; From 2c39380487fba3b353725dc3397f65017cc1b56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 20:50:05 +0900 Subject: [PATCH 29/72] =?UTF-8?q?feat:=20f.=20DELETE=20/articles/{id}=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 17 +++++++++++------ .../repository/MemoryArticleRepository.java | 14 ++++++++++---- .../example/bcsd/service/ArticleService.java | 8 ++++---- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 857f44a6..229f7d06 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -2,6 +2,7 @@ import com.example.bcsd.domain.Article; import com.example.bcsd.service.ArticleService; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -38,10 +39,14 @@ public Article update(@PathVariable Long id, article.setId(id); // body에 id넣지 않아도 자동 세팅되도록 return articleService.update(article); } -// // 5. DELETE /articles/{id} : id로 삭제하기 -// @DeleteMapping("/{id}") -// public void delete(@PathVariable Long id){ -// articleService.delete(id); -// } - + // 5. DELETE /articles/{id} : id로 삭제하기 + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + boolean deleted = articleService.delete(id); + if (deleted) { + return ResponseEntity.noContent().build(); // 204 + } else { + return ResponseEntity.notFound().build(); // 404 + } + } } diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index acc61d61..333d03d0 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -65,8 +65,14 @@ public Article update(Article article){ jdbctemplate.update(sql, article.getTitle(), article.getContent(), article.getId()); return findById(article.getId()); } -// // 4. DELETE(삭제) -// public void deleteById(Long id){ -// articles.remove(id); -// } + // 4. DELETE(삭제) + public boolean deleteById(Long id){ + String sql = "DELETE FROM article WHERE id = ?"; + int rows = jdbctemplate.update(sql, id); + + if (rows == 0) { + throw new IllegalArgumentException(id + "번 게시글이 없습니다."); + } + return false; + } } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index b5853c20..ecbe255b 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -31,8 +31,8 @@ public Article create(Article article){ public Article update(Article article){ return articleRepository.update(article); } -// // 4. DELETE -// public void delete(Long id){ -// articleRepository.deleteById(id); -// } + // 4. DELETE + public boolean delete(Long id){ + return articleRepository.deleteById(id); + } } From 97372811bff07f084775a20de7c4db92fbc1e447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 22:36:40 +0900 Subject: [PATCH 30/72] =?UTF-8?q?feat:=201.=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=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 --- .../bcsd/controller/ArticleApiController.java | 20 ++++++++++--------- .../exception/GlobalExceptionHandler.java | 17 ++++++++++++++++ .../repository/MemoryArticleRepository.java | 2 +- .../example/bcsd/service/ArticleService.java | 1 - 4 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 229f7d06..7aa7fe29 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -15,11 +15,10 @@ public class ArticleApiController { public ArticleApiController(ArticleService articleService) { this.articleService = articleService; } - - // 3. GET /articles/{id} : 아이디로 article 찾기 - @GetMapping("/{id}") - public Article getOne(@PathVariable Long id){ - return articleService.getOne(id); + // 1. POST /articles : 게시글 저장하기 + @PostMapping + public Article create(@RequestBody Article article){ // ?? + return articleService.create(article); } // 2. GET /articles?boardId={boardId} : 한 게시판의 모든 article 조회하기 @@ -27,11 +26,13 @@ public Article getOne(@PathVariable Long id){ public List
getAllArticlesByBoard(Long boardId){ return articleService.getAllArticlesByBoard(boardId); } - // 3. POST /articles : 게시글 저장하기 - @PostMapping - public Article create(@RequestBody Article article){ // ?? - return articleService.create(article); + + // 3. GET /articles/{id} : 아이디로 article 찾기 + @GetMapping("/{id}") + public Article getOne(@PathVariable Long id){ + return articleService.getOne(id); } + // 4. PUT : 게시글 수정하기 @PutMapping("/{id}") public Article update(@PathVariable Long id, @@ -39,6 +40,7 @@ public Article update(@PathVariable Long id, article.setId(id); // body에 id넣지 않아도 자동 세팅되도록 return articleService.update(article); } + // 5. DELETE /articles/{id} : id로 삭제하기 @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java new file mode 100644 index 00000000..bd4a6cf5 --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -0,0 +1,17 @@ +package com.example.bcsd.exception; + +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + // 1. 조회 예외처리 - 존재하지 않는 게시물 조회 시 404 + @ExceptionHandler(EmptyResultDataAccessException.class) + public ResponseEntity handleEmptyResult(EmptyResultDataAccessException ex) { +// ex.printStackTrace(); + return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); + } +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 333d03d0..630696df 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -24,7 +24,7 @@ public MemoryArticleRepository(JdbcTemplate jdbctemplate) { public List
findByBoardId(Long board_id){ String sql = "select * from article where board_id = ?"; return jdbctemplate.query(sql, new ArticleRowMapper(), board_id); - }; + } // c. article의 id로 해당 article 하나 조회 // /articles/{id} diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index ecbe255b..1533a86e 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -21,7 +21,6 @@ public List
getAllArticlesByBoard(Long boardId){ // 1. READ - 하나만 public Article getOne(Long id){ return articleRepository.findById(id); -// .orElseThrow(() -> new IllegalArgumentException( id+"번 게시글이 없습니다.")); } // 2. CREATE public Article create(Article article){ From 1392bb5439569fb7338912c5fda96f22c52265b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 23:39:51 +0900 Subject: [PATCH 31/72] =?UTF-8?q?refactor:=20member=EB=8F=84=20jdbc?= =?UTF-8?q?=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 --- .../bcsd/controller/MemberController.java | 50 +++++++- .../java/com/example/bcsd/domain/Member.java | 16 +++ .../java/com/example/bcsd/dto/MemberDTO.java | 15 +++ .../exception/DuplicateEmailException.java | 7 ++ .../exception/GlobalExceptionHandler.java | 8 ++ .../bcsd/repository/MemberRepository.java | 11 +- .../bcsd/repository/MemberRowMapper.java | 20 +++ .../repository/MemoryMemberRepository.java | 75 ++++++++--- .../example/bcsd/service/MemberService.java | 59 ++++----- .../MemoryMemberRepositoryTest.java | 116 +++++++++--------- 10 files changed, 254 insertions(+), 123 deletions(-) create mode 100644 src/main/java/com/example/bcsd/dto/MemberDTO.java create mode 100644 src/main/java/com/example/bcsd/exception/DuplicateEmailException.java create mode 100644 src/main/java/com/example/bcsd/repository/MemberRowMapper.java diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java index f3f80b52..8e79c155 100644 --- a/src/main/java/com/example/bcsd/controller/MemberController.java +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -1,15 +1,18 @@ package com.example.bcsd.controller; +import com.example.bcsd.domain.Member; +import com.example.bcsd.dto.MemberDTO; import com.example.bcsd.service.MemberService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; -@Controller -public class MemberController { +import java.util.List; - // private final MemberService memberService = new MemberService(); - // 이렇게 굳이 여러 개 생성할 필요 없음. - // 스프링 컨테이너에 bean으로 등록하면 한 번만 생성해도 된다. +@RestController +@RequestMapping("/members") +public class MemberController { private final MemberService memberService; @@ -17,4 +20,41 @@ public class MemberController { public MemberController(MemberService memberService) { this.memberService = memberService; } + // 1. member 생성 + @PostMapping + public Member create(@RequestBody MemberDTO req) { + Member member = new Member(); + member.setName(req.getName()); + member.setEmail(req.getEmail()); + member.setPassword(req.getPassword()); + + return memberService.create(member); + } + // 2. member 정보 수정 + @PutMapping("/{id}") + public Member update(@PathVariable Long id, + @RequestBody MemberDTO req) { + return memberService.update(id, req); + } + // 3. member 삭제 + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + boolean deleted = memberService.delete(id); + if (deleted) { + return ResponseEntity.noContent().build(); // 204 + } else { + return ResponseEntity.notFound().build(); // 404 + } + } + // 4. member 조회 + // 4-1. id로 조회 + @GetMapping("/{id}") + public Member getOne(@PathVariable Long id) { + return memberService.getOne(id); + } + // 4-2. name으로 조회 + @GetMapping("/search") + public List searchByName(@RequestParam String name) { + return memberService.searchByName(name); + } } diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 27c089db..83441a3e 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -22,4 +22,20 @@ public Long getId() { public void setId(Long id) { this.id = id; } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/main/java/com/example/bcsd/dto/MemberDTO.java b/src/main/java/com/example/bcsd/dto/MemberDTO.java new file mode 100644 index 00000000..252e3af3 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/MemberDTO.java @@ -0,0 +1,15 @@ +package com.example.bcsd.dto; + +public class MemberDTO { + private String name; + private String email; + private String password; + + public String getName() { return name; } + public String getEmail() { return email; } + public String getPassword() { return password; } + + public void setName(String name) { this.name = name; } + public void setEmail(String email) { this.email = email; } + public void setPassword(String password) { this.password = password; } +} diff --git a/src/main/java/com/example/bcsd/exception/DuplicateEmailException.java b/src/main/java/com/example/bcsd/exception/DuplicateEmailException.java new file mode 100644 index 00000000..45d391be --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/DuplicateEmailException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.exception; + +public class DuplicateEmailException extends RuntimeException{ + public DuplicateEmailException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java index bd4a6cf5..67266cbe 100644 --- a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -1,6 +1,7 @@ package com.example.bcsd.exception; import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -14,4 +15,11 @@ public ResponseEntity handleEmptyResult(EmptyResultDataAccessException e // ex.printStackTrace(); return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); } + // 2. 수정 예외처리 - 1. 중복된 이메일로 수정 시도하면 409 + @ExceptionHandler(DuplicateEmailException.class) + public ResponseEntity handleDuplicateEmail(DuplicateEmailException ex) { + return ResponseEntity + .status(HttpStatus.CONFLICT) + .body(ex.getMessage()); + } } diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index c5ce2efe..37a4ed05 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -5,8 +5,11 @@ import java.util.Optional; public interface MemberRepository { - Member save(Member member); - Optional findById(Long id); //ID로 회원 정보 가져오기 - Optional findByName(String name); // 이름으로 회원 정보 가져오기 - List findAll(); // 모든 회원 정보 가져오기 + Member insert(Member member); + Member update(Member member); + Member findById(Long id); //ID로 회원 정보 가져오기 + List findByName(String name); // 이름으로 회원 정보 가져오기 + List findAll(); // 이름으로 회원 정보 가져오기 + + boolean existsByEmail(String email); } diff --git a/src/main/java/com/example/bcsd/repository/MemberRowMapper.java b/src/main/java/com/example/bcsd/repository/MemberRowMapper.java new file mode 100644 index 00000000..4511563b --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemberRowMapper.java @@ -0,0 +1,20 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Member; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class MemberRowMapper implements RowMapper { + Member member = new Member(); + public Member mapRow(ResultSet rs, int rowNum) throws SQLException { + + // setter + member.setName(rs.getString("name")); + member.setEmail(rs.getString("email")); + member.setPassword(rs.getString("password")); + + return member; +} +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index 200fa817..48ff9a63 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -1,43 +1,80 @@ package com.example.bcsd.repository; - import com.example.bcsd.domain.Member; +import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; - +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import java.sql.PreparedStatement; +import java.sql.Statement; import java.util.*; @Repository public class MemoryMemberRepository implements MemberRepository { + private final JdbcTemplate jdbctemplate; + private final MemberRowMapper rowMapper = new MemberRowMapper(); - // 실제 저장되는 곳 - private static Map store = new HashMap<>(); - private static long sequence = 0L; // key값 생성 + public MemoryMemberRepository(JdbcTemplate jdbctemplate) { + this.jdbctemplate = jdbctemplate; + } @Override - public Member save(Member member) { - member.setId(++sequence); // id값 설정 - store.put(member.getId(), member); //id값+member 합치기 - return member; + public Member insert(Member member) { + String sql = "INSERT INTO member (name, email, password)" + + "VALUES (?, ?, ?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbctemplate.update(con -> { + PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ps.setString(1, member.getName()); + ps.setString(2, member.getEmail()); + ps.setString(3, member.getPassword()); + return ps; + }, keyHolder); + + Long newId = keyHolder.getKey().longValue(); + return findById(newId); } @Override - public Optional findById(Long id) { - // return store.get(id); // 없으면 null이 반환되기 때문에... - return Optional.ofNullable(store.get(id)); // Optional.ofNullable로 감싸면 클라이언트에서 대처 가능 + public Member update(Member member) { + String sql = "UPDATE member SET name = ?, email = ? , password=? WHERE id = ?"; + jdbctemplate.update(sql, member.getName(), member.getEmail(), member.getId()); + return findById(member.getId()); } @Override - public Optional findByName(String name) { - return store.values().stream() - .filter(member -> member.getName().equals(name)) // 두 값이 같은 경우에만 필터링 됨 - .findAny(); + public Member findById(Long id) { + String sql = "SELECT * FROM member WHERE id = ?"; + return jdbctemplate.queryForObject(sql, new MemberRowMapper(), id); + } + + @Override + public List findByName(String name) { // 동명이인 발생 가능 + String sql = "SELECT * FROM member where name = ?"; + return jdbctemplate.query(sql, rowMapper, name); + } + + @Override + public boolean existsByEmail(String email) { + String sql = "SELECT COUNT(*) FROM member WHERE email = ?"; + Integer count = jdbctemplate.queryForObject(sql, Integer.class, email); + return count != null && count > 0; } @Override public List findAll() { - return new ArrayList<>(store.values()); // values가 member들임! + String sql = "SELECT * FROM member"; + return jdbctemplate.query(sql, rowMapper); } - public void clearStore(){ - store.clear(); // 초기화 + public boolean deleteById(Long id){ + String sql = "DELETE FROM article WHERE id = ?"; + int rows = jdbctemplate.update(sql, id); + + if (rows == 0) { + throw new IllegalArgumentException(id + "번 사용자가 존재하지 않습니다."); + } + return false; } + } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index c718ab82..cad23004 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -2,60 +2,45 @@ package com.example.bcsd.service; import com.example.bcsd.domain.Member; -import com.example.bcsd.repository.MemberRepository; +import com.example.bcsd.dto.MemberDTO; +import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; + @Service public class MemberService { - // 우선 회원 리포지토리를 가져오자. - private final MemberRepository memberRepository; + // 우선 회원 리포지토리를 가져오자 + private final MemoryMemberRepository memberRepository; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemberRepository memberRepository) { + public MemberService(MemoryMemberRepository memberRepository) { this.memberRepository = memberRepository; } - // 회원 가입 - public Long join(Member member){ - // 신규 회원 정보 저장 - // 만약 동명이인이 있다면, 불가능하다. -// // [1] 정직한 버전 -// Optional result = memberRepository.findByName(member.getName()); -// // 만약 값이 이미 존재한다면: 예외처리 -// result.ifPresent(m -> { -// throw new IllegalStateException("이미 존재하는 회원입니다"); -// }); - - // [2] 축약 버전 -// memberRepository.findByName(member.getName()); -// .ifPresent(m -> { -// throw new IllegalStateException("이미 존재하는 회원입니다"); -// }); - - // [3] 메서드로 추출한 버전 (길어져서) - validateDuplicateMember(member); - memberRepository.save(member); - return member.getId(); + public Member create(Member member) { + return memberRepository.insert(member); } - private void validateDuplicateMember(Member member) { - memberRepository.findByName(member.getName()) - .ifPresent(m -> { - throw new IllegalStateException("이미 존재하는 회원입니다"); - }); + public Member update(Long id, MemberDTO req) { + Member member = memberRepository.findById(id); + member.setName(req.getName()); + member.setEmail(req.getEmail()); + member.setPassword(req.getPassword()); + + return memberRepository.update(member); + } + public Member getOne(Long id) { + return memberRepository.findById(id); } - // 전체 회원 조회 - public List findMembers(){ - return memberRepository.findAll(); + public List searchByName(String name) { + return memberRepository.findByName(name); } - // id로 고객 찾기 - public Optional findOne(Long id){ - return memberRepository.findById(id); + public boolean delete(Long id) { + return memberRepository.deleteById(id); } } diff --git a/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java index f82e15a0..2dc8dfa2 100644 --- a/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java +++ b/src/test/java/com/example/bcsd/repository/MemoryMemberRepositoryTest.java @@ -1,58 +1,58 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Member; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import java.util.List; -import java.util.Optional; -import static org.assertj.core.api.Assertions.*; - -public class MemoryMemberRepositoryTest { - MemoryMemberRepository repository = new MemoryMemberRepository(); - @AfterEach - public void afterEach() { - repository.clearStore(); - } - // save 테스트 - @Test - public void save(){ - Member member = new Member(); - member.setName("spring"); - - repository.save(member); // 저장 - - Member result = repository.findById(member.getId()).get(); // id가져오는지 보기 - // 같은 의미 - // Assertions.assertEquals(member, result); - assertThat(member).isEqualTo(result); - } - - @Test - public void findByName(){ - Member member1 = new Member(); - member1.setName("spring1"); - repository.save(member1); - - Member member2 = new Member(); - member2.setName("spring2"); - repository.save(member2); - - Member result = repository.findByName("spring1").get(); - assertThat(result).isEqualTo(member1); - } - @Test - public void findAll(){ - Member member1 = new Member(); - member1.setName("spring1"); - repository.save(member1); - - Member member2 = new Member(); - member2.setName("spring2"); - repository.save(member2); - - List result = repository.findAll(); - assertThat(result.size()).isEqualTo(2); - } -} +//package com.example.bcsd.repository; +// +//import com.example.bcsd.domain.Member; +//import org.junit.jupiter.api.AfterEach; +//import org.junit.jupiter.api.Assertions; +//import org.junit.jupiter.api.Test; +// +//import java.util.List; +//import java.util.Optional; +//import static org.assertj.core.api.Assertions.*; +// +//public class MemoryMemberRepositoryTest { +// MemoryMemberRepository repository = new MemoryMemberRepository(); +// @AfterEach +// public void afterEach() { +// repository.clearStore(); +// } +// // save 테스트 +// @Test +// public void save(){ +// Member member = new Member(); +// member.setName("spring"); +// +// repository.save(member); // 저장 +// +// Member result = repository.findById(member.getId()).get(); // id가져오는지 보기 +// // 같은 의미 +// // Assertions.assertEquals(member, result); +// assertThat(member).isEqualTo(result); +// } +// +// @Test +// public void findByName(){ +// Member member1 = new Member(); +// member1.setName("spring1"); +// repository.save(member1); +// +// Member member2 = new Member(); +// member2.setName("spring2"); +// repository.save(member2); +// +// Member result = repository.findByName("spring1").get(); +// assertThat(result).isEqualTo(member1); +// } +// @Test +// public void findAll(){ +// Member member1 = new Member(); +// member1.setName("spring1"); +// repository.save(member1); +// +// Member member2 = new Member(); +// member2.setName("spring2"); +// repository.save(member2); +// +// List result = repository.findAll(); +// assertThat(result.size()).isEqualTo(2); +// } +//} From 2a2f42c13888ff9c355d8e1438db8870d52c0e65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 1 Dec 2025 23:51:19 +0900 Subject: [PATCH 32/72] =?UTF-8?q?fix:=20=EC=97=90=EB=9F=AC=20=ED=94=BD?= =?UTF-8?q?=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/bcsd/controller/MemberController.java | 12 ++++-------- .../bcsd/repository/MemoryMemberRepository.java | 2 +- .../java/com/example/bcsd/service/MemberService.java | 11 +++++------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java index 8e79c155..1db46ce4 100644 --- a/src/main/java/com/example/bcsd/controller/MemberController.java +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -5,7 +5,6 @@ import com.example.bcsd.service.MemberService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -22,19 +21,16 @@ public MemberController(MemberService memberService) { } // 1. member 생성 @PostMapping - public Member create(@RequestBody MemberDTO req) { - Member member = new Member(); - member.setName(req.getName()); - member.setEmail(req.getEmail()); - member.setPassword(req.getPassword()); + public Member create(@RequestBody Member member) { return memberService.create(member); } // 2. member 정보 수정 @PutMapping("/{id}") public Member update(@PathVariable Long id, - @RequestBody MemberDTO req) { - return memberService.update(id, req); + @RequestBody Member member) { + member.setId(id); // body에 id넣지 않아도 자동 세팅되도록 + return memberService.update(member); } // 3. member 삭제 @DeleteMapping("/{id}") diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index 48ff9a63..a4246672 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -38,7 +38,7 @@ public Member insert(Member member) { @Override public Member update(Member member) { String sql = "UPDATE member SET name = ?, email = ? , password=? WHERE id = ?"; - jdbctemplate.update(sql, member.getName(), member.getEmail(), member.getId()); + jdbctemplate.update(sql, member.getName(), member.getEmail(), member.getPassword(), member.getId()); return findById(member.getId()); } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index cad23004..371a0cf7 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -2,7 +2,6 @@ package com.example.bcsd.service; import com.example.bcsd.domain.Member; -import com.example.bcsd.dto.MemberDTO; import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,11 +23,11 @@ public Member create(Member member) { return memberRepository.insert(member); } - public Member update(Long id, MemberDTO req) { - Member member = memberRepository.findById(id); - member.setName(req.getName()); - member.setEmail(req.getEmail()); - member.setPassword(req.getPassword()); + public Member update(Member member) { +// Member member = memberRepository.findById(id); +// member.setName(req.getName()); +// member.setEmail(req.getEmail()); +// member.setPassword(req.getPassword()); return memberRepository.update(member); } From e656eceaaf86ceefdc3d2c1f4830a8fa517e07f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 00:15:26 +0900 Subject: [PATCH 33/72] =?UTF-8?q?feat:=202.=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20409=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=20=EC=A4=91=EB=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/MemberController.java | 13 ++++++++---- .../exception/GlobalExceptionHandler.java | 2 +- .../example/bcsd/service/MemberService.java | 21 ++++++++++++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java index 1db46ce4..cd055e27 100644 --- a/src/main/java/com/example/bcsd/controller/MemberController.java +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -21,17 +21,22 @@ public MemberController(MemberService memberService) { } // 1. member 생성 @PostMapping - public Member create(@RequestBody Member member) { + public Member create(@RequestBody MemberDTO req) { + Member member = new Member(); + member.setName(req.getName()); + member.setEmail(req.getEmail()); + member.setPassword(req.getPassword()); return memberService.create(member); } + // 2. member 정보 수정 @PutMapping("/{id}") public Member update(@PathVariable Long id, - @RequestBody Member member) { - member.setId(id); // body에 id넣지 않아도 자동 세팅되도록 - return memberService.update(member); + @RequestBody MemberDTO req) { + return memberService.update(req, id); } + // 3. member 삭제 @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java index 67266cbe..4a26d9dd 100644 --- a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -19,7 +19,7 @@ public ResponseEntity handleEmptyResult(EmptyResultDataAccessException e @ExceptionHandler(DuplicateEmailException.class) public ResponseEntity handleDuplicateEmail(DuplicateEmailException ex) { return ResponseEntity - .status(HttpStatus.CONFLICT) + .status(409) .body(ex.getMessage()); } } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 371a0cf7..49c94427 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -1,7 +1,8 @@ // 모든 비즈니스 로직들을 작성한다. package com.example.bcsd.service; - import com.example.bcsd.domain.Member; +import com.example.bcsd.dto.MemberDTO; +import com.example.bcsd.exception.DuplicateEmailException; import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -11,7 +12,6 @@ @Service public class MemberService { - // 우선 회원 리포지토리를 가져오자 private final MemoryMemberRepository memberRepository; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! @@ -23,14 +23,21 @@ public Member create(Member member) { return memberRepository.insert(member); } - public Member update(Member member) { -// Member member = memberRepository.findById(id); -// member.setName(req.getName()); -// member.setEmail(req.getEmail()); -// member.setPassword(req.getPassword()); + public Member update(MemberDTO req, Long id) { + Member member = memberRepository.findById(id); + + if (memberRepository.existsByEmail(req.getEmail()) + && !member.getEmail().equals(req.getEmail())) { + throw new DuplicateEmailException("이미 사용 중인 이메일입니다: " + req.getEmail()); + } + + member.setName(req.getName()); + member.setEmail(req.getEmail()); + member.setPassword(req.getPassword()); return memberRepository.update(member); } + public Member getOne(Long id) { return memberRepository.findById(id); } From 442ca102654056eccae99db42dae1dabe9956e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 00:29:40 +0900 Subject: [PATCH 34/72] =?UTF-8?q?fix=20:=20ArticleDTO=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?,=20article=EC=9D=98=20board=5Fid=EA=B0=80=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EB=9C=A8=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=9D=B4?= =?UTF-8?q?=EC=8A=88=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 7 +++-- .../java/com/example/bcsd/dto/ArticleDTO.java | 28 +++++++++++++++++++ .../bcsd/repository/ArticleRowMapper.java | 5 ++-- .../example/bcsd/service/ArticleService.java | 9 +++++- 4 files changed, 42 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/example/bcsd/dto/ArticleDTO.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 7aa7fe29..c0c02966 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -1,6 +1,8 @@ package com.example.bcsd.controller; import com.example.bcsd.domain.Article; +import com.example.bcsd.dto.ArticleDTO; + import com.example.bcsd.service.ArticleService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -36,9 +38,8 @@ public Article getOne(@PathVariable Long id){ // 4. PUT : 게시글 수정하기 @PutMapping("/{id}") public Article update(@PathVariable Long id, - @RequestBody Article article){ - article.setId(id); // body에 id넣지 않아도 자동 세팅되도록 - return articleService.update(article); + @RequestBody ArticleDTO req){ + return articleService.update(req, id); } // 5. DELETE /articles/{id} : id로 삭제하기 diff --git a/src/main/java/com/example/bcsd/dto/ArticleDTO.java b/src/main/java/com/example/bcsd/dto/ArticleDTO.java new file mode 100644 index 00000000..5d129722 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/ArticleDTO.java @@ -0,0 +1,28 @@ +package com.example.bcsd.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.time.LocalDateTime; + + +public class ArticleDTO { + private String title; + private String content; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + +} diff --git a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java index 8f9fadd6..489a9ee8 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java @@ -17,11 +17,10 @@ public Article mapRow(ResultSet rs, int rowNum) throws SQLException { // setter article.setId(rs.getLong("id")); - article.setAuthorId(rs.getLong("author_id")); - article.setAuthorId(rs.getLong("board_id")); - article.setTitle(rs.getString("title")); article.setContent(rs.getString("content")); + article.setAuthorId(rs.getLong("author_id")); + article.setBoardId(rs.getLong("board_id")); article.setCreatedAt(rs.getTimestamp("created_date").toLocalDateTime()); article.setUpdatedAt(rs.getTimestamp("modified_date").toLocalDateTime()); diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 1533a86e..81e95cb5 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -1,6 +1,8 @@ package com.example.bcsd.service; import com.example.bcsd.domain.Article; +import com.example.bcsd.dto.ArticleDTO; + import com.example.bcsd.repository.MemoryArticleRepository; import org.springframework.stereotype.Service; @@ -27,7 +29,12 @@ public Article create(Article article){ return articleRepository.insert(article); } // 3. UPDATE - public Article update(Article article){ + public Article update(ArticleDTO req, Long id){ + Article article = articleRepository.findById(id); + + article.setTitle(req.getTitle()); + article.setContent(req.getContent()); + return articleRepository.update(article); } // 4. DELETE From d8d580c6601229829bf42389f485169cdbcd5c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 02:20:27 +0900 Subject: [PATCH 35/72] =?UTF-8?q?feat:=202.=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20400=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90/=EA=B2=8C=EC=8B=9C=ED=8C=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 3 ++- .../java/com/example/bcsd/dto/ArticleDTO.java | 24 +++++++++++++++--- .../exception/GlobalExceptionHandler.java | 19 +++++++++----- .../exception/InvalidReferenceException.java | 7 ++++++ .../bcsd/repository/BoardRepository.java | 7 ++++++ .../bcsd/repository/MemberRepository.java | 2 +- .../bcsd/repository/MemberRowMapper.java | 1 + .../repository/MemoryArticleRepository.java | 9 +++++-- .../repository/MemoryMemberRepository.java | 7 ++++++ .../example/bcsd/service/ArticleService.java | 25 ++++++++++++++++++- 10 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/example/bcsd/exception/InvalidReferenceException.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index c0c02966..ccc7e0e2 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -25,7 +25,8 @@ public Article create(@RequestBody Article article){ // ?? // 2. GET /articles?boardId={boardId} : 한 게시판의 모든 article 조회하기 @GetMapping - public List
getAllArticlesByBoard(Long boardId){ + public List
getAllArticlesByBoard( + @RequestParam(required = false) Long boardId){ return articleService.getAllArticlesByBoard(boardId); } diff --git a/src/main/java/com/example/bcsd/dto/ArticleDTO.java b/src/main/java/com/example/bcsd/dto/ArticleDTO.java index 5d129722..275f201d 100644 --- a/src/main/java/com/example/bcsd/dto/ArticleDTO.java +++ b/src/main/java/com/example/bcsd/dto/ArticleDTO.java @@ -2,13 +2,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; -import java.time.LocalDateTime; - - public class ArticleDTO { private String title; private String content; + @JsonProperty("board_id") + private Long boardId; + + @JsonProperty("author_id") + private Long authorId; + // getter와 setter public String getTitle() { return title; } @@ -25,4 +28,19 @@ public void setContent(String content) { this.content = content; } + public Long getAuthorId() { + return authorId; + } + + public void setAuthorId(Long authorId) { + this.authorId = authorId; + } + + public Long getBoardId() { + return boardId; + } + + public void setBoardId(Long boardId) { + this.boardId = boardId; + } } diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java index 4a26d9dd..a66e9b7c 100644 --- a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -9,12 +9,12 @@ @RestControllerAdvice public class GlobalExceptionHandler { - // 1. 조회 예외처리 - 존재하지 않는 게시물 조회 시 404 - @ExceptionHandler(EmptyResultDataAccessException.class) - public ResponseEntity handleEmptyResult(EmptyResultDataAccessException ex) { -// ex.printStackTrace(); - return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); - } +// // 1. 조회 예외처리 - 존재하지 않는 게시물 조회 시 404 +// @ExceptionHandler(EmptyResultDataAccessException.class) +// public ResponseEntity handleEmptyResult(EmptyResultDataAccessException ex) { +//// ex.printStackTrace(); +// return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); +// } // 2. 수정 예외처리 - 1. 중복된 이메일로 수정 시도하면 409 @ExceptionHandler(DuplicateEmailException.class) public ResponseEntity handleDuplicateEmail(DuplicateEmailException ex) { @@ -22,4 +22,11 @@ public ResponseEntity handleDuplicateEmail(DuplicateEmailException ex) { .status(409) .body(ex.getMessage()); } + // 2. 수정 예외처리 - 2. 존재하지 않는 사용자 혹은 게시판을 참조하면 400 + @ExceptionHandler(InvalidReferenceException.class) + public ResponseEntity handleInvalidReference(InvalidReferenceException ex) { + return ResponseEntity + .status(400) + .body(ex.getMessage()); + } } diff --git a/src/main/java/com/example/bcsd/exception/InvalidReferenceException.java b/src/main/java/com/example/bcsd/exception/InvalidReferenceException.java new file mode 100644 index 00000000..0242c9d4 --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/InvalidReferenceException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.exception; + +public class InvalidReferenceException extends RuntimeException { + public InvalidReferenceException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java index 2eb660bc..d585a671 100644 --- a/src/main/java/com/example/bcsd/repository/BoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -16,4 +16,11 @@ public String findNameById(Long id) { String sql = "SELECT name FROM board WHERE id = ?"; return jdbcTemplate.queryForObject(sql, String.class, id); } + + public boolean existsById(Long id) { + String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; + Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id); + return count != null && count > 0; + } + } diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index 37a4ed05..97bb7263 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -10,6 +10,6 @@ public interface MemberRepository { Member findById(Long id); //ID로 회원 정보 가져오기 List findByName(String name); // 이름으로 회원 정보 가져오기 List findAll(); // 이름으로 회원 정보 가져오기 - boolean existsByEmail(String email); + boolean existsById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/MemberRowMapper.java b/src/main/java/com/example/bcsd/repository/MemberRowMapper.java index 4511563b..facd259c 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRowMapper.java +++ b/src/main/java/com/example/bcsd/repository/MemberRowMapper.java @@ -11,6 +11,7 @@ public class MemberRowMapper implements RowMapper { public Member mapRow(ResultSet rs, int rowNum) throws SQLException { // setter + member.setId(rs.getLong("id")); member.setName(rs.getString("name")); member.setEmail(rs.getString("email")); member.setPassword(rs.getString("password")); diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index 630696df..ab82afca 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -61,8 +61,13 @@ public Article insert(Article article){ // 3. PUT(수정) @Override public Article update(Article article){ - String sql = "UPDATE article SET title = ?, content = ? WHERE id = ?"; - jdbctemplate.update(sql, article.getTitle(), article.getContent(), article.getId()); + String sql = "UPDATE article SET title = ?, content = ?, author_id = ?, board_id = ? WHERE id = ?"; + jdbctemplate.update(sql, + article.getTitle(), + article.getContent(), + article.getAuthorId(), + article.getBoardId(), + article.getId()); return findById(article.getId()); } // 4. DELETE(삭제) diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index a4246672..f3bd79f4 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -61,6 +61,13 @@ public boolean existsByEmail(String email) { return count != null && count > 0; } + @Override + public boolean existsById(Long id) { + String sql = "SELECT COUNT(*) FROM member WHERE id = ?"; + Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); + return count != null && count > 0; + } + @Override public List findAll() { String sql = "SELECT * FROM member"; diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 81e95cb5..5d0389e1 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -3,7 +3,13 @@ import com.example.bcsd.domain.Article; import com.example.bcsd.dto.ArticleDTO; +import com.example.bcsd.exception.InvalidReferenceException; +import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemoryArticleRepository; +import com.example.bcsd.repository.MemoryMemberRepository; +import com.example.bcsd.repository.BoardRepository; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @@ -11,9 +17,16 @@ @Service public class ArticleService { private final MemoryArticleRepository articleRepository; + private final MemoryMemberRepository memberRepository; + private final BoardRepository boardRepository; - public ArticleService(MemoryArticleRepository articleRepository) { + @Autowired + public ArticleService(MemoryArticleRepository articleRepository, + MemoryMemberRepository memberRepository, + BoardRepository boardRepository) { this.articleRepository = articleRepository; + this.memberRepository = memberRepository; + this.boardRepository = boardRepository; } // 1. READ - board의 전체 article @@ -30,10 +43,20 @@ public Article create(Article article){ } // 3. UPDATE public Article update(ArticleDTO req, Long id){ + if (!memberRepository.existsById(req.getAuthorId())) { + throw new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId()); + } + + if (!boardRepository.existsById(req.getBoardId())) { + throw new InvalidReferenceException("존재하지 않는 게시판입니다. board_id: " + req.getBoardId()); + } + Article article = articleRepository.findById(id); article.setTitle(req.getTitle()); article.setContent(req.getContent()); + article.setBoardId(req.getBoardId()); + article.setAuthorId(req.getAuthorId()); return articleRepository.update(article); } From 6ef2a24c0684cde1981b3a50552c81d13460fe7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 02:54:32 +0900 Subject: [PATCH 36/72] =?UTF-8?q?feat:=203.=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20400=20missing=20fiel?= =?UTF-8?q?d=20-=20member,=20article=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 4 +-- .../bcsd/controller/MemberController.java | 7 +---- .../bcsd/controller/PostController.java | 7 +++-- .../exception/GlobalExceptionHandler.java | 23 +++++++++----- .../bcsd/exception/MissingFieldException.java | 7 +++++ .../bcsd/repository/MemberRepository.java | 1 + .../repository/MemoryMemberRepository.java | 1 + .../example/bcsd/service/ArticleService.java | 31 ++++++++++++++++++- .../example/bcsd/service/BoardService.java | 21 ++++++++++--- .../example/bcsd/service/MemberService.java | 25 ++++++++++++++- 10 files changed, 103 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/example/bcsd/exception/MissingFieldException.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index ccc7e0e2..9fba82a9 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -19,8 +19,8 @@ public ArticleApiController(ArticleService articleService) { } // 1. POST /articles : 게시글 저장하기 @PostMapping - public Article create(@RequestBody Article article){ // ?? - return articleService.create(article); + public Article create(@RequestBody ArticleDTO req){ // ?? + return articleService.create(req); } // 2. GET /articles?boardId={boardId} : 한 게시판의 모든 article 조회하기 diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java index cd055e27..84a31bbf 100644 --- a/src/main/java/com/example/bcsd/controller/MemberController.java +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -22,12 +22,7 @@ public MemberController(MemberService memberService) { // 1. member 생성 @PostMapping public Member create(@RequestBody MemberDTO req) { - Member member = new Member(); - member.setName(req.getName()); - member.setEmail(req.getEmail()); - member.setPassword(req.getPassword()); - - return memberService.create(member); + return memberService.create(req); } // 2. member 정보 수정 diff --git a/src/main/java/com/example/bcsd/controller/PostController.java b/src/main/java/com/example/bcsd/controller/PostController.java index 409e9e5c..0732ad19 100644 --- a/src/main/java/com/example/bcsd/controller/PostController.java +++ b/src/main/java/com/example/bcsd/controller/PostController.java @@ -12,14 +12,17 @@ @Controller @RequestMapping("/posts") // /posts?boardId={boardId} public class PostController { + private final BoardService boardService; private final ArticleService articleService; - public PostController(ArticleService articleService) { + + public PostController(ArticleService articleService, BoardService boardService) { + this.boardService = boardService; this.articleService = articleService; } @GetMapping public String posts(@RequestParam("boardId") Long boardId, Model model) { - String boardName = BoardService.getBoardName(boardId); + String boardName = boardService.getBoardName(boardId); model.addAttribute("boardName", boardName); model.addAttribute("articles", articleService.getAllArticlesByBoard(boardId)); return "posts"; diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java index a66e9b7c..b98076dd 100644 --- a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -1,7 +1,6 @@ package com.example.bcsd.exception; import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -9,12 +8,12 @@ @RestControllerAdvice public class GlobalExceptionHandler { -// // 1. 조회 예외처리 - 존재하지 않는 게시물 조회 시 404 -// @ExceptionHandler(EmptyResultDataAccessException.class) -// public ResponseEntity handleEmptyResult(EmptyResultDataAccessException ex) { -//// ex.printStackTrace(); -// return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); -// } + // 1. 조회 예외처리 - 존재하지 않는 게시물 조회 시 404 + @ExceptionHandler(EmptyResultDataAccessException.class) + public ResponseEntity handleEmptyResult(EmptyResultDataAccessException ex) { +// ex.printStackTrace(); + return ResponseEntity.status(404).body("해당 데이터를 찾을 수 없습니다."); + } // 2. 수정 예외처리 - 1. 중복된 이메일로 수정 시도하면 409 @ExceptionHandler(DuplicateEmailException.class) public ResponseEntity handleDuplicateEmail(DuplicateEmailException ex) { @@ -29,4 +28,14 @@ public ResponseEntity handleInvalidReference(InvalidReferenceException e .status(400) .body(ex.getMessage()); } + // 3. 생성 예외처리 - 1. 사용자/게시판/게시물 생성 시 들어온 요청 중 null인 값이 하나라도 존재하면 400 + @ExceptionHandler(MissingFieldException.class) + public ResponseEntity handleMissingField(MissingFieldException ex){ + return ResponseEntity + .status(400) + .body(ex.getMessage()); + } + + // 3. 생성 예외처리 - 2. 게시물(Article) 생성 시 존재하지 않는 사용자 혹은 게시판을 참조하는 경우 400 + } diff --git a/src/main/java/com/example/bcsd/exception/MissingFieldException.java b/src/main/java/com/example/bcsd/exception/MissingFieldException.java new file mode 100644 index 00000000..c33b8c56 --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/MissingFieldException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.exception; + +public class MissingFieldException extends RuntimeException { + public MissingFieldException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index 97bb7263..ed79bf7d 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -12,4 +12,5 @@ public interface MemberRepository { List findAll(); // 이름으로 회원 정보 가져오기 boolean existsByEmail(String email); boolean existsById(Long id); + boolean deleteById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java index f3bd79f4..8237777c 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java @@ -74,6 +74,7 @@ public List findAll() { return jdbctemplate.query(sql, rowMapper); } + @Override public boolean deleteById(Long id){ String sql = "DELETE FROM article WHERE id = ?"; int rows = jdbctemplate.update(sql, id); diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 5d0389e1..82968753 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -4,6 +4,7 @@ import com.example.bcsd.dto.ArticleDTO; import com.example.bcsd.exception.InvalidReferenceException; +import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemoryArticleRepository; import com.example.bcsd.repository.MemoryMemberRepository; @@ -38,7 +39,15 @@ public Article getOne(Long id){ return articleRepository.findById(id); } // 2. CREATE - public Article create(Article article){ + public Article create(ArticleDTO req){ + validateForCreate(req); + + Article article = new Article(); + article.setTitle(req.getTitle()); + article.setContent(req.getContent()); + article.setAuthorId(req.getAuthorId()); + article.setBoardId(req.getBoardId()); + return articleRepository.insert(article); } // 3. UPDATE @@ -64,4 +73,24 @@ public Article update(ArticleDTO req, Long id){ public boolean delete(Long id){ return articleRepository.deleteById(id); } + + private void validateForCreate(ArticleDTO req) { + + if (req.getTitle() == null || req.getTitle().isBlank()) { + throw new MissingFieldException("title은 null일 수 없습니다."); + } + + if (req.getContent() == null || req.getContent().isBlank()) { + throw new MissingFieldException("content는 null일 수 없습니다."); + } + + if (req.getAuthorId() == null) { + throw new MissingFieldException("authorId는 null일 수 없습니다."); + } + + if (req.getBoardId() == null) { + throw new MissingFieldException("boardId는 null일 수 없습니다."); + } + } + } diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index 628e245b..c9135a35 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -1,16 +1,27 @@ package com.example.bcsd.service; +import com.example.bcsd.domain.Board; +import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.BoardRepository; import org.springframework.stereotype.Service; @Service public class BoardService { - private static BoardRepository boardRepository; - - public BoardService(BoardRepository boardRepository) { - this.boardRepository = boardRepository; + private BoardRepository boardRepository; + public BoardService(BoardRepository boardRepository){ + this.boardRepository=boardRepository; } - public static String getBoardName(Long boardId) { + public String getBoardName(Long boardId) { return boardRepository.findNameById(boardId); } + private void validateForCreate(Board board) { + + if (board.getTitle() == null || board.getTitle().isBlank()) { + throw new MissingFieldException("title은 null일 수 없습니다."); + } + + if (board.getId() == null) { + throw new MissingFieldException("Id는 null일 수 없습니다."); + } + } } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 49c94427..46ce0207 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -1,8 +1,10 @@ // 모든 비즈니스 로직들을 작성한다. package com.example.bcsd.service; import com.example.bcsd.domain.Member; +import com.example.bcsd.dto.ArticleDTO; import com.example.bcsd.dto.MemberDTO; import com.example.bcsd.exception.DuplicateEmailException; +import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -19,7 +21,14 @@ public MemberService(MemoryMemberRepository memberRepository) { this.memberRepository = memberRepository; } - public Member create(Member member) { + public Member create(MemberDTO req) { + validateForCreate(req); + + Member member = new Member(); + member.setName(req.getName()); + member.setEmail(req.getEmail()); + member.setPassword(req.getPassword()); + return memberRepository.insert(member); } @@ -49,4 +58,18 @@ public List searchByName(String name) { public boolean delete(Long id) { return memberRepository.deleteById(id); } + private void validateForCreate(MemberDTO req) { + + if (req.getName() == null || req.getName().isBlank()) { + throw new MissingFieldException("name은 null일 수 없습니다."); + } + + if (req.getEmail() == null || req.getEmail().isBlank()) { + throw new MissingFieldException("email은 null일 수 없습니다."); + } + + if (req.getPassword() == null || req.getPassword().isBlank()) { + throw new MissingFieldException("password은 null일 수 없습니다."); + } + } } From 0f23e4d65406203a4fc4f351fc308ba4a1d21a5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 03:31:34 +0900 Subject: [PATCH 37/72] =?UTF-8?q?refactor:=20board=20-=20jdbctemplate?= =?UTF-8?q?=EC=82=AC=EC=9A=A9.=20feat:=203.=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20400=20missing=20fiel?= =?UTF-8?q?d=20-=20board=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/BoardController.java | 34 ++++++++++++++ .../java/com/example/bcsd/dto/BoardDTO.java | 13 ++++++ .../bcsd/repository/BoardRepository.java | 46 ++++++++++++++++--- .../bcsd/repository/BoardRowMapper.java | 20 ++++++++ .../example/bcsd/service/BoardService.java | 23 ++++++---- 5 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/example/bcsd/controller/BoardController.java create mode 100644 src/main/java/com/example/bcsd/dto/BoardDTO.java create mode 100644 src/main/java/com/example/bcsd/repository/BoardRowMapper.java diff --git a/src/main/java/com/example/bcsd/controller/BoardController.java b/src/main/java/com/example/bcsd/controller/BoardController.java new file mode 100644 index 00000000..3cfc0ce2 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/BoardController.java @@ -0,0 +1,34 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.domain.Board; +import com.example.bcsd.dto.BoardDTO; +import com.example.bcsd.service.BoardService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/board") +public class BoardController { + private final BoardService boardService; + + public BoardController(BoardService boardService) { + this.boardService = boardService; + } + + // 1. POST /board : 게시판 신규 생성하기 + @PostMapping + public Board create(@RequestBody BoardDTO req){ + return boardService.create(req); + } + + // 2. DELETE /boardId/{id} : 게시판 id로 삭제하기 + @DeleteMapping("/{id}") + public ResponseEntity delete(@PathVariable Long id) { + boolean deleted = boardService.delete(id); + if (deleted) { + return ResponseEntity.noContent().build(); // 204 + } else { + return ResponseEntity.notFound().build(); // 404 + } + } +} diff --git a/src/main/java/com/example/bcsd/dto/BoardDTO.java b/src/main/java/com/example/bcsd/dto/BoardDTO.java new file mode 100644 index 00000000..ffb94e16 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/BoardDTO.java @@ -0,0 +1,13 @@ +package com.example.bcsd.dto; + +public class BoardDTO { + private String title; // 게시판 이름 + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } +} diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java index d585a671..6ff3acb4 100644 --- a/src/main/java/com/example/bcsd/repository/BoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -1,26 +1,58 @@ package com.example.bcsd.repository; +import com.example.bcsd.domain.Board; +import com.example.bcsd.dto.BoardDTO; import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; import org.springframework.stereotype.Repository; +import java.sql.PreparedStatement; +import java.util.Objects; + @Repository public class BoardRepository { - private final JdbcTemplate jdbcTemplate; + private final JdbcTemplate jdbctemplate; public BoardRepository(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; + this.jdbctemplate = jdbcTemplate; + } + + public Board findById(Long id){ + String sql = "select * from board where id = ?"; + return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); + } + + // 1. 생성 + public Board insert(BoardDTO board) { + String sql = "INSERT INTO board (title) VALUES (?)"; + // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbctemplate.update(con-> { + PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); + ps.setString(1, board.getTitle()); + return ps; + }, keyHolder); + Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); + return findById(id); } - public String findNameById(Long id) { - String sql = "SELECT name FROM board WHERE id = ?"; - return jdbcTemplate.queryForObject(sql, String.class, id); + // 2. 삭제 + public boolean delete(Long id){ + String sql = "delete from board where id = ?"; + int rows = jdbctemplate.update(sql, id); + + if (rows == 0) { + throw new IllegalArgumentException(id + "번 게시판이 없습니다."); + } + return false; } public boolean existsById(Long id) { String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; - Integer count = jdbcTemplate.queryForObject(sql, Integer.class, id); + Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); return count != null && count > 0; } - } diff --git a/src/main/java/com/example/bcsd/repository/BoardRowMapper.java b/src/main/java/com/example/bcsd/repository/BoardRowMapper.java new file mode 100644 index 00000000..62185048 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/BoardRowMapper.java @@ -0,0 +1,20 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Board; +import org.springframework.jdbc.core.RowMapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class BoardRowMapper implements RowMapper { + @Override + public Board mapRow(ResultSet rs, int rowNum) throws SQLException { + Board board = new Board(); + + // setter + board.setId(rs.getLong("id")); + board.setTitle(rs.getString("title")); + + return board; + } +} diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index c9135a35..b175d995 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -1,27 +1,34 @@ package com.example.bcsd.service; import com.example.bcsd.domain.Board; +import com.example.bcsd.dto.BoardDTO; import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.BoardRepository; import org.springframework.stereotype.Service; @Service public class BoardService { - private BoardRepository boardRepository; + private final BoardRepository boardRepository; public BoardService(BoardRepository boardRepository){ this.boardRepository=boardRepository; } - public String getBoardName(Long boardId) { - return boardRepository.findNameById(boardId); + public Board create(BoardDTO req) { + validateForCreate(req); + return boardRepository.insert(req); + } + + public boolean delete(Long id) { + return boardRepository.delete(id); } - private void validateForCreate(Board board) { - if (board.getTitle() == null || board.getTitle().isBlank()) { + private void validateForCreate(BoardDTO req) { + + if (req.getTitle() == null || req.getTitle().isBlank()) { throw new MissingFieldException("title은 null일 수 없습니다."); } + } - if (board.getId() == null) { - throw new MissingFieldException("Id는 null일 수 없습니다."); - } + public String getBoardName(Long boardId) { + return boardRepository.findById(boardId).getTitle(); } } From 761fdd987b3db5636667806ed2c21f4925a6d385 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 03:43:12 +0900 Subject: [PATCH 38/72] =?UTF-8?q?feat:=203.=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20400=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=A1=B4=EC=9E=AC=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=EC=82=AC=EC=9A=A9=EC=9E=90/=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=ED=8C=90=20=EC=B0=B8=EC=A1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/service/ArticleService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 82968753..f5113df4 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -41,6 +41,13 @@ public Article getOne(Long id){ // 2. CREATE public Article create(ArticleDTO req){ validateForCreate(req); + if (!memberRepository.existsById(req.getAuthorId())) { + throw new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId()); + } + + if (!boardRepository.existsById(req.getBoardId())) { + throw new InvalidReferenceException("존재하지 않는 게시판입니다. board_id: " + req.getBoardId()); + } Article article = new Article(); article.setTitle(req.getTitle()); From a92300a6e77e0e25eb049d455b2760dbf1c9c7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 03:59:26 +0900 Subject: [PATCH 39/72] =?UTF-8?q?feat:=204.=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20400=20RemainArticles?= =?UTF-8?q?Exception?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/exception/GlobalExceptionHandler.java | 10 +++++++++- .../bcsd/exception/RemainArticlesException.java | 7 +++++++ .../bcsd/repository/MemoryArticleRepository.java | 5 +++++ .../com/example/bcsd/service/MemberService.java | 14 ++++++++++++-- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/example/bcsd/exception/RemainArticlesException.java diff --git a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java index b98076dd..e686d979 100644 --- a/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/example/bcsd/exception/GlobalExceptionHandler.java @@ -36,6 +36,14 @@ public ResponseEntity handleMissingField(MissingFieldException ex){ .body(ex.getMessage()); } - // 3. 생성 예외처리 - 2. 게시물(Article) 생성 시 존재하지 않는 사용자 혹은 게시판을 참조하는 경우 400 + // 4. 삭제 예외처리 - 1. 사용자(Member) 삭제 시 사용자가 작성한 게시물이 하나라도 있으면 400 + @ExceptionHandler(RemainArticlesException.class) + public ResponseEntity handleRemainArticles(RemainArticlesException ex){ + return ResponseEntity + .status(400) + .body(ex.getMessage()); + } + + // 4. 삭제 예외처리 - 2. 게시판(Board) 삭제 시 해당 게시판에 작성된 게시물이 하나라도 있으면 400 } diff --git a/src/main/java/com/example/bcsd/exception/RemainArticlesException.java b/src/main/java/com/example/bcsd/exception/RemainArticlesException.java new file mode 100644 index 00000000..743454cd --- /dev/null +++ b/src/main/java/com/example/bcsd/exception/RemainArticlesException.java @@ -0,0 +1,7 @@ +package com.example.bcsd.exception; + +public class RemainArticlesException extends RuntimeException { + public RemainArticlesException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index ab82afca..e49debcf 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -80,4 +80,9 @@ public boolean deleteById(Long id){ } return false; } + public boolean existsByAuthorId(Long author_id){ + String sql = "select count(*) from article where author_id = ?"; + int count = jdbctemplate.queryForObject(sql, new Object[]{author_id}, Integer.class); + return count > 0; + } } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 46ce0207..ca720b3e 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -1,10 +1,11 @@ // 모든 비즈니스 로직들을 작성한다. package com.example.bcsd.service; import com.example.bcsd.domain.Member; -import com.example.bcsd.dto.ArticleDTO; import com.example.bcsd.dto.MemberDTO; import com.example.bcsd.exception.DuplicateEmailException; import com.example.bcsd.exception.MissingFieldException; +import com.example.bcsd.exception.RemainArticlesException; +import com.example.bcsd.repository.MemoryArticleRepository; import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,10 +16,12 @@ @Service public class MemberService { private final MemoryMemberRepository memberRepository; + private final MemoryArticleRepository articleRepository; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemoryMemberRepository memberRepository) { + public MemberService(MemoryMemberRepository memberRepository, MemoryArticleRepository articleRepository) { this.memberRepository = memberRepository; + this.articleRepository = articleRepository; } public Member create(MemberDTO req) { @@ -56,8 +59,12 @@ public List searchByName(String name) { } public boolean delete(Long id) { + if (articleRepository.existsByAuthorId(id)){ + throw new RemainArticlesException("사용자가 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); + } return memberRepository.deleteById(id); } + private void validateForCreate(MemberDTO req) { if (req.getName() == null || req.getName().isBlank()) { @@ -72,4 +79,7 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } + private void validateForDelete(MemberDTO req) { + + } } From f256dc4d19b420b45328b7501e2ce16bd6501fda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Tue, 2 Dec 2025 04:09:17 +0900 Subject: [PATCH 40/72] =?UTF-8?q?feat:=204.=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20-=20=EA=B2=8C=EC=8B=9C?= =?UTF-8?q?=ED=8C=90=EA=B9=8C=EC=A7=80=20=EC=99=84=EB=A3=8Cgit=20add=20.gi?= =?UTF-8?q?t=20add=20.git=20add=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/repository/MemoryArticleRepository.java | 9 +++++++-- .../java/com/example/bcsd/service/BoardService.java | 10 +++++++++- .../java/com/example/bcsd/service/MemberService.java | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java index e49debcf..30b7008b 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java @@ -80,9 +80,14 @@ public boolean deleteById(Long id){ } return false; } - public boolean existsByAuthorId(Long author_id){ + public boolean existsByAuthorId(Long authorId){ String sql = "select count(*) from article where author_id = ?"; - int count = jdbctemplate.queryForObject(sql, new Object[]{author_id}, Integer.class); + int count = jdbctemplate.queryForObject(sql, new Object[]{authorId}, Integer.class); + return count > 0; + } + public boolean existsByBoardId(Long boardId){ + String sql = "select count(*) from board where board_id = ?"; + int count = jdbctemplate.queryForObject(sql, new Object[]{boardId}, Integer.class); return count > 0; } } diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index b175d995..0f572bc0 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -2,14 +2,19 @@ import com.example.bcsd.domain.Board; import com.example.bcsd.dto.BoardDTO; import com.example.bcsd.exception.MissingFieldException; +import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.BoardRepository; +import com.example.bcsd.repository.MemoryArticleRepository; import org.springframework.stereotype.Service; @Service public class BoardService { private final BoardRepository boardRepository; - public BoardService(BoardRepository boardRepository){ + private final MemoryArticleRepository articleRepository; + + public BoardService(BoardRepository boardRepository, MemoryArticleRepository articleRepository) { this.boardRepository=boardRepository; + this.articleRepository=articleRepository; } public Board create(BoardDTO req) { @@ -18,6 +23,9 @@ public Board create(BoardDTO req) { } public boolean delete(Long id) { + if (articleRepository.existsByAuthorId(id)){ + throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. board_id =" + id); + } return boardRepository.delete(id); } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index ca720b3e..ff975ee4 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -59,8 +59,8 @@ public List searchByName(String name) { } public boolean delete(Long id) { - if (articleRepository.existsByAuthorId(id)){ - throw new RemainArticlesException("사용자가 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); + if (articleRepository.existsByBoardId(id)){ + throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); } return memberRepository.deleteById(id); } From 102741fb9367cf9e629193358480a93ff04db5dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 22:31:15 +0900 Subject: [PATCH 41/72] =?UTF-8?q?refactor:=20jpa=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index 0f03a25c..5e22111f 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'com.mysql:mysql-connector-j' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' From 0b3a894c5e90f82c7c8b64498b6cb24d7cf357a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 22:42:30 +0900 Subject: [PATCH 42/72] =?UTF-8?q?refactor:=20member=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20jpa=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Member.java | 49 ++++++------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 83441a3e..e44e667e 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -1,41 +1,24 @@ package com.example.bcsd.domain; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Entity +@Table(name = "member") public class Member { + @Id + @Column(name = "ID") private Long id; + @Setter + @Column(name = "name") private String name; + @Column(name = "email") private String email; + @Column(name = "password") private String password; - - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public String getEmail() { - return email; - } - - public void setEmail(String email) { - this.email = email; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } } From 7532a7915d8ecd6d8bd93cb85d711387e2c2849e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 22:44:22 +0900 Subject: [PATCH 43/72] =?UTF-8?q?fix:=20setter=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=9C=84=EC=B9=98=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/com/example/bcsd/domain/Member.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index e44e667e..070a87a5 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -7,6 +7,7 @@ import lombok.Getter; import lombok.Setter; +@Setter @Getter @Entity @Table(name = "member") @@ -14,7 +15,6 @@ public class Member { @Id @Column(name = "ID") private Long id; - @Setter @Column(name = "name") private String name; @Column(name = "email") From 6ed39c0c68d757d24f97d15f4e88eed6afea17b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 22:46:02 +0900 Subject: [PATCH 44/72] =?UTF-8?q?refactor:=20board=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=20jpa=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Board.java | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index 02b6362a..414aa588 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -1,21 +1,17 @@ package com.example.bcsd.domain; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter +@Entity +@Table(name = "board") public class Board { - private long id; + @Id + private Long id; private String title; // 게시판 이름 - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - public Long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } } From 584c45ca68f0120793db50095bdd72e327b39a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 22:47:42 +0900 Subject: [PATCH 45/72] =?UTF-8?q?refactor:=20article=ED=85=8C=EC=9D=B4?= =?UTF-8?q?=EB=B8=94=EC=97=90=20jpa=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Article.java | 68 +++---------------- 1 file changed, 10 insertions(+), 58 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index 71b8a0c6..1ef2e5f4 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -1,11 +1,20 @@ package com.example.bcsd.domain; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; import java.time.LocalDateTime; - +@Setter +@Getter +@Entity +@Table(name = "article") public class Article { + @Id private Long id; @JsonProperty("author_id") private Long authorId; @@ -19,61 +28,4 @@ public class Article { private LocalDateTime createdAt; public Article(){} - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getAuthorId() { - return authorId; - } - - public void setAuthorId(Long authorId) { - this.authorId = authorId; - } - - public Long getBoardId() { - return boardId; - } - - public void setBoardId(Long boardId) { - this.boardId = boardId; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public LocalDateTime getUpdatedAt() { - return updatedAt; - } - - public void setUpdatedAt(LocalDateTime updatedAt) { - this.updatedAt = updatedAt; - } - - public LocalDateTime getCreatedAt() { - return createdAt; - } - - public void setCreatedAt(LocalDateTime createdAt) { - this.createdAt = createdAt; - } - } From 2ac2e2f58ac2b3fcbd99b3cc0c067a3ec10c6440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 23:01:00 +0900 Subject: [PATCH 46/72] =?UTF-8?q?refactor:=20BoardRepository=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20=EB=B6=84=EB=A6=AC,=20Jpa=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/repository/BoardRepository.java | 54 ++--------------- .../repository/MemoryBoardRepository.java | 58 +++++++++++++++++++ 2 files changed, 64 insertions(+), 48 deletions(-) create mode 100644 src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java index 6ff3acb4..637f06a5 100644 --- a/src/main/java/com/example/bcsd/repository/BoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -1,58 +1,16 @@ package com.example.bcsd.repository; - import com.example.bcsd.domain.Board; import com.example.bcsd.dto.BoardDTO; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import java.sql.PreparedStatement; -import java.util.Objects; - -@Repository -public class BoardRepository { - - private final JdbcTemplate jdbctemplate; +import org.springframework.data.jpa.repository.JpaRepository; - public BoardRepository(JdbcTemplate jdbcTemplate) { - this.jdbctemplate = jdbcTemplate; - } - - public Board findById(Long id){ - String sql = "select * from board where id = ?"; - return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); - } +public interface BoardRepository extends JpaRepository { +// Board findById(Long id); // 1. 생성 - public Board insert(BoardDTO board) { - String sql = "INSERT INTO board (title) VALUES (?)"; - // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbctemplate.update(con-> { - PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); - ps.setString(1, board.getTitle()); - return ps; - }, keyHolder); - Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); - return findById(id); - } + Board insert(BoardDTO board); // 2. 삭제 - public boolean delete(Long id){ - String sql = "delete from board where id = ?"; - int rows = jdbctemplate.update(sql, id); - - if (rows == 0) { - throw new IllegalArgumentException(id + "번 게시판이 없습니다."); - } - return false; - } + boolean delete(Long id); - public boolean existsById(Long id) { - String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; - Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); - return count != null && count > 0; - } + boolean existsById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java b/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java new file mode 100644 index 00000000..5b29f5d2 --- /dev/null +++ b/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java @@ -0,0 +1,58 @@ +package com.example.bcsd.repository; + +import com.example.bcsd.domain.Board; +import com.example.bcsd.dto.BoardDTO; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; + +import java.sql.PreparedStatement; +import java.util.Objects; + +@Repository +public class MemoryBoardRepository { + + private final JdbcTemplate jdbctemplate; + + public MemoryBoardRepository(JdbcTemplate jdbcTemplate) { + this.jdbctemplate = jdbcTemplate; + } + + public Board findById(Long id){ + String sql = "select * from board where id = ?"; + return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); + } + + // 1. 생성 + public Board insert(BoardDTO board) { + String sql = "INSERT INTO board (title) VALUES (?)"; + // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER + KeyHolder keyHolder = new GeneratedKeyHolder(); + + jdbctemplate.update(con-> { + PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); + ps.setString(1, board.getTitle()); + return ps; + }, keyHolder); + Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); + return findById(id); + } + + // 2. 삭제 + public boolean delete(Long id){ + String sql = "delete from board where id = ?"; + int rows = jdbctemplate.update(sql, id); + + if (rows == 0) { + throw new IllegalArgumentException(id + "번 게시판이 없습니다."); + } + return false; + } + + public boolean existsById(Long id) { + String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; + Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); + return count != null && count > 0; + } +} From 4fc9db80b1f64252b9275462fecfa5c54abaf6ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 23:06:57 +0900 Subject: [PATCH 47/72] =?UTF-8?q?remove:=20boardRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EB=B6=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/repository/BoardRepository.java | 10 +- .../repository/MemoryBoardRepository.java | 116 +++++++++--------- 2 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java index 637f06a5..68e550d4 100644 --- a/src/main/java/com/example/bcsd/repository/BoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -4,13 +4,5 @@ import org.springframework.data.jpa.repository.JpaRepository; public interface BoardRepository extends JpaRepository { -// Board findById(Long id); - - // 1. 생성 - Board insert(BoardDTO board); - - // 2. 삭제 - boolean delete(Long id); - - boolean existsById(Long id); + // 내용 전부 삭제. JPA가 대체. } diff --git a/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java b/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java index 5b29f5d2..9f54521f 100644 --- a/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java @@ -1,58 +1,58 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Board; -import com.example.bcsd.dto.BoardDTO; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import java.sql.PreparedStatement; -import java.util.Objects; - -@Repository -public class MemoryBoardRepository { - - private final JdbcTemplate jdbctemplate; - - public MemoryBoardRepository(JdbcTemplate jdbcTemplate) { - this.jdbctemplate = jdbcTemplate; - } - - public Board findById(Long id){ - String sql = "select * from board where id = ?"; - return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); - } - - // 1. 생성 - public Board insert(BoardDTO board) { - String sql = "INSERT INTO board (title) VALUES (?)"; - // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbctemplate.update(con-> { - PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); - ps.setString(1, board.getTitle()); - return ps; - }, keyHolder); - Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); - return findById(id); - } - - // 2. 삭제 - public boolean delete(Long id){ - String sql = "delete from board where id = ?"; - int rows = jdbctemplate.update(sql, id); - - if (rows == 0) { - throw new IllegalArgumentException(id + "번 게시판이 없습니다."); - } - return false; - } - - public boolean existsById(Long id) { - String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; - Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); - return count != null && count > 0; - } -} +//package com.example.bcsd.repository; +// +//import com.example.bcsd.domain.Board; +//import com.example.bcsd.dto.BoardDTO; +//import org.springframework.jdbc.core.JdbcTemplate; +//import org.springframework.jdbc.support.GeneratedKeyHolder; +//import org.springframework.jdbc.support.KeyHolder; +//import org.springframework.stereotype.Repository; +// +//import java.sql.PreparedStatement; +//import java.util.Objects; +// +//@Repository +//public class MemoryBoardRepository { +// +// private final JdbcTemplate jdbctemplate; +// +// public MemoryBoardRepository(JdbcTemplate jdbcTemplate) { +// this.jdbctemplate = jdbcTemplate; +// } +// +// public Board findById(Long id){ +// String sql = "select * from board where id = ?"; +// return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); +// } +// +// // 1. 생성 +// public Board insert(BoardDTO board) { +// String sql = "INSERT INTO board (title) VALUES (?)"; +// // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER +// KeyHolder keyHolder = new GeneratedKeyHolder(); +// +// jdbctemplate.update(con-> { +// PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); +// ps.setString(1, board.getTitle()); +// return ps; +// }, keyHolder); +// Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); +// return findById(id); +// } +// +// // 2. 삭제 +// public boolean delete(Long id){ +// String sql = "delete from board where id = ?"; +// int rows = jdbctemplate.update(sql, id); +// +// if (rows == 0) { +// throw new IllegalArgumentException(id + "번 게시판이 없습니다."); +// } +// return false; +// } +// +// public boolean existsById(Long id) { +// String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; +// Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); +// return count != null && count > 0; +// } +//} From 31c6853d5e353234a6d01c5e5f15ef6460692782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 23:07:40 +0900 Subject: [PATCH 48/72] =?UTF-8?q?remove:=20boardRepository=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EB=B6=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/MemoryBoardRepository.java | 58 ------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java diff --git a/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java b/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java deleted file mode 100644 index 9f54521f..00000000 --- a/src/main/java/com/example/bcsd/repository/MemoryBoardRepository.java +++ /dev/null @@ -1,58 +0,0 @@ -//package com.example.bcsd.repository; -// -//import com.example.bcsd.domain.Board; -//import com.example.bcsd.dto.BoardDTO; -//import org.springframework.jdbc.core.JdbcTemplate; -//import org.springframework.jdbc.support.GeneratedKeyHolder; -//import org.springframework.jdbc.support.KeyHolder; -//import org.springframework.stereotype.Repository; -// -//import java.sql.PreparedStatement; -//import java.util.Objects; -// -//@Repository -//public class MemoryBoardRepository { -// -// private final JdbcTemplate jdbctemplate; -// -// public MemoryBoardRepository(JdbcTemplate jdbcTemplate) { -// this.jdbctemplate = jdbcTemplate; -// } -// -// public Board findById(Long id){ -// String sql = "select * from board where id = ?"; -// return jdbctemplate.queryForObject(sql, new BoardRowMapper(), id); -// } -// -// // 1. 생성 -// public Board insert(BoardDTO board) { -// String sql = "INSERT INTO board (title) VALUES (?)"; -// // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER -// KeyHolder keyHolder = new GeneratedKeyHolder(); -// -// jdbctemplate.update(con-> { -// PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); -// ps.setString(1, board.getTitle()); -// return ps; -// }, keyHolder); -// Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); -// return findById(id); -// } -// -// // 2. 삭제 -// public boolean delete(Long id){ -// String sql = "delete from board where id = ?"; -// int rows = jdbctemplate.update(sql, id); -// -// if (rows == 0) { -// throw new IllegalArgumentException(id + "번 게시판이 없습니다."); -// } -// return false; -// } -// -// public boolean existsById(Long id) { -// String sql = "SELECT COUNT(*) FROM board WHERE id = ?"; -// Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); -// return count != null && count > 0; -// } -//} From 4d1d3e8cebc2d78098d171a73e080cc4a60cd0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Sun, 4 Jan 2026 23:08:32 +0900 Subject: [PATCH 49/72] =?UTF-8?q?remove:=20board=20rowmapper=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 --- .../bcsd/repository/BoardRowMapper.java | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/repository/BoardRowMapper.java diff --git a/src/main/java/com/example/bcsd/repository/BoardRowMapper.java b/src/main/java/com/example/bcsd/repository/BoardRowMapper.java deleted file mode 100644 index 62185048..00000000 --- a/src/main/java/com/example/bcsd/repository/BoardRowMapper.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Board; -import org.springframework.jdbc.core.RowMapper; - -import java.sql.ResultSet; -import java.sql.SQLException; - -public class BoardRowMapper implements RowMapper { - @Override - public Board mapRow(ResultSet rs, int rowNum) throws SQLException { - Board board = new Board(); - - // setter - board.setId(rs.getLong("id")); - board.setTitle(rs.getString("title")); - - return board; - } -} From b0cc9ea4b92776b0d48068115f52f50975f6e173 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 00:03:28 +0900 Subject: [PATCH 50/72] =?UTF-8?q?refactor:=20BoardService=20JPA=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ .../bcsd/repository/BoardRepository.java | 1 - .../example/bcsd/service/BoardService.java | 21 ++++++++++++------- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/build.gradle b/build.gradle index 5e22111f..7d35d42c 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,8 @@ dependencies { implementation 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + compileOnly 'org.projectlombok:lombok:1.18.38' + annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } @@ -31,3 +33,5 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +def void plugins(Closure pluginDependencySpecClosure) {} diff --git a/src/main/java/com/example/bcsd/repository/BoardRepository.java b/src/main/java/com/example/bcsd/repository/BoardRepository.java index 68e550d4..52e3423c 100644 --- a/src/main/java/com/example/bcsd/repository/BoardRepository.java +++ b/src/main/java/com/example/bcsd/repository/BoardRepository.java @@ -1,6 +1,5 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Board; -import com.example.bcsd.dto.BoardDTO; import org.springframework.data.jpa.repository.JpaRepository; public interface BoardRepository extends JpaRepository { diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index 0f572bc0..d60b8dd2 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -13,20 +13,25 @@ public class BoardService { private final MemoryArticleRepository articleRepository; public BoardService(BoardRepository boardRepository, MemoryArticleRepository articleRepository) { - this.boardRepository=boardRepository; - this.articleRepository=articleRepository; + this.boardRepository = boardRepository; + this.articleRepository = articleRepository; } public Board create(BoardDTO req) { validateForCreate(req); - return boardRepository.insert(req); + + // dto -> entity로 변환 + Board board = new Board(); + board.setTitle(req.getTitle()); + + return boardRepository.save(board); } - public boolean delete(Long id) { - if (articleRepository.existsByAuthorId(id)){ + public void delete(Long id) { + if (articleRepository.existsByBoardId(id)){ throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. board_id =" + id); } - return boardRepository.delete(id); + boardRepository.deleteById(id); } private void validateForCreate(BoardDTO req) { @@ -37,6 +42,8 @@ private void validateForCreate(BoardDTO req) { } public String getBoardName(Long boardId) { - return boardRepository.findById(boardId).getTitle(); + Board board = boardRepository.findById(boardId) + .orElseThrow(() -> new IllegalArgumentException(boardId + "번 게시판이 없습니다.")); + return board.getTitle(); } } From f576b72d4be6c24ab346873aaf47c550fc0d94b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 00:05:56 +0900 Subject: [PATCH 51/72] =?UTF-8?q?remove:=20articleRepository=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EB=B6=80=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/repository/ArticleRepository.java | 18 +--- .../bcsd/repository/ArticleRowMapper.java | 29 ------ .../repository/MemoryArticleRepository.java | 93 ------------------- 3 files changed, 2 insertions(+), 138 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/repository/ArticleRowMapper.java delete mode 100644 src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index dcb0f7e9..82c9e1ec 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -1,24 +1,10 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Article; +import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; -public interface ArticleRepository { - // 1. GET(조회) - // b. boardId로 게시판의 게시물들을 JSON 배열로 반환 - // /articles?boardId={boardId} - List
findByBoardId(Long boardId); +public interface ArticleRepository extends JpaRepository { - // c. article의 id로 해당 article 하나 조회 - Article findById(Long id); //ID로 회원 정보 가져오기 - - // 2. POST(등록) - Article insert(Article article); - - // 3. PUT(수정) - Article update(Article article); - -// // 4. DELETE(삭제) -// void deleteById(Long id); } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java b/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java deleted file mode 100644 index 489a9ee8..00000000 --- a/src/main/java/com/example/bcsd/repository/ArticleRowMapper.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Article; -import org.springframework.jdbc.core.RowMapper; - -import java.sql.ResultSet; -import java.sql.SQLException; - -//public interface RowMapper { -// T mapRow(ResultSet rs, int rowNum) throws SQLException; -//} -public class ArticleRowMapper implements RowMapper
{ - - @Override - public Article mapRow(ResultSet rs, int rowNum) throws SQLException { - Article article = new Article(); - - // setter - article.setId(rs.getLong("id")); - article.setTitle(rs.getString("title")); - article.setContent(rs.getString("content")); - article.setAuthorId(rs.getLong("author_id")); - article.setBoardId(rs.getLong("board_id")); - - article.setCreatedAt(rs.getTimestamp("created_date").toLocalDateTime()); - article.setUpdatedAt(rs.getTimestamp("modified_date").toLocalDateTime()); - return article; - } -} diff --git a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java b/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java deleted file mode 100644 index 30b7008b..00000000 --- a/src/main/java/com/example/bcsd/repository/MemoryArticleRepository.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Article; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import org.springframework.stereotype.Repository; - -import java.sql.PreparedStatement; -import java.util.*; - -@Repository -public class MemoryArticleRepository implements ArticleRepository { - // db 연결 - private final JdbcTemplate jdbctemplate; // jdbc 정의 - public MemoryArticleRepository(JdbcTemplate jdbctemplate) { - this.jdbctemplate = jdbctemplate; - } - - // 1. GET(조회) - - // a&b. boardId로 게시판의 게시물들을 모두 JSON 배열로 반환 - // /articles?boardId={boardId} - public List
findByBoardId(Long board_id){ - String sql = "select * from article where board_id = ?"; - return jdbctemplate.query(sql, new ArticleRowMapper(), board_id); - } - - // c. article의 id로 해당 article 하나 조회 - // /articles/{id} - @Override - public Article findById(Long id){ //ID로 회원 정보 가져오기 - String sql = "select * from article where id = ?"; - return jdbctemplate.queryForObject(sql, new ArticleRowMapper(), id); - } - - // 2. POST(등록) - @Override - public Article insert(Article article){ - String sql = "INSERT INTO article(board_id, author_id, title, content)" + - "VALUES (?, ?, ?, ?)"; - - // 자동 증가 PK(id)를 받기 위한 객체 KEYHOLDER - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbctemplate.update(con-> { - PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"}); - ps.setLong(1, article.getBoardId()); - ps.setLong(2, article.getAuthorId()); - ps.setString(3, article.getTitle()); - ps.setString(4, article.getContent()); - return ps; - }, keyHolder); - - // 방금 insert된 row의 id 가져오기 + NULL 처리 - Long id = Objects.requireNonNull(keyHolder.getKey()).longValue(); - - // date까지 채워진 상태를 다시 조회해서 리턴해주기. - return findById(id); - } - // 3. PUT(수정) - @Override - public Article update(Article article){ - String sql = "UPDATE article SET title = ?, content = ?, author_id = ?, board_id = ? WHERE id = ?"; - jdbctemplate.update(sql, - article.getTitle(), - article.getContent(), - article.getAuthorId(), - article.getBoardId(), - article.getId()); - return findById(article.getId()); - } - // 4. DELETE(삭제) - public boolean deleteById(Long id){ - String sql = "DELETE FROM article WHERE id = ?"; - int rows = jdbctemplate.update(sql, id); - - if (rows == 0) { - throw new IllegalArgumentException(id + "번 게시글이 없습니다."); - } - return false; - } - public boolean existsByAuthorId(Long authorId){ - String sql = "select count(*) from article where author_id = ?"; - int count = jdbctemplate.queryForObject(sql, new Object[]{authorId}, Integer.class); - return count > 0; - } - public boolean existsByBoardId(Long boardId){ - String sql = "select count(*) from board where board_id = ?"; - int count = jdbctemplate.queryForObject(sql, new Object[]{boardId}, Integer.class); - return count > 0; - } -} From c8ca0231cba80c9b72cfd8a920e658249e73baad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 00:21:09 +0900 Subject: [PATCH 52/72] =?UTF-8?q?refactor:=20ArticleService=20JPA=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/repository/ArticleRepository.java | 3 +-- .../example/bcsd/service/ArticleService.java | 23 ++++++++++--------- .../example/bcsd/service/BoardService.java | 6 ++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index 82c9e1ec..bedb43f5 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -3,8 +3,7 @@ import com.example.bcsd.domain.Article; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; - public interface ArticleRepository extends JpaRepository { + boolean existsByBoardId(Integer id); } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index f5113df4..abf3879b 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -6,7 +6,6 @@ import com.example.bcsd.exception.InvalidReferenceException; import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.ArticleRepository; -import com.example.bcsd.repository.MemoryArticleRepository; import com.example.bcsd.repository.MemoryMemberRepository; import com.example.bcsd.repository.BoardRepository; @@ -17,12 +16,12 @@ @Service public class ArticleService { - private final MemoryArticleRepository articleRepository; + private final ArticleRepository articleRepository; private final MemoryMemberRepository memberRepository; private final BoardRepository boardRepository; @Autowired - public ArticleService(MemoryArticleRepository articleRepository, + public ArticleService(ArticleRepository articleRepository, MemoryMemberRepository memberRepository, BoardRepository boardRepository) { this.articleRepository = articleRepository; @@ -35,8 +34,9 @@ public List
getAllArticlesByBoard(Long boardId){ return articleRepository.findByBoardId(boardId); } // 1. READ - 하나만 - public Article getOne(Long id){ - return articleRepository.findById(id); + public Article getOne(Integer id){ + return articleRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException(id + "번 게시글이 없습니다."));; } // 2. CREATE public Article create(ArticleDTO req){ @@ -55,10 +55,10 @@ public Article create(ArticleDTO req){ article.setAuthorId(req.getAuthorId()); article.setBoardId(req.getBoardId()); - return articleRepository.insert(article); + return articleRepository.save(article); } // 3. UPDATE - public Article update(ArticleDTO req, Long id){ + public Article update(ArticleDTO req, Integer id){ if (!memberRepository.existsById(req.getAuthorId())) { throw new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId()); } @@ -67,18 +67,19 @@ public Article update(ArticleDTO req, Long id){ throw new InvalidReferenceException("존재하지 않는 게시판입니다. board_id: " + req.getBoardId()); } - Article article = articleRepository.findById(id); + Article article = articleRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException(id + "번 게시글이 없습니다."));; article.setTitle(req.getTitle()); article.setContent(req.getContent()); article.setBoardId(req.getBoardId()); article.setAuthorId(req.getAuthorId()); - return articleRepository.update(article); + return articleRepository.save(article); } // 4. DELETE - public boolean delete(Long id){ - return articleRepository.deleteById(id); + public void delete(Integer id){ + articleRepository.deleteById(id); } private void validateForCreate(ArticleDTO req) { diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index d60b8dd2..9ac9803e 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -4,15 +4,15 @@ import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.BoardRepository; -import com.example.bcsd.repository.MemoryArticleRepository; +import com.example.bcsd.repository.ArticleRepository; import org.springframework.stereotype.Service; @Service public class BoardService { private final BoardRepository boardRepository; - private final MemoryArticleRepository articleRepository; + private final ArticleRepository articleRepository; - public BoardService(BoardRepository boardRepository, MemoryArticleRepository articleRepository) { + public BoardService(BoardRepository boardRepository, ArticleRepository articleRepository) { this.boardRepository = boardRepository; this.articleRepository = articleRepository; } From 5455de27bb6e6f873ba1fe0fc65c731991fc8f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 00:36:43 +0900 Subject: [PATCH 53/72] =?UTF-8?q?fix:=20=EC=9E=90=EC=9E=98=ED=95=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EB=93=A4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 13 +++++-------- .../example/bcsd/controller/BoardController.java | 8 ++------ .../example/bcsd/repository/ArticleRepository.java | 8 ++++++-- .../com/example/bcsd/service/ArticleService.java | 11 +++++++---- .../com/example/bcsd/service/MemberService.java | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index 9fba82a9..b04a2635 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -17,6 +17,7 @@ public class ArticleApiController { public ArticleApiController(ArticleService articleService) { this.articleService = articleService; } + // 1. POST /articles : 게시글 저장하기 @PostMapping public Article create(@RequestBody ArticleDTO req){ // ?? @@ -25,8 +26,7 @@ public Article create(@RequestBody ArticleDTO req){ // ?? // 2. GET /articles?boardId={boardId} : 한 게시판의 모든 article 조회하기 @GetMapping - public List
getAllArticlesByBoard( - @RequestParam(required = false) Long boardId){ + public List
getAllArticlesByBoard(@RequestParam(required = false) Long boardId){ return articleService.getAllArticlesByBoard(boardId); } @@ -46,11 +46,8 @@ public Article update(@PathVariable Long id, // 5. DELETE /articles/{id} : id로 삭제하기 @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { - boolean deleted = articleService.delete(id); - if (deleted) { - return ResponseEntity.noContent().build(); // 204 - } else { - return ResponseEntity.notFound().build(); // 404 - } + articleService.delete(id); + // 예외는 service에서만! + return ResponseEntity.noContent().build(); // 204 } } diff --git a/src/main/java/com/example/bcsd/controller/BoardController.java b/src/main/java/com/example/bcsd/controller/BoardController.java index 3cfc0ce2..0df86aac 100644 --- a/src/main/java/com/example/bcsd/controller/BoardController.java +++ b/src/main/java/com/example/bcsd/controller/BoardController.java @@ -24,11 +24,7 @@ public Board create(@RequestBody BoardDTO req){ // 2. DELETE /boardId/{id} : 게시판 id로 삭제하기 @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { - boolean deleted = boardService.delete(id); - if (deleted) { - return ResponseEntity.noContent().build(); // 204 - } else { - return ResponseEntity.notFound().build(); // 404 - } + boardService.delete(id); + return ResponseEntity.noContent().build(); // 204 } } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index bedb43f5..02e5adb9 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -3,7 +3,11 @@ import com.example.bcsd.domain.Article; import org.springframework.data.jpa.repository.JpaRepository; -public interface ArticleRepository extends JpaRepository { +import java.util.List; - boolean existsByBoardId(Integer id); +public interface ArticleRepository extends JpaRepository { + + boolean existsByBoardId(Long id); + + List
findByBoardId(Long boardId); } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index abf3879b..37d84f85 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -34,9 +34,9 @@ public List
getAllArticlesByBoard(Long boardId){ return articleRepository.findByBoardId(boardId); } // 1. READ - 하나만 - public Article getOne(Integer id){ + public Article getOne(Long id){ return articleRepository.findById(id) - .orElseThrow(() -> new IllegalArgumentException(id + "번 게시글이 없습니다."));; + .orElseThrow(() -> new IllegalArgumentException(id + "번 게시글이 없습니다.")); } // 2. CREATE public Article create(ArticleDTO req){ @@ -58,7 +58,7 @@ public Article create(ArticleDTO req){ return articleRepository.save(article); } // 3. UPDATE - public Article update(ArticleDTO req, Integer id){ + public Article update(ArticleDTO req, Long id){ if (!memberRepository.existsById(req.getAuthorId())) { throw new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId()); } @@ -78,7 +78,10 @@ public Article update(ArticleDTO req, Integer id){ return articleRepository.save(article); } // 4. DELETE - public void delete(Integer id){ + public void delete(Long id){ + if (!articleRepository.existsById(id)) { + throw new IllegalArgumentException(id + "번 게시글이 없습니다."); + } articleRepository.deleteById(id); } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index ff975ee4..81c09e96 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -5,7 +5,7 @@ import com.example.bcsd.exception.DuplicateEmailException; import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.exception.RemainArticlesException; -import com.example.bcsd.repository.MemoryArticleRepository; +import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemoryMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -16,10 +16,10 @@ @Service public class MemberService { private final MemoryMemberRepository memberRepository; - private final MemoryArticleRepository articleRepository; + private final ArticleRepository articleRepository; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemoryMemberRepository memberRepository, MemoryArticleRepository articleRepository) { + public MemberService(MemoryMemberRepository memberRepository, ArticleRepository articleRepository) { this.memberRepository = memberRepository; this.articleRepository = articleRepository; } From 64be0c4470fe4ac5bf16e1000f761aaaed5a697d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 00:56:31 +0900 Subject: [PATCH 54/72] =?UTF-8?q?refactor:=20memberRepository=EA=B5=AC?= =?UTF-8?q?=ED=98=84=EB=B6=80=20=EC=82=AD=EC=A0=9C=20+=20JPA=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/MemberController.java | 11 ++- .../bcsd/repository/MemberRepository.java | 14 ++- .../bcsd/repository/MemberRowMapper.java | 21 ----- .../repository/MemoryMemberRepository.java | 88 ------------------- .../example/bcsd/service/ArticleService.java | 6 +- .../example/bcsd/service/MemberService.java | 20 +++-- 6 files changed, 24 insertions(+), 136 deletions(-) delete mode 100644 src/main/java/com/example/bcsd/repository/MemberRowMapper.java delete mode 100644 src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java diff --git a/src/main/java/com/example/bcsd/controller/MemberController.java b/src/main/java/com/example/bcsd/controller/MemberController.java index 84a31bbf..4e50a6b7 100644 --- a/src/main/java/com/example/bcsd/controller/MemberController.java +++ b/src/main/java/com/example/bcsd/controller/MemberController.java @@ -19,6 +19,7 @@ public class MemberController { public MemberController(MemberService memberService) { this.memberService = memberService; } + // 1. member 생성 @PostMapping public Member create(@RequestBody MemberDTO req) { @@ -35,19 +36,17 @@ public Member update(@PathVariable Long id, // 3. member 삭제 @DeleteMapping("/{id}") public ResponseEntity delete(@PathVariable Long id) { - boolean deleted = memberService.delete(id); - if (deleted) { - return ResponseEntity.noContent().build(); // 204 - } else { - return ResponseEntity.notFound().build(); // 404 - } + memberService.delete(id); + return ResponseEntity.noContent().build(); // 204 } + // 4. member 조회 // 4-1. id로 조회 @GetMapping("/{id}") public Member getOne(@PathVariable Long id) { return memberService.getOne(id); } + // 4-2. name으로 조회 @GetMapping("/search") public List searchByName(@RequestParam String name) { diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index ed79bf7d..ad74f539 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -1,16 +1,12 @@ package com.example.bcsd.repository; import com.example.bcsd.domain.Member; +import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; -import java.util.Optional; -public interface MemberRepository { - Member insert(Member member); - Member update(Member member); - Member findById(Long id); //ID로 회원 정보 가져오기 - List findByName(String name); // 이름으로 회원 정보 가져오기 - List findAll(); // 이름으로 회원 정보 가져오기 +public interface MemberRepository extends JpaRepository { + boolean existsByEmail(String email); - boolean existsById(Long id); - boolean deleteById(Long id); + + List findByName(String name); } diff --git a/src/main/java/com/example/bcsd/repository/MemberRowMapper.java b/src/main/java/com/example/bcsd/repository/MemberRowMapper.java deleted file mode 100644 index facd259c..00000000 --- a/src/main/java/com/example/bcsd/repository/MemberRowMapper.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.bcsd.repository; - -import com.example.bcsd.domain.Member; -import org.springframework.jdbc.core.RowMapper; - -import java.sql.ResultSet; -import java.sql.SQLException; - -public class MemberRowMapper implements RowMapper { - Member member = new Member(); - public Member mapRow(ResultSet rs, int rowNum) throws SQLException { - - // setter - member.setId(rs.getLong("id")); - member.setName(rs.getString("name")); - member.setEmail(rs.getString("email")); - member.setPassword(rs.getString("password")); - - return member; -} -} diff --git a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java b/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java deleted file mode 100644 index 8237777c..00000000 --- a/src/main/java/com/example/bcsd/repository/MemoryMemberRepository.java +++ /dev/null @@ -1,88 +0,0 @@ -package com.example.bcsd.repository; -import com.example.bcsd.domain.Member; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.stereotype.Repository; -import org.springframework.jdbc.support.GeneratedKeyHolder; -import org.springframework.jdbc.support.KeyHolder; -import java.sql.PreparedStatement; -import java.sql.Statement; -import java.util.*; - -@Repository -public class MemoryMemberRepository implements MemberRepository { - private final JdbcTemplate jdbctemplate; - private final MemberRowMapper rowMapper = new MemberRowMapper(); - - public MemoryMemberRepository(JdbcTemplate jdbctemplate) { - this.jdbctemplate = jdbctemplate; - } - - @Override - public Member insert(Member member) { - String sql = "INSERT INTO member (name, email, password)" - + "VALUES (?, ?, ?)"; - KeyHolder keyHolder = new GeneratedKeyHolder(); - - jdbctemplate.update(con -> { - PreparedStatement ps = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); - ps.setString(1, member.getName()); - ps.setString(2, member.getEmail()); - ps.setString(3, member.getPassword()); - return ps; - }, keyHolder); - - Long newId = keyHolder.getKey().longValue(); - return findById(newId); - } - - @Override - public Member update(Member member) { - String sql = "UPDATE member SET name = ?, email = ? , password=? WHERE id = ?"; - jdbctemplate.update(sql, member.getName(), member.getEmail(), member.getPassword(), member.getId()); - return findById(member.getId()); - } - - @Override - public Member findById(Long id) { - String sql = "SELECT * FROM member WHERE id = ?"; - return jdbctemplate.queryForObject(sql, new MemberRowMapper(), id); - } - - @Override - public List findByName(String name) { // 동명이인 발생 가능 - String sql = "SELECT * FROM member where name = ?"; - return jdbctemplate.query(sql, rowMapper, name); - } - - @Override - public boolean existsByEmail(String email) { - String sql = "SELECT COUNT(*) FROM member WHERE email = ?"; - Integer count = jdbctemplate.queryForObject(sql, Integer.class, email); - return count != null && count > 0; - } - - @Override - public boolean existsById(Long id) { - String sql = "SELECT COUNT(*) FROM member WHERE id = ?"; - Integer count = jdbctemplate.queryForObject(sql, Integer.class, id); - return count != null && count > 0; - } - - @Override - public List findAll() { - String sql = "SELECT * FROM member"; - return jdbctemplate.query(sql, rowMapper); - } - - @Override - public boolean deleteById(Long id){ - String sql = "DELETE FROM article WHERE id = ?"; - int rows = jdbctemplate.update(sql, id); - - if (rows == 0) { - throw new IllegalArgumentException(id + "번 사용자가 존재하지 않습니다."); - } - return false; - } - -} diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 37d84f85..fced7379 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -6,7 +6,7 @@ import com.example.bcsd.exception.InvalidReferenceException; import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.ArticleRepository; -import com.example.bcsd.repository.MemoryMemberRepository; +import com.example.bcsd.repository.MemberRepository; import com.example.bcsd.repository.BoardRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -17,12 +17,12 @@ @Service public class ArticleService { private final ArticleRepository articleRepository; - private final MemoryMemberRepository memberRepository; + private final MemberRepository memberRepository; private final BoardRepository boardRepository; @Autowired public ArticleService(ArticleRepository articleRepository, - MemoryMemberRepository memberRepository, + MemberRepository memberRepository, BoardRepository boardRepository) { this.articleRepository = articleRepository; this.memberRepository = memberRepository; diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 81c09e96..112bab49 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -6,7 +6,7 @@ import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.ArticleRepository; -import com.example.bcsd.repository.MemoryMemberRepository; +import com.example.bcsd.repository.MemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -15,11 +15,11 @@ @Service public class MemberService { - private final MemoryMemberRepository memberRepository; + private final MemberRepository memberRepository; private final ArticleRepository articleRepository; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemoryMemberRepository memberRepository, ArticleRepository articleRepository) { + public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository) { this.memberRepository = memberRepository; this.articleRepository = articleRepository; } @@ -32,11 +32,12 @@ public Member create(MemberDTO req) { member.setEmail(req.getEmail()); member.setPassword(req.getPassword()); - return memberRepository.insert(member); + return memberRepository.save(member); } public Member update(MemberDTO req, Long id) { - Member member = memberRepository.findById(id); + Member member = memberRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException(id + "번 유저는 존재하지 않습니다.")); if (memberRepository.existsByEmail(req.getEmail()) && !member.getEmail().equals(req.getEmail())) { @@ -47,22 +48,23 @@ public Member update(MemberDTO req, Long id) { member.setEmail(req.getEmail()); member.setPassword(req.getPassword()); - return memberRepository.update(member); + return memberRepository.save(member); } public Member getOne(Long id) { - return memberRepository.findById(id); + return memberRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("존재하지 않는 유저 id입니다.")); } public List searchByName(String name) { return memberRepository.findByName(name); } - public boolean delete(Long id) { + public void delete(Long id) { if (articleRepository.existsByBoardId(id)){ throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); } - return memberRepository.deleteById(id); + memberRepository.deleteById(id); } private void validateForCreate(MemberDTO req) { From 0a4351b2e91738d4ae0514d0ce12bfeac2df329c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 10:33:37 +0900 Subject: [PATCH 55/72] =?UTF-8?q?JPARepository=20->=20entityManager?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=ED=95=98=EA=B8=B0=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20=EC=BB=A4=EB=B0=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/service/BoardService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index 9ac9803e..0444382e 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -35,7 +35,6 @@ public void delete(Long id) { } private void validateForCreate(BoardDTO req) { - if (req.getTitle() == null || req.getTitle().isBlank()) { throw new MissingFieldException("title은 null일 수 없습니다."); } From 8f37f467728f619fe2d6a0dc110b229066d5575c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 20:33:48 +0900 Subject: [PATCH 56/72] =?UTF-8?q?feat:=20article=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EC=97=90=20=EC=97=B0=EA=B4=80=EA=B4=80=EA=B3=84=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Article.java | 20 ++++++++++--------- .../bcsd/repository/MemberRepository.java | 6 +++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index 1ef2e5f4..f24ce11b 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -1,9 +1,6 @@ package com.example.bcsd.domain; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -15,15 +12,20 @@ @Table(name = "article") public class Article { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @JsonProperty("author_id") - private Long authorId; - - @JsonProperty("board_id") - private Long boardId; private String title; private String content; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "author_id", nullable = false) + private Member authorId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "board_id", nullable = false) + private Board boardId; + private LocalDateTime updatedAt; private LocalDateTime createdAt; diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index ad74f539..858319ce 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -1,12 +1,12 @@ package com.example.bcsd.repository; + import com.example.bcsd.domain.Member; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; +import java.util.Optional; -public interface MemberRepository extends JpaRepository { - +public interface MemberRepository extends JpaRepository { boolean existsByEmail(String email); - List findByName(String name); } From 9103f745e1a1682649d94658868c80daf1784130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 21:40:58 +0900 Subject: [PATCH 57/72] =?UTF-8?q?feat:=20board=20=EC=97=94=ED=8B=B0?= =?UTF-8?q?=ED=8B=B0=EC=97=90=20=EC=97=B0=EA=B4=80=EA=B4=80=EA=B3=84+?= =?UTF-8?q?=EB=B6=80=EB=AA=A8=20=EB=A7=A4=ED=95=91,=20=EC=98=81=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Article.java | 10 ++++++++-- .../java/com/example/bcsd/domain/Board.java | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index f24ce11b..a77ce2bf 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -20,14 +20,20 @@ public class Article { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "author_id", nullable = false) - private Member authorId; + private Member author; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "board_id", nullable = false) - private Board boardId; + private Board board; private LocalDateTime updatedAt; private LocalDateTime createdAt; public Article(){} + public Article(Member author, Board board, String title, String content) { + this.title = title; + this.content = content; + this.author = author; + this.board = board; + } } diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index 414aa588..362b544e 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -1,11 +1,12 @@ package com.example.bcsd.domain; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; +import java.util.ArrayList; +import java.util.List; + @Setter @Getter @Entity @@ -14,4 +15,15 @@ public class Board { @Id private Long id; private String title; // 게시판 이름 + + // 부모 선언 (+ 양방향 매핑(역방향 조회 편의성↑)) + @OneToMany(mappedBy = "board", // 연관관계의 주인은 Article.board + cascade = CascadeType.ALL, // 부모의 영속성을 자식(Article)에게도 + orphanRemoval = true) // 고아 객체 제거 옵션 활성화 + private List
articles = new ArrayList<>(); + + public Board(){} + public Board(String title) { + this.title = title; + } } From 37b4ea3b37df93bfba4550cc159e07d76b7abb42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 21:43:57 +0900 Subject: [PATCH 58/72] =?UTF-8?q?feat:=20member=EC=97=94=ED=8B=B0=ED=8B=B0?= =?UTF-8?q?=EC=97=90=20=EC=96=91=EB=B0=A9=ED=96=A5=20=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/domain/Member.java | 14 +++++++------- .../example/bcsd/repository/ArticleRepository.java | 2 -- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 070a87a5..2e941bfb 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -1,12 +1,12 @@ package com.example.bcsd.domain; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; +import java.util.ArrayList; +import java.util.List; + @Setter @Getter @Entity @@ -15,10 +15,10 @@ public class Member { @Id @Column(name = "ID") private Long id; - @Column(name = "name") private String name; - @Column(name = "email") private String email; - @Column(name = "password") private String password; + + @OneToMany(mappedBy = "author") + private List
articles = new ArrayList<>(); } diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index 02e5adb9..a847da07 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -6,8 +6,6 @@ import java.util.List; public interface ArticleRepository extends JpaRepository { - boolean existsByBoardId(Long id); - List
findByBoardId(Long boardId); } From 2af9bcdc9bc7c1fa9dbc28bb9b1fe5ec75c085a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 22:10:44 +0900 Subject: [PATCH 59/72] =?UTF-8?q?refactor:=20JPA=EC=99=80=20=EB=B6=80?= =?UTF-8?q?=EB=AA=A8-=EC=9E=90=EC=8B=9D=EC=97=90=20=EB=A7=9E=EA=B2=8C=20se?= =?UTF-8?q?rvice=20=EB=B0=8F=20controller=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/domain/Article.java | 2 ++ .../java/com/example/bcsd/domain/Board.java | 12 ++++++++++ .../java/com/example/bcsd/domain/Member.java | 1 + .../bcsd/repository/ArticleRepository.java | 1 + .../example/bcsd/service/ArticleService.java | 22 +++++++++---------- .../example/bcsd/service/BoardService.java | 4 +--- .../example/bcsd/service/MemberService.java | 4 ++-- 7 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/example/bcsd/domain/Article.java b/src/main/java/com/example/bcsd/domain/Article.java index a77ce2bf..e6fce2d9 100644 --- a/src/main/java/com/example/bcsd/domain/Article.java +++ b/src/main/java/com/example/bcsd/domain/Article.java @@ -36,4 +36,6 @@ public Article(Member author, Board board, String title, String content) { this.author = author; this.board = board; } + + } diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index 362b544e..f8f06ec0 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -13,6 +13,7 @@ @Table(name = "board") public class Board { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String title; // 게시판 이름 @@ -26,4 +27,15 @@ public Board(){} public Board(String title) { this.title = title; } + + // 연관관계 편의 메서드 + public void addArticle(Article article) { + articles.add(article); + article.setBoard(this); + } + + public void removeArticle(Article article) { + articles.remove(article); + article.setBoard(null); + } } diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 2e941bfb..95d940e3 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -13,6 +13,7 @@ @Table(name = "member") public class Member { @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "ID") private Long id; private String name; diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index a847da07..f6233263 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -7,5 +7,6 @@ public interface ArticleRepository extends JpaRepository { boolean existsByBoardId(Long id); + boolean existsByAuthorId(Long authorId); List
findByBoardId(Long boardId); } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index fced7379..bde3c479 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -1,6 +1,8 @@ package com.example.bcsd.service; import com.example.bcsd.domain.Article; +import com.example.bcsd.domain.Board; +import com.example.bcsd.domain.Member; import com.example.bcsd.dto.ArticleDTO; import com.example.bcsd.exception.InvalidReferenceException; @@ -41,22 +43,21 @@ public Article getOne(Long id){ // 2. CREATE public Article create(ArticleDTO req){ validateForCreate(req); - if (!memberRepository.existsById(req.getAuthorId())) { - throw new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId()); - } + Member author = memberRepository.findById(req.getAuthorId()) + .orElseThrow(() -> new InvalidReferenceException("존재하지 않는 사용자입니다. author_id: " + req.getAuthorId())); - if (!boardRepository.existsById(req.getBoardId())) { - throw new InvalidReferenceException("존재하지 않는 게시판입니다. board_id: " + req.getBoardId()); - } + Board board = boardRepository.findById(req.getBoardId()) + .orElseThrow(() -> new InvalidReferenceException("존재하지 않는 게시판입니다. board_id: " + req.getBoardId())); Article article = new Article(); article.setTitle(req.getTitle()); article.setContent(req.getContent()); - article.setAuthorId(req.getAuthorId()); - article.setBoardId(req.getBoardId()); + article.setAuthor(author); - return articleRepository.save(article); + boardRepository.save(board); + return article; } + // 3. UPDATE public Article update(ArticleDTO req, Long id){ if (!memberRepository.existsById(req.getAuthorId())) { @@ -72,8 +73,6 @@ public Article update(ArticleDTO req, Long id){ article.setTitle(req.getTitle()); article.setContent(req.getContent()); - article.setBoardId(req.getBoardId()); - article.setAuthorId(req.getAuthorId()); return articleRepository.save(article); } @@ -103,5 +102,4 @@ private void validateForCreate(ArticleDTO req) { throw new MissingFieldException("boardId는 null일 수 없습니다."); } } - } diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index 0444382e..b809da70 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -28,9 +28,7 @@ public Board create(BoardDTO req) { } public void delete(Long id) { - if (articleRepository.existsByBoardId(id)){ - throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. board_id =" + id); - } + // 이제 게시판에 게시글이 남아있어도 삭제 가능(부모-자식) boardRepository.deleteById(id); } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 112bab49..0b35663b 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -61,8 +61,8 @@ public List searchByName(String name) { } public void delete(Long id) { - if (articleRepository.existsByBoardId(id)){ - throw new RemainArticlesException("게시판에 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); + if (articleRepository.existsByAuthorId(id)){ + throw new RemainArticlesException("회원이 작성한 게시글이 남아있어 삭제가 불가능합니다. member_id =" + id); } memberRepository.deleteById(id); } From fc7492545fbb64f19d4aa0ef46572e2e1021aa1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 22:27:40 +0900 Subject: [PATCH 60/72] =?UTF-8?q?feat:=20jsonIgnore=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/controller/BoardController.java | 1 + src/main/java/com/example/bcsd/domain/Board.java | 2 ++ src/main/java/com/example/bcsd/domain/Member.java | 2 ++ 3 files changed, 5 insertions(+) diff --git a/src/main/java/com/example/bcsd/controller/BoardController.java b/src/main/java/com/example/bcsd/controller/BoardController.java index 0df86aac..95cba5ac 100644 --- a/src/main/java/com/example/bcsd/controller/BoardController.java +++ b/src/main/java/com/example/bcsd/controller/BoardController.java @@ -27,4 +27,5 @@ public ResponseEntity delete(@PathVariable Long id) { boardService.delete(id); return ResponseEntity.noContent().build(); // 204 } + } diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index f8f06ec0..39d6a597 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -1,5 +1,6 @@ package com.example.bcsd.domain; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -21,6 +22,7 @@ public class Board { @OneToMany(mappedBy = "board", // 연관관계의 주인은 Article.board cascade = CascadeType.ALL, // 부모의 영속성을 자식(Article)에게도 orphanRemoval = true) // 고아 객체 제거 옵션 활성화 + @JsonIgnore private List
articles = new ArrayList<>(); public Board(){} diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index 95d940e3..e922a2d8 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -1,5 +1,6 @@ package com.example.bcsd.domain; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -21,5 +22,6 @@ public class Member { private String password; @OneToMany(mappedBy = "author") + @JsonIgnore private List
articles = new ArrayList<>(); } From 80d0c448b58a420f484f191512dcf02e6627f8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Mon, 5 Jan 2026 22:56:25 +0900 Subject: [PATCH 61/72] =?UTF-8?q?feat:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/ArticleApiController.java | 10 +++++- .../bcsd/controller/BoardController.java | 9 ++++- .../java/com/example/bcsd/domain/Board.java | 2 ++ .../java/com/example/bcsd/domain/Member.java | 2 ++ .../java/com/example/bcsd/dto/ArticleDTO.java | 36 +++---------------- .../com/example/bcsd/dto/ArticleResponse.java | 21 +++++++++++ .../java/com/example/bcsd/dto/BoardDTO.java | 13 +++---- .../com/example/bcsd/dto/BoardResponse.java | 12 +++++++ .../java/com/example/bcsd/dto/MemberDTO.java | 12 +++---- .../example/bcsd/service/BoardService.java | 8 +++-- 10 files changed, 74 insertions(+), 51 deletions(-) create mode 100644 src/main/java/com/example/bcsd/dto/ArticleResponse.java create mode 100644 src/main/java/com/example/bcsd/dto/BoardResponse.java diff --git a/src/main/java/com/example/bcsd/controller/ArticleApiController.java b/src/main/java/com/example/bcsd/controller/ArticleApiController.java index b04a2635..6e69f02c 100644 --- a/src/main/java/com/example/bcsd/controller/ArticleApiController.java +++ b/src/main/java/com/example/bcsd/controller/ArticleApiController.java @@ -3,6 +3,7 @@ import com.example.bcsd.domain.Article; import com.example.bcsd.dto.ArticleDTO; +import com.example.bcsd.dto.ArticleResponse; import com.example.bcsd.service.ArticleService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -29,7 +30,13 @@ public Article create(@RequestBody ArticleDTO req){ // ?? public List
getAllArticlesByBoard(@RequestParam(required = false) Long boardId){ return articleService.getAllArticlesByBoard(boardId); } - + @GetMapping("/by-board") + public List getByBoard(@RequestParam Long boardId) { + return articleService.getAllArticlesByBoard(boardId) + .stream() + .map(ArticleResponse::from) + .toList(); + } // 3. GET /articles/{id} : 아이디로 article 찾기 @GetMapping("/{id}") public Article getOne(@PathVariable Long id){ @@ -50,4 +57,5 @@ public ResponseEntity delete(@PathVariable Long id) { // 예외는 service에서만! return ResponseEntity.noContent().build(); // 204 } + } diff --git a/src/main/java/com/example/bcsd/controller/BoardController.java b/src/main/java/com/example/bcsd/controller/BoardController.java index 95cba5ac..08609236 100644 --- a/src/main/java/com/example/bcsd/controller/BoardController.java +++ b/src/main/java/com/example/bcsd/controller/BoardController.java @@ -2,6 +2,7 @@ import com.example.bcsd.domain.Board; import com.example.bcsd.dto.BoardDTO; +import com.example.bcsd.dto.BoardResponse; import com.example.bcsd.service.BoardService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -27,5 +28,11 @@ public ResponseEntity delete(@PathVariable Long id) { boardService.delete(id); return ResponseEntity.noContent().build(); // 204 } - + + // 3. GET /board/{id} : 게시판 id로 게시글 조회하기 + @GetMapping("/{id}") + public BoardResponse getOne(@PathVariable Long id) { +// return boardService.getOne(id); + return BoardResponse.from(boardService.getOne(id)); + } } diff --git a/src/main/java/com/example/bcsd/domain/Board.java b/src/main/java/com/example/bcsd/domain/Board.java index 39d6a597..1dc62e34 100644 --- a/src/main/java/com/example/bcsd/domain/Board.java +++ b/src/main/java/com/example/bcsd/domain/Board.java @@ -1,6 +1,7 @@ package com.example.bcsd.domain; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -8,6 +9,7 @@ import java.util.ArrayList; import java.util.List; +@JsonIgnoreProperties({"articles"}) @Setter @Getter @Entity diff --git a/src/main/java/com/example/bcsd/domain/Member.java b/src/main/java/com/example/bcsd/domain/Member.java index e922a2d8..85150bdd 100644 --- a/src/main/java/com/example/bcsd/domain/Member.java +++ b/src/main/java/com/example/bcsd/domain/Member.java @@ -1,6 +1,7 @@ package com.example.bcsd.domain; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -8,6 +9,7 @@ import java.util.ArrayList; import java.util.List; +@JsonIgnoreProperties({"articles"}) @Setter @Getter @Entity diff --git a/src/main/java/com/example/bcsd/dto/ArticleDTO.java b/src/main/java/com/example/bcsd/dto/ArticleDTO.java index 275f201d..316b56f3 100644 --- a/src/main/java/com/example/bcsd/dto/ArticleDTO.java +++ b/src/main/java/com/example/bcsd/dto/ArticleDTO.java @@ -1,7 +1,11 @@ package com.example.bcsd.dto; import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; +@Setter +@Getter public class ArticleDTO { private String title; private String content; @@ -11,36 +15,4 @@ public class ArticleDTO { @JsonProperty("author_id") private Long authorId; - // getter와 setter - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getContent() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - public Long getAuthorId() { - return authorId; - } - - public void setAuthorId(Long authorId) { - this.authorId = authorId; - } - - public Long getBoardId() { - return boardId; - } - - public void setBoardId(Long boardId) { - this.boardId = boardId; - } } diff --git a/src/main/java/com/example/bcsd/dto/ArticleResponse.java b/src/main/java/com/example/bcsd/dto/ArticleResponse.java new file mode 100644 index 00000000..dc6ce614 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/ArticleResponse.java @@ -0,0 +1,21 @@ +package com.example.bcsd.dto; + +import com.example.bcsd.domain.Article; + +public record ArticleResponse( + Long id, + String title, + String content, + Long boardId, + Long authorId +) { + public static ArticleResponse from(Article a) { + return new ArticleResponse( + a.getId(), + a.getTitle(), + a.getContent(), + a.getBoard() != null ? a.getBoard().getId() : null, + a.getAuthor() != null ? a.getAuthor().getId() : null + ); + } +} diff --git a/src/main/java/com/example/bcsd/dto/BoardDTO.java b/src/main/java/com/example/bcsd/dto/BoardDTO.java index ffb94e16..9a27a508 100644 --- a/src/main/java/com/example/bcsd/dto/BoardDTO.java +++ b/src/main/java/com/example/bcsd/dto/BoardDTO.java @@ -1,13 +1,10 @@ package com.example.bcsd.dto; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter public class BoardDTO { private String title; // 게시판 이름 - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } } diff --git a/src/main/java/com/example/bcsd/dto/BoardResponse.java b/src/main/java/com/example/bcsd/dto/BoardResponse.java new file mode 100644 index 00000000..d4d5cc39 --- /dev/null +++ b/src/main/java/com/example/bcsd/dto/BoardResponse.java @@ -0,0 +1,12 @@ +package com.example.bcsd.dto; + +import com.example.bcsd.domain.Board; + +public record BoardResponse( + Long id, + String title +) { + public static BoardResponse from(Board b) { + return new BoardResponse(b.getId(), b.getTitle()); + } +} diff --git a/src/main/java/com/example/bcsd/dto/MemberDTO.java b/src/main/java/com/example/bcsd/dto/MemberDTO.java index 252e3af3..5530b3e4 100644 --- a/src/main/java/com/example/bcsd/dto/MemberDTO.java +++ b/src/main/java/com/example/bcsd/dto/MemberDTO.java @@ -1,15 +1,13 @@ package com.example.bcsd.dto; +import lombok.Getter; +import lombok.Setter; + +@Setter +@Getter public class MemberDTO { private String name; private String email; private String password; - public String getName() { return name; } - public String getEmail() { return email; } - public String getPassword() { return password; } - - public void setName(String name) { this.name = name; } - public void setEmail(String email) { this.email = email; } - public void setPassword(String password) { this.password = password; } } diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index b809da70..ed8b0b44 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -5,16 +5,15 @@ import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.BoardRepository; import com.example.bcsd.repository.ArticleRepository; +import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; @Service public class BoardService { private final BoardRepository boardRepository; - private final ArticleRepository articleRepository; public BoardService(BoardRepository boardRepository, ArticleRepository articleRepository) { this.boardRepository = boardRepository; - this.articleRepository = articleRepository; } public Board create(BoardDTO req) { @@ -43,4 +42,9 @@ public String getBoardName(Long boardId) { .orElseThrow(() -> new IllegalArgumentException(boardId + "번 게시판이 없습니다.")); return board.getTitle(); } + + public Board getOne(Long id) { + return boardRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException(id + "번 게시판이 없습니다.")); + } } From 98bab1592a5b30e779f3e77d2595d932dee32f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Wed, 14 Jan 2026 16:01:40 +0900 Subject: [PATCH 62/72] Initial commit --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..f745dd8d --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# BCSD_BackEnd25-2-week10 +비기너 10주차까지의 과제 백업 From 709f5b78cd1774b9adef2035ba69886362af1a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Wed, 14 Jan 2026 16:04:11 +0900 Subject: [PATCH 63/72] =?UTF-8?q?feat:=2010=EC=A3=BC=EC=B0=A8=EA=B9=8C?= =?UTF-8?q?=EC=A7=80=EC=9D=98=20=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/bcsd/repository/ArticleRepository.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/repository/ArticleRepository.java b/src/main/java/com/example/bcsd/repository/ArticleRepository.java index f6233263..9d443465 100644 --- a/src/main/java/com/example/bcsd/repository/ArticleRepository.java +++ b/src/main/java/com/example/bcsd/repository/ArticleRepository.java @@ -6,7 +6,6 @@ import java.util.List; public interface ArticleRepository extends JpaRepository { - boolean existsByBoardId(Long id); boolean existsByAuthorId(Long authorId); List
findByBoardId(Long boardId); } From b55b520192030747cbc00e607bb5148fb2530f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Wed, 14 Jan 2026 23:32:19 +0900 Subject: [PATCH 64/72] =?UTF-8?q?feat:=20brypt=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +-- src/main/java/com/example/bcsd/service/MemberService.java | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 7d35d42c..e3d14c19 100644 --- a/build.gradle +++ b/build.gradle @@ -23,6 +23,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-jdbc' implementation 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + implementation 'org.springframework.boot:spring-boot-starter-security' compileOnly 'org.projectlombok:lombok:1.18.38' annotationProcessor 'org.projectlombok:lombok' @@ -33,5 +34,3 @@ dependencies { tasks.named('test') { useJUnitPlatform() } - -def void plugins(Closure pluginDependencySpecClosure) {} diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 0b35663b..770c793d 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -7,6 +7,7 @@ import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemberRepository; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -30,8 +31,8 @@ public Member create(MemberDTO req) { Member member = new Member(); member.setName(req.getName()); member.setEmail(req.getEmail()); - member.setPassword(req.getPassword()); - + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + member.setPassword(passwordEncoder.encode(req.getPassword())); return memberRepository.save(member); } @@ -81,7 +82,4 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } - private void validateForDelete(MemberDTO req) { - - } } From 73f2cca4dcc93995c6eb3275bde49132e4dc1880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Wed, 14 Jan 2026 23:53:46 +0900 Subject: [PATCH 65/72] =?UTF-8?q?feat:=20bcrypt=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=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/com/example/bcsd/service/MemberService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 770c793d..b0364af0 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -82,4 +82,5 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } + } From da2d39eb6df4db93821aeb93b763e5f7a482311d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Wed, 14 Jan 2026 23:54:50 +0900 Subject: [PATCH 66/72] =?UTF-8?q?feat:=20bcrypt=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=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/com/example/bcsd/service/MemberService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index b0364af0..770c793d 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -82,5 +82,4 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } - } From 8cbe136ddf23f9e8a72cef6a3ddb310715380190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Thu, 15 Jan 2026 00:08:21 +0900 Subject: [PATCH 67/72] =?UTF-8?q?refactor:=20bcrypt=EB=A5=BC=20bean?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/bcsd/config/SecurityConfig.java | 14 ++++++++++++++ .../com/example/bcsd/service/MemberService.java | 6 ++++-- 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/bcsd/config/SecurityConfig.java diff --git a/src/main/java/com/example/bcsd/config/SecurityConfig.java b/src/main/java/com/example/bcsd/config/SecurityConfig.java new file mode 100644 index 00000000..e479f126 --- /dev/null +++ b/src/main/java/com/example/bcsd/config/SecurityConfig.java @@ -0,0 +1,14 @@ +package com.example.bcsd.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +@Configuration +public class SecurityConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 770c793d..578b1e79 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -9,6 +9,7 @@ import com.example.bcsd.repository.MemberRepository; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; @@ -18,11 +19,13 @@ public class MemberService { private final MemberRepository memberRepository; private final ArticleRepository articleRepository; + private final PasswordEncoder passwordEncoder; @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository) { + public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository, PasswordEncoder passwordEncoder) { this.memberRepository = memberRepository; this.articleRepository = articleRepository; + this.passwordEncoder = passwordEncoder; } public Member create(MemberDTO req) { @@ -31,7 +34,6 @@ public Member create(MemberDTO req) { Member member = new Member(); member.setName(req.getName()); member.setEmail(req.getEmail()); - BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); member.setPassword(passwordEncoder.encode(req.getPassword())); return memberRepository.save(member); } From 4fc91c860a7678d05160c635c28d5268e63b96aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Thu, 15 Jan 2026 00:33:31 +0900 Subject: [PATCH 68/72] =?UTF-8?q?feat:=20login()=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/bcsd/dto/MemberDTO.java | 1 - .../bcsd/repository/MemberRepository.java | 1 + .../com/example/bcsd/service/MemberService.java | 17 +++++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/bcsd/dto/MemberDTO.java b/src/main/java/com/example/bcsd/dto/MemberDTO.java index 5530b3e4..6dabf35c 100644 --- a/src/main/java/com/example/bcsd/dto/MemberDTO.java +++ b/src/main/java/com/example/bcsd/dto/MemberDTO.java @@ -9,5 +9,4 @@ public class MemberDTO { private String name; private String email; private String password; - } diff --git a/src/main/java/com/example/bcsd/repository/MemberRepository.java b/src/main/java/com/example/bcsd/repository/MemberRepository.java index 858319ce..b946a665 100644 --- a/src/main/java/com/example/bcsd/repository/MemberRepository.java +++ b/src/main/java/com/example/bcsd/repository/MemberRepository.java @@ -9,4 +9,5 @@ public interface MemberRepository extends JpaRepository { boolean existsByEmail(String email); List findByName(String name); + Optional findByEmail(String email); } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 578b1e79..91261b98 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -7,12 +7,12 @@ import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemberRepository; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; +import java.util.Optional; @Service @@ -49,7 +49,7 @@ public Member update(MemberDTO req, Long id) { member.setName(req.getName()); member.setEmail(req.getEmail()); - member.setPassword(req.getPassword()); + member.setPassword(passwordEncoder.encode(req.getPassword())); // 암호화로 변경 return memberRepository.save(member); } @@ -84,4 +84,17 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } + private Member login(MemberDTO req) { + String email = req.getEmail(); + String password = req.getPassword(); + if (email == null || email.isBlank()) { throw new MissingFieldException("email은 null일수 없습니다.");} + if (password == null || password.isBlank()) { throw new MissingFieldException("password는 null일수 없습니다.");} + + Member member = memberRepository.findByEmail(email) + .orElseThrow(() -> new IllegalArgumentException("이메일 또는 비밀번호를 다시 확인해주세요.")); + if (!passwordEncoder.matches(password, member.getPassword())) { + throw new IllegalArgumentException("이메일 또는 비밀번호를 다시 확인해주세요."); + } + return member; + } } From b67e4f9ba97b30309494cd81b3798c8d176083d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Thu, 15 Jan 2026 00:55:04 +0900 Subject: [PATCH 69/72] =?UTF-8?q?feat:=20AuthController=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/bcsd/config/SecurityConfig.java | 18 +++++++++++++ .../bcsd/controller/AuthController.java | 26 +++++++++++++++++++ src/main/java/com/example/bcsd/login.http | 8 ++++++ .../example/bcsd/service/MemberService.java | 2 +- 4 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/bcsd/controller/AuthController.java create mode 100644 src/main/java/com/example/bcsd/login.http diff --git a/src/main/java/com/example/bcsd/config/SecurityConfig.java b/src/main/java/com/example/bcsd/config/SecurityConfig.java index e479f126..77234474 100644 --- a/src/main/java/com/example/bcsd/config/SecurityConfig.java +++ b/src/main/java/com/example/bcsd/config/SecurityConfig.java @@ -2,7 +2,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.web.SecurityFilterChain; @Configuration public class SecurityConfig { @@ -11,4 +15,18 @@ public class SecurityConfig { public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(csrf -> csrf.disable()) // JWT 사용하므로 비활성화 + .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/auth/**").permitAll() // 로그인/회원가입은 열어두어야 접근 가능함... + .anyRequest().authenticated() + ) + .httpBasic(AbstractHttpConfigurer::disable); // Basic Auth 끄기 + + return http.build(); + } } diff --git a/src/main/java/com/example/bcsd/controller/AuthController.java b/src/main/java/com/example/bcsd/controller/AuthController.java new file mode 100644 index 00000000..6ec0c4d3 --- /dev/null +++ b/src/main/java/com/example/bcsd/controller/AuthController.java @@ -0,0 +1,26 @@ +package com.example.bcsd.controller; + +import com.example.bcsd.dto.MemberDTO; +import com.example.bcsd.service.MemberService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/auth") +public class AuthController { + + private final MemberService memberService; + + public AuthController(MemberService memberService) { + this.memberService = memberService; + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody MemberDTO req) { + memberService.login(req); + return ResponseEntity.ok("login success"); + } +} diff --git a/src/main/java/com/example/bcsd/login.http b/src/main/java/com/example/bcsd/login.http new file mode 100644 index 00000000..2f51051a --- /dev/null +++ b/src/main/java/com/example/bcsd/login.http @@ -0,0 +1,8 @@ +### 로그인 테스트 +POST http://localhost:8080/auth/login +Content-Type: application/json + +{ + "email": "test@test.com", + "password": "1234" +} diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 91261b98..4d3ec4f8 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -84,7 +84,7 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } - private Member login(MemberDTO req) { + public Member login(MemberDTO req) { String email = req.getEmail(); String password = req.getPassword(); if (email == null || email.isBlank()) { throw new MissingFieldException("email은 null일수 없습니다.");} From 0feaa1721e333df95067046988e294fe0a1cf85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Thu, 15 Jan 2026 01:21:51 +0900 Subject: [PATCH 70/72] =?UTF-8?q?feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EB=B0=8F=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bcsd/controller/AuthController.java | 6 +++++ src/main/java/com/example/bcsd/login.http | 4 ++-- .../example/bcsd/service/MemberService.java | 24 +++++++++++++++++++ src/main/java/com/example/bcsd/signup.http | 9 +++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/bcsd/signup.http diff --git a/src/main/java/com/example/bcsd/controller/AuthController.java b/src/main/java/com/example/bcsd/controller/AuthController.java index 6ec0c4d3..e161243f 100644 --- a/src/main/java/com/example/bcsd/controller/AuthController.java +++ b/src/main/java/com/example/bcsd/controller/AuthController.java @@ -23,4 +23,10 @@ public ResponseEntity login(@RequestBody MemberDTO req) { memberService.login(req); return ResponseEntity.ok("login success"); } + + @PostMapping("/signup") + public ResponseEntity signup(@RequestBody MemberDTO req) { + memberService.signup(req); + return ResponseEntity.ok("signup success"); + } } diff --git a/src/main/java/com/example/bcsd/login.http b/src/main/java/com/example/bcsd/login.http index 2f51051a..c521e5b4 100644 --- a/src/main/java/com/example/bcsd/login.http +++ b/src/main/java/com/example/bcsd/login.http @@ -3,6 +3,6 @@ POST http://localhost:8080/auth/login Content-Type: application/json { - "email": "test@test.com", - "password": "1234" + "email": "haein1234@abc.com", + "password": "123" } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 4d3ec4f8..9b0688a3 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -97,4 +97,28 @@ public Member login(MemberDTO req) { } return member; } + + public Member signup(MemberDTO req) { + Member member = new Member(); + + String name = req.getName(); + String email = req.getEmail(); + String password = passwordEncoder.encode(req.getPassword()); + + // 이메일 중복 체크 + if (memberRepository.existsByEmail(email)) { + throw new DuplicateEmailException("이미 사용 중인 이메일입니다."); + } + + // 필드 빈칸 체크 + if (name == null || name.isBlank()) { throw new MissingFieldException("name은 null일 수 없습니다.");} + if (email == null || email.isBlank()) { throw new MissingFieldException("email은 null일 수 없습니다.");} + if (password == null || password.isBlank()) { throw new MissingFieldException("password은 null일 수 없습니다.");} + + member.setName(name); + member.setEmail(email); + member.setPassword(password); + + return memberRepository.save(member); + } } diff --git a/src/main/java/com/example/bcsd/signup.http b/src/main/java/com/example/bcsd/signup.http new file mode 100644 index 00000000..b4d64237 --- /dev/null +++ b/src/main/java/com/example/bcsd/signup.http @@ -0,0 +1,9 @@ +### 회원가입 테스트 +POST http://localhost:8080/auth/signup +Content-Type: application/json + +{ + "name": "haein", + "email": "haein1234@abc.com", + "password": "123" +} From 07d590b49cf2a0ef85f386c2ffbfd142554a80a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Thu, 15 Jan 2026 22:45:25 +0900 Subject: [PATCH 71/72] =?UTF-8?q?refactor:=20@RequiredArgsConstructor=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++ .../example/bcsd/config/SecurityConfig.java | 36 +++++++++++++++++-- .../example/bcsd/service/ArticleService.java | 14 ++------ .../example/bcsd/service/BoardService.java | 3 +- .../example/bcsd/service/MemberService.java | 19 +++------- 5 files changed, 45 insertions(+), 30 deletions(-) diff --git a/build.gradle b/build.gradle index e3d14c19..457d4247 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,9 @@ dependencies { implementation 'com.mysql:mysql-connector-j' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'io.jsonwebtoken:jjwt-api:0.12.3' + implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' + implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' compileOnly 'org.projectlombok:lombok:1.18.38' annotationProcessor 'org.projectlombok:lombok' diff --git a/src/main/java/com/example/bcsd/config/SecurityConfig.java b/src/main/java/com/example/bcsd/config/SecurityConfig.java index 77234474..81b2b85f 100644 --- a/src/main/java/com/example/bcsd/config/SecurityConfig.java +++ b/src/main/java/com/example/bcsd/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.example.bcsd.config; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -7,7 +8,13 @@ import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.reactive.CorsConfigurationSource; +import java.util.Collections; + +@RequiredArgsConstructor @Configuration public class SecurityConfig { @@ -21,12 +28,37 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .csrf(csrf -> csrf.disable()) // JWT 사용하므로 비활성화 .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + + // 엔드포인트별 접근 권한 설정 .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**").permitAll() // 로그인/회원가입은 열어두어야 접근 가능함... - .anyRequest().authenticated() + .anyRequest().authenticated() // 이외 요청은 인증된 사용자만 접근 가능 ) - .httpBasic(AbstractHttpConfigurer::disable); // Basic Auth 끄기 + .httpBasic(AbstractHttpConfigurer::disable) // Basic Auth 끄기 + // JWT 필터 추가 (기존 UsernamePasswordAuthenticationFilter 이전에 실행) + .addFilterBefore(new JWTFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) + + // 로그인 필터 추가 (JWTFilter 실행 후 JWT 발급 처리) + .addFilterAfter(new LoginFilter(authenticationManager(), jwtUtil), JWTFilter.class) + + // 세션을 사용하지 않음 (JWT 기반 인증이므로 STATELESS 모드 설정) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); return http.build(); } + + // 프론트용 + @Bean + public CorsConfigurationSource corsConfigurationSource() { + return request -> { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); // 허용할 도메인 + configuration.setAllowedMethods(Collections.singletonList("*")); // 모든 HTTP 메서드 허용 + configuration.setAllowCredentials(true); // 인증 정보 포함 허용 + configuration.setAllowedHeaders(Collections.singletonList("*")); // 모든 헤더 허용 + configuration.setExposedHeaders(Collections.singletonList("Authorization")); // Authorization 헤더 노출 + configuration.setMaxAge(3600L); // 1시간 동안 캐싱 + return configuration; + }; + } } diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index bde3c479..8b6c0b1e 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -4,33 +4,23 @@ import com.example.bcsd.domain.Board; import com.example.bcsd.domain.Member; import com.example.bcsd.dto.ArticleDTO; - import com.example.bcsd.exception.InvalidReferenceException; import com.example.bcsd.exception.MissingFieldException; import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemberRepository; import com.example.bcsd.repository.BoardRepository; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; - import java.util.List; +@RequiredArgsConstructor @Service public class ArticleService { private final ArticleRepository articleRepository; private final MemberRepository memberRepository; private final BoardRepository boardRepository; - @Autowired - public ArticleService(ArticleRepository articleRepository, - MemberRepository memberRepository, - BoardRepository boardRepository) { - this.articleRepository = articleRepository; - this.memberRepository = memberRepository; - this.boardRepository = boardRepository; - } - // 1. READ - board의 전체 article public List
getAllArticlesByBoard(Long boardId){ return articleRepository.findByBoardId(boardId); diff --git a/src/main/java/com/example/bcsd/service/BoardService.java b/src/main/java/com/example/bcsd/service/BoardService.java index ed8b0b44..89a8493d 100644 --- a/src/main/java/com/example/bcsd/service/BoardService.java +++ b/src/main/java/com/example/bcsd/service/BoardService.java @@ -2,16 +2,15 @@ import com.example.bcsd.domain.Board; import com.example.bcsd.dto.BoardDTO; import com.example.bcsd.exception.MissingFieldException; -import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.BoardRepository; import com.example.bcsd.repository.ArticleRepository; -import jakarta.transaction.Transactional; import org.springframework.stereotype.Service; @Service public class BoardService { private final BoardRepository boardRepository; + public BoardService(BoardRepository boardRepository, ArticleRepository articleRepository) { this.boardRepository = boardRepository; } diff --git a/src/main/java/com/example/bcsd/service/MemberService.java b/src/main/java/com/example/bcsd/service/MemberService.java index 9b0688a3..3d1f91f0 100644 --- a/src/main/java/com/example/bcsd/service/MemberService.java +++ b/src/main/java/com/example/bcsd/service/MemberService.java @@ -7,27 +7,19 @@ import com.example.bcsd.exception.RemainArticlesException; import com.example.bcsd.repository.ArticleRepository; import com.example.bcsd.repository.MemberRepository; -import org.springframework.beans.factory.annotation.Autowired; +import lombok.RequiredArgsConstructor; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; - +@RequiredArgsConstructor @Service public class MemberService { private final MemberRepository memberRepository; private final ArticleRepository articleRepository; private final PasswordEncoder passwordEncoder; - @Autowired // 생성자 호출할 때 MemberRepository(실제로는 구현부인 MemoryMemberRepository)를 넣어줌! - public MemberService(MemberRepository memberRepository, ArticleRepository articleRepository, PasswordEncoder passwordEncoder) { - this.memberRepository = memberRepository; - this.articleRepository = articleRepository; - this.passwordEncoder = passwordEncoder; - } - public Member create(MemberDTO req) { validateForCreate(req); @@ -84,7 +76,7 @@ private void validateForCreate(MemberDTO req) { throw new MissingFieldException("password은 null일 수 없습니다."); } } - public Member login(MemberDTO req) { + public void login(MemberDTO req) { String email = req.getEmail(); String password = req.getPassword(); if (email == null || email.isBlank()) { throw new MissingFieldException("email은 null일수 없습니다.");} @@ -95,10 +87,9 @@ public Member login(MemberDTO req) { if (!passwordEncoder.matches(password, member.getPassword())) { throw new IllegalArgumentException("이메일 또는 비밀번호를 다시 확인해주세요."); } - return member; } - public Member signup(MemberDTO req) { + public void signup(MemberDTO req) { Member member = new Member(); String name = req.getName(); @@ -119,6 +110,6 @@ public Member signup(MemberDTO req) { member.setEmail(email); member.setPassword(password); - return memberRepository.save(member); + memberRepository.save(member); } } From c943699ed83c8022104b2bad0660d4888cf5280e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A4=ED=95=B4=EC=9D=B8?= Date: Fri, 16 Jan 2026 00:19:41 +0900 Subject: [PATCH 72/72] =?UTF-8?q?feat:=20jwttokenDTO,=20tokenProvider=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 --- build.gradle | 2 ++ .../example/bcsd/config/SecurityConfig.java | 1 - .../com/example/bcsd/jwt/JwtTokenDTO.java | 14 +++++++++++++ .../example/bcsd/jwt/JwtTokenProvider.java | 21 +++++++++++++++++++ .../example/bcsd/service/ArticleService.java | 7 +++---- 5 files changed, 40 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/example/bcsd/jwt/JwtTokenDTO.java create mode 100644 src/main/java/com/example/bcsd/jwt/JwtTokenProvider.java diff --git a/build.gradle b/build.gradle index 457d4247..e9cc8421 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,8 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-impl:0.12.3' implementation 'io.jsonwebtoken:jjwt-jackson:0.12.3' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3' compileOnly 'org.projectlombok:lombok:1.18.38' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' diff --git a/src/main/java/com/example/bcsd/config/SecurityConfig.java b/src/main/java/com/example/bcsd/config/SecurityConfig.java index 81b2b85f..3e9425ab 100644 --- a/src/main/java/com/example/bcsd/config/SecurityConfig.java +++ b/src/main/java/com/example/bcsd/config/SecurityConfig.java @@ -17,7 +17,6 @@ @RequiredArgsConstructor @Configuration public class SecurityConfig { - @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); diff --git a/src/main/java/com/example/bcsd/jwt/JwtTokenDTO.java b/src/main/java/com/example/bcsd/jwt/JwtTokenDTO.java new file mode 100644 index 00000000..13c9ef9a --- /dev/null +++ b/src/main/java/com/example/bcsd/jwt/JwtTokenDTO.java @@ -0,0 +1,14 @@ +package com.example.bcsd.jwt; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@AllArgsConstructor +public class JwtTokenDTO { + private String grantType; + private String accessToken; + private String refreshToken; +} diff --git a/src/main/java/com/example/bcsd/jwt/JwtTokenProvider.java b/src/main/java/com/example/bcsd/jwt/JwtTokenProvider.java new file mode 100644 index 00000000..860d2b0f --- /dev/null +++ b/src/main/java/com/example/bcsd/jwt/JwtTokenProvider.java @@ -0,0 +1,21 @@ +package com.example.bcsd.jwt; + +import org.springframework.stereotype.Component; +import io.jsonwebtoken.Jwts; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import java.util.Date; + +@Component +public class JwtTokenProvider { + private final Key key = new SecretKeySpec("secret".getBytes(), "AES"); + + public String generateToken(Long memberId, String email) { + return Jwts.builder() + .subject(email) // 토큰 주인 + .claim("memberId", memberId) // 커스텀 정보 + .issuedAt(new Date()) // 발급 시간 + .signWith(key) // 서명 + .compact(); + } +} diff --git a/src/main/java/com/example/bcsd/service/ArticleService.java b/src/main/java/com/example/bcsd/service/ArticleService.java index 8b6c0b1e..d9961097 100644 --- a/src/main/java/com/example/bcsd/service/ArticleService.java +++ b/src/main/java/com/example/bcsd/service/ArticleService.java @@ -25,11 +25,13 @@ public class ArticleService { public List
getAllArticlesByBoard(Long boardId){ return articleRepository.findByBoardId(boardId); } + // 1. READ - 하나만 public Article getOne(Long id){ return articleRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException(id + "번 게시글이 없습니다.")); } + // 2. CREATE public Article create(ArticleDTO req){ validateForCreate(req); @@ -66,6 +68,7 @@ public Article update(ArticleDTO req, Long id){ return articleRepository.save(article); } + // 4. DELETE public void delete(Long id){ if (!articleRepository.existsById(id)) { @@ -75,19 +78,15 @@ public void delete(Long id){ } private void validateForCreate(ArticleDTO req) { - if (req.getTitle() == null || req.getTitle().isBlank()) { throw new MissingFieldException("title은 null일 수 없습니다."); } - if (req.getContent() == null || req.getContent().isBlank()) { throw new MissingFieldException("content는 null일 수 없습니다."); } - if (req.getAuthorId() == null) { throw new MissingFieldException("authorId는 null일 수 없습니다."); } - if (req.getBoardId() == null) { throw new MissingFieldException("boardId는 null일 수 없습니다."); }