From ad9fc1492ef4ac3a0b8bc4f90f3c9051670c0da8 Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 6 Nov 2024 15:28:30 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=ED=99=88=20=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1,=20=EC=98=88=EC=95=BD=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20-=20Gradle=20=EC=88=98=EC=A0=95=20-=20HomeController,=20Rese?= =?UTF-8?q?rvationController=20=EC=83=9D=EC=84=B1=20-=20Reservation=20dto?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 ++ .../roomescape/controller/HomeController.java | 14 ++++++++ .../controller/ReservationController.java | 36 +++++++++++++++++++ src/main/java/roomescape/dto/Reservation.java | 32 +++++++++++++++++ src/test/java/roomescape/MissionStepTest.java | 16 +++++++++ 5 files changed, 101 insertions(+) create mode 100644 src/main/java/roomescape/controller/HomeController.java create mode 100644 src/main/java/roomescape/controller/ReservationController.java create mode 100644 src/main/java/roomescape/dto/Reservation.java diff --git a/build.gradle b/build.gradle index 57267157c..b331b63b3 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' + + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' } test { diff --git a/src/main/java/roomescape/controller/HomeController.java b/src/main/java/roomescape/controller/HomeController.java new file mode 100644 index 000000000..ccb3fa03f --- /dev/null +++ b/src/main/java/roomescape/controller/HomeController.java @@ -0,0 +1,14 @@ +package roomescape.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; + +@Controller +public class HomeController { + + @RequestMapping("/") + public String home(){ + return "home"; + } + +} diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java new file mode 100644 index 000000000..521e55fba --- /dev/null +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -0,0 +1,36 @@ +package roomescape.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import roomescape.dto.Reservation; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +@Controller +public class ReservationController { + + private List reservations = new ArrayList<>(); + private AtomicLong index = new AtomicLong(1); + + public ReservationController() { + reservations.add(new Reservation(1L, "브라운", "2023-01-01", "10:00")); + reservations.add(new Reservation(2L, "브라운", "2023-01-02", "11:00")); + reservations.add(new Reservation(3L, "브라운", "2023-01-03", "12:00")); + } + + @GetMapping("/reservation") + public String reservationPage(){ + return "reservation"; + } + + @ResponseBody + @GetMapping("/reservations") + public List reservationList(){ + return reservations; + } +} diff --git a/src/main/java/roomescape/dto/Reservation.java b/src/main/java/roomescape/dto/Reservation.java new file mode 100644 index 000000000..f9d815cbd --- /dev/null +++ b/src/main/java/roomescape/dto/Reservation.java @@ -0,0 +1,32 @@ +package roomescape.dto; + +public class Reservation { + + private Long id; + private String name; + private String date; + private String time; + + public Reservation(Long id, String name, String date, String time) { + this.id = id; + this.name = name; + this.date = date; + this.time = time; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDate() { + return date; + } + + public String getTime() { + return time; + } +} diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index cf4efbe91..99f72d275 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -4,6 +4,7 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; +import static org.hamcrest.Matchers.is; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) @@ -16,4 +17,19 @@ public class MissionStepTest { .then().log().all() .statusCode(200); } + + @Test + void 이단계() { + RestAssured.given().log().all() + .when().get("/reservation") + .then().log().all() + .statusCode(200); + + RestAssured.given().log().all() + .when().get("/reservations") + .then().log().all() + .statusCode(200) + .body("size()", is(3)); // 아직 생성 요청이 없으니 Controller에서 임의로 넣어준 Reservation 갯수 만큼 검증하거나 0개임을 확인하세요. + } + } From 7dfd8c5cb009c9b218aa0e87e2ed3176d7285581 Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 6 Nov 2024 21:43:46 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80/=EC=B7=A8=EC=86=8C=20-=20ReservationController?= =?UTF-8?q?=EC=86=8D=20=EB=B3=80=EC=88=98=EC=97=90=20=EA=B0=92=20=EB=84=A3?= =?UTF-8?q?=EC=96=B4=EC=A4=80=20=EC=BD=94=EB=93=9C=20=EC=A3=BC=EC=84=9D?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 44 ++++++++++++++++--- src/main/java/roomescape/dto/Reservation.java | 1 + src/main/resources/application.properties | 1 + src/test/java/roomescape/MissionStepTest.java | 40 +++++++++++++++++ 4 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 521e55fba..90837a2c6 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -1,12 +1,16 @@ package roomescape.controller; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import roomescape.dto.Reservation; +import java.net.URI; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; @@ -17,20 +21,46 @@ public class ReservationController { private List reservations = new ArrayList<>(); private AtomicLong index = new AtomicLong(1); - public ReservationController() { - reservations.add(new Reservation(1L, "브라운", "2023-01-01", "10:00")); - reservations.add(new Reservation(2L, "브라운", "2023-01-02", "11:00")); - reservations.add(new Reservation(3L, "브라운", "2023-01-03", "12:00")); - } +// public ReservationController() { +// reservations.add(new Reservation(1L, "브라운1", "2023-01-01", "10:00")); +// reservations.add(new Reservation(2L, "브라운2", "2023-01-02", "11:00")); +// reservations.add(new Reservation(3L, "브라운3", "2023-01-03", "12:00")); +// } + // 홈화면 @GetMapping("/reservation") public String reservationPage(){ return "reservation"; } + //예약 조회 @ResponseBody @GetMapping("/reservations") - public List reservationList(){ + public List list(){ return reservations; } + + //예약 추가 + @ResponseBody + @PostMapping("/reservations") + public ResponseEntity create(@RequestBody Reservation newReservation){ + + Reservation reservation = new Reservation(index.getAndIncrement(), newReservation.getName(), newReservation.getDate(), newReservation.getTime()); + + reservations.add(reservation); + return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())) + .body(reservation); + } + + //예약 삭제 + @DeleteMapping("/reservations/{id}") + public ResponseEntity delete(@PathVariable Long id){ + Reservation reservation = reservations.stream() + .filter(it -> it.getId().equals(id)) + .findFirst() + .orElseThrow(() -> new RuntimeException("Reservation not found")); + + reservations.remove(reservation); + return ResponseEntity.noContent().build(); + } } diff --git a/src/main/java/roomescape/dto/Reservation.java b/src/main/java/roomescape/dto/Reservation.java index f9d815cbd..dc4a784ae 100644 --- a/src/main/java/roomescape/dto/Reservation.java +++ b/src/main/java/roomescape/dto/Reservation.java @@ -29,4 +29,5 @@ public String getDate() { public String getTime() { return time; } + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e69de29bb..4c00e40de 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -0,0 +1 @@ +server.port=8080 diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 99f72d275..a99d4ce74 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -1,9 +1,14 @@ package roomescape; import io.restassured.RestAssured; +import io.restassured.http.ContentType; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; + +import java.util.HashMap; +import java.util.Map; + import static org.hamcrest.Matchers.is; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @@ -32,4 +37,39 @@ public class MissionStepTest { .body("size()", is(3)); // 아직 생성 요청이 없으니 Controller에서 임의로 넣어준 Reservation 갯수 만큼 검증하거나 0개임을 확인하세요. } + @Test + void 삼단계() { + Map params = new HashMap<>(); + params.put("name", "브라운"); + params.put("date", "2023-08-05"); + params.put("time", "15:40"); + + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(params) + .when().post("/reservations") + .then().log().all() + .statusCode(201) + .header("Location", "/reservations/1") + .body("id", is(1)); + + RestAssured.given().log().all() + .when().get("/reservations") + .then().log().all() + .statusCode(200) + .body("size()", is(1)); + + RestAssured.given().log().all() + .when().delete("/reservations/1") + .then().log().all() + .statusCode(204); + + RestAssured.given().log().all() + .when().get("/reservations") + .then().log().all() + .statusCode(200) + .body("size()", is(0)); + } + + } From 3452ba4ddd1da1a7bf65d2f6b41884d43eef6495 Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 6 Nov 2024 23:16:35 +0900 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=EC=98=88=EC=99=B8=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/controller/HomeController.java | 2 +- .../controller/ReservationController.java | 21 ++++++++++++------- .../exception/ExceptionHandler.java | 19 +++++++++++++++++ .../exception/InvalidValueException.java | 8 +++++++ .../NotFoundReservationException.java | 7 +++++++ src/test/java/roomescape/MissionStepTest.java | 20 ++++++++++++++++++ 6 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 src/main/java/roomescape/exception/ExceptionHandler.java create mode 100644 src/main/java/roomescape/exception/InvalidValueException.java create mode 100644 src/main/java/roomescape/exception/NotFoundReservationException.java diff --git a/src/main/java/roomescape/controller/HomeController.java b/src/main/java/roomescape/controller/HomeController.java index ccb3fa03f..6efe2ab58 100644 --- a/src/main/java/roomescape/controller/HomeController.java +++ b/src/main/java/roomescape/controller/HomeController.java @@ -7,7 +7,7 @@ public class HomeController { @RequestMapping("/") - public String home(){ + public String home() { return "home"; } diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 90837a2c6..2b0138b37 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -9,6 +9,8 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import roomescape.dto.Reservation; +import roomescape.exception.InvalidValueException; +import roomescape.exception.NotFoundReservationException; import java.net.URI; import java.util.ArrayList; @@ -20,7 +22,7 @@ public class ReservationController { private List reservations = new ArrayList<>(); private AtomicLong index = new AtomicLong(1); - +// 이단계 // public ReservationController() { // reservations.add(new Reservation(1L, "브라운1", "2023-01-01", "10:00")); // reservations.add(new Reservation(2L, "브라운2", "2023-01-02", "11:00")); @@ -29,36 +31,41 @@ public class ReservationController { // 홈화면 @GetMapping("/reservation") - public String reservationPage(){ + public String reservationPage() { return "reservation"; } //예약 조회 @ResponseBody @GetMapping("/reservations") - public List list(){ + public List list() { return reservations; } //예약 추가 @ResponseBody @PostMapping("/reservations") - public ResponseEntity create(@RequestBody Reservation newReservation){ + public ResponseEntity create(@RequestBody Reservation newReservation) { + if (newReservation.getName() == null || newReservation.getName().isEmpty() || + newReservation.getDate() == null || newReservation.getDate().isEmpty() || + newReservation.getTime() == null || newReservation.getTime().isEmpty()) { + throw new InvalidValueException("예약 추가에 필요한 인자값이 비어있습니다."); + } Reservation reservation = new Reservation(index.getAndIncrement(), newReservation.getName(), newReservation.getDate(), newReservation.getTime()); - reservations.add(reservation); + return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())) .body(reservation); } //예약 삭제 @DeleteMapping("/reservations/{id}") - public ResponseEntity delete(@PathVariable Long id){ + public ResponseEntity delete(@PathVariable Long id) { Reservation reservation = reservations.stream() .filter(it -> it.getId().equals(id)) .findFirst() - .orElseThrow(() -> new RuntimeException("Reservation not found")); + .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); reservations.remove(reservation); return ResponseEntity.noContent().build(); diff --git a/src/main/java/roomescape/exception/ExceptionHandler.java b/src/main/java/roomescape/exception/ExceptionHandler.java new file mode 100644 index 000000000..8d83f2506 --- /dev/null +++ b/src/main/java/roomescape/exception/ExceptionHandler.java @@ -0,0 +1,19 @@ +package roomescape.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class ExceptionHandler { + + @org.springframework.web.bind.annotation.ExceptionHandler(NotFoundReservationException.class) + public ResponseEntity handleNotFoundReservationException(NotFoundReservationException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } + + @org.springframework.web.bind.annotation.ExceptionHandler(InvalidValueException.class) + public ResponseEntity handleInvalidReservationException(InvalidValueException ex) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); + } +} diff --git a/src/main/java/roomescape/exception/InvalidValueException.java b/src/main/java/roomescape/exception/InvalidValueException.java new file mode 100644 index 000000000..0fe7afbaa --- /dev/null +++ b/src/main/java/roomescape/exception/InvalidValueException.java @@ -0,0 +1,8 @@ +package roomescape.exception; + +public class InvalidValueException extends RuntimeException { + + public InvalidValueException(String message) { + super(message); + } +} diff --git a/src/main/java/roomescape/exception/NotFoundReservationException.java b/src/main/java/roomescape/exception/NotFoundReservationException.java new file mode 100644 index 000000000..55990b696 --- /dev/null +++ b/src/main/java/roomescape/exception/NotFoundReservationException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class NotFoundReservationException extends RuntimeException { + public NotFoundReservationException(String message) { + super(message); + } +} diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index a99d4ce74..c8615ff55 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -71,5 +71,25 @@ public class MissionStepTest { .body("size()", is(0)); } + @Test + void 사단계() { + Map params = new HashMap<>(); + params.put("name", "브라운"); + params.put("date", ""); + params.put("time", ""); + // 필요한 인자가 없는 경우 + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(params) + .when().post("/reservations") + .then().log().all() + .statusCode(400); + + // 삭제할 예약이 없는 경우 + RestAssured.given().log().all() + .when().delete("/reservations/1") + .then().log().all() + .statusCode(400); + } } From 7b379b3b5201c5dfd45afc7ec64f5396fc37307c Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 13 Nov 2024 21:38:11 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat:=205=EB=8B=A8=EA=B3=84=20-=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=EB=B2=A0=EC=9D=B4=EC=8A=A4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 --- src/main/resources/schema.sql | 0 src/test/java/roomescape/MissionStepTest2.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/schema.sql create mode 100644 src/test/java/roomescape/MissionStepTest2.java diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/java/roomescape/MissionStepTest2.java b/src/test/java/roomescape/MissionStepTest2.java new file mode 100644 index 000000000..e69de29bb From dec3a7ad5558b37a8637994d709d91af84fb2d88 Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 13 Nov 2024 23:07:21 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat:=206=EB=8B=A8=EA=B3=84=20-=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A1=B0=ED=9A=8C=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 예약 조회 API 처리 로직에서 저장된 예약을 조회할 때 데이터베이스를 활용하도록 수정 --- src/main/java/roomescape/repository/ReservationRepository.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/java/roomescape/repository/ReservationRepository.java diff --git a/src/main/java/roomescape/repository/ReservationRepository.java b/src/main/java/roomescape/repository/ReservationRepository.java new file mode 100644 index 000000000..e69de29bb From bad771c5d1eb70a7e6523d0c67389d729addc5bd Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Wed, 13 Nov 2024 23:56:13 +0900 Subject: [PATCH 6/7] =?UTF-8?q?feat:=207=EB=8B=A8=EA=B3=84=20-=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80/=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 --- build.gradle | 3 + .../controller/ReservationController.java | 27 +++---- .../repository/ReservationRepository.java | 54 +++++++++++++ src/main/resources/application.properties | 3 + src/main/resources/schema.sql | 8 ++ src/test/java/roomescape/MissionStepTest.java | 2 + .../java/roomescape/MissionStepTest2.java | 80 +++++++++++++++++++ 7 files changed, 161 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index b331b63b3..e4a27b7a9 100644 --- a/build.gradle +++ b/build.gradle @@ -19,6 +19,9 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' + + implementation 'org.springframework.boot:spring-boot-starter-jdbc' + runtimeOnly 'com.h2database:h2' } test { diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 2b0138b37..9cdf5ca5b 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -11,6 +11,7 @@ import roomescape.dto.Reservation; import roomescape.exception.InvalidValueException; import roomescape.exception.NotFoundReservationException; +import roomescape.repository.ReservationRepository; import java.net.URI; import java.util.ArrayList; @@ -20,14 +21,11 @@ @Controller public class ReservationController { - private List reservations = new ArrayList<>(); - private AtomicLong index = new AtomicLong(1); -// 이단계 -// public ReservationController() { -// reservations.add(new Reservation(1L, "브라운1", "2023-01-01", "10:00")); -// reservations.add(new Reservation(2L, "브라운2", "2023-01-02", "11:00")); -// reservations.add(new Reservation(3L, "브라운3", "2023-01-03", "12:00")); -// } + private final ReservationRepository reservationRepository; + + public ReservationController(ReservationRepository repository) { + this.reservationRepository = repository; + } // 홈화면 @GetMapping("/reservation") @@ -39,7 +37,7 @@ public String reservationPage() { @ResponseBody @GetMapping("/reservations") public List list() { - return reservations; + return reservationRepository.findAll(); } //예약 추가 @@ -52,8 +50,7 @@ public ResponseEntity create(@RequestBody Reservation newReservatio throw new InvalidValueException("예약 추가에 필요한 인자값이 비어있습니다."); } - Reservation reservation = new Reservation(index.getAndIncrement(), newReservation.getName(), newReservation.getDate(), newReservation.getTime()); - reservations.add(reservation); + Reservation reservation = reservationRepository.insert(newReservation); return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())) .body(reservation); @@ -62,12 +59,10 @@ public ResponseEntity create(@RequestBody Reservation newReservatio //예약 삭제 @DeleteMapping("/reservations/{id}") public ResponseEntity delete(@PathVariable Long id) { - Reservation reservation = reservations.stream() - .filter(it -> it.getId().equals(id)) - .findFirst() - .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); +// 수정예정 Reservation reservation = reservationRepository.fin +// .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); - reservations.remove(reservation); + reservationRepository.delete(id); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/roomescape/repository/ReservationRepository.java b/src/main/java/roomescape/repository/ReservationRepository.java index e69de29bb..f4d0e6de0 100644 --- a/src/main/java/roomescape/repository/ReservationRepository.java +++ b/src/main/java/roomescape/repository/ReservationRepository.java @@ -0,0 +1,54 @@ +package roomescape.repository; + +import org.springframework.http.ResponseEntity; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import roomescape.dto.Reservation; + +import java.util.List; + +@Repository +public class ReservationRepository { + + private final JdbcTemplate jdbcTemplate; + + public ReservationRepository(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + //예약 조회 + public List findAll() { + String sql = "SELECT id, name, date, time FROM reservation"; + + return jdbcTemplate.query( + sql, (resultSet, rowNum) -> new Reservation( + resultSet.getLong("id"), + resultSet.getString("name"), + resultSet.getString("date"), + resultSet.getString("time") + )); + } + + //예약 추가 + public Reservation insert(Reservation reservation) { + try { + String sql = "INSERT INTO reservation(name, date, time) VALUES (?, ?, ?)"; + jdbcTemplate.update(sql, reservation.getName(), reservation.getDate(), reservation.getTime()); + + String query = "SELECT id FROM reservation ORDER BY id DESC LIMIT 1"; + Long id = jdbcTemplate.queryForObject(query, Long.class); + + return new Reservation(id, reservation.getName(), reservation.getDate(), reservation.getTime()); + } catch (Exception ex) { + throw new RuntimeException("오류가 발생하였습니다."); + } + } + + //예약 삭제 + public ResponseEntity delete(Long id) { + String sql = "DELETE FROM reservation WHERE id = ?"; + jdbcTemplate.update(sql, Long.valueOf(id)); + return ResponseEntity.noContent().build(); + } +} + diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 4c00e40de..39bfef124 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1 +1,4 @@ server.port=8080 +spring.h2.console.enabled=true +spring.h2.console.path=/h2-console +spring.datasource.url=jdbc:h2:mem:database diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index e69de29bb..8d9ab2754 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -0,0 +1,8 @@ +CREATE TABLE reservation +( + id BIGINT NOT NULL AUTO_INCREMENT, + name VARCHAR(255) NOT NULL, + date VARCHAR(255) NOT NULL, + time VARCHAR(255) NOT NULL, + PRIMARY KEY (id) +); diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index c8615ff55..1cd3587a4 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -92,4 +92,6 @@ public class MissionStepTest { .then().log().all() .statusCode(400); } + + } diff --git a/src/test/java/roomescape/MissionStepTest2.java b/src/test/java/roomescape/MissionStepTest2.java index e69de29bb..490cb26ea 100644 --- a/src/test/java/roomescape/MissionStepTest2.java +++ b/src/test/java/roomescape/MissionStepTest2.java @@ -0,0 +1,80 @@ +package roomescape; + +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.annotation.DirtiesContext; +import roomescape.dto.Reservation; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.hamcrest.Matchers.is; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +public class MissionStepTest2 { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Test + void 오단계() { + try (Connection connection = jdbcTemplate.getDataSource().getConnection()) { + assertThat(connection).isNotNull(); + assertThat(connection.getCatalog()).isEqualTo("DATABASE"); + assertThat(connection.getMetaData().getTables(null, null, "RESERVATION", null).next()).isTrue(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + + @Test + void 육단계() { + jdbcTemplate.update("INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)", "브라운", "2023-08-05", "15:40"); + + List reservations = RestAssured.given().log().all() + .when().get("/reservations") + .then().log().all() + .statusCode(200).extract() + .jsonPath().getList(".", Reservation.class); + + Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class); + + assertThat(reservations.size()).isEqualTo(count); + } + + @Test + void 칠단계() { + Map params = new HashMap<>(); + params.put("name", "브라운"); + params.put("date", "2023-08-05"); + params.put("time", "10:00"); + + RestAssured.given().log().all() + .contentType(ContentType.JSON) + .body(params) + .when().post("/reservations") + .then().log().all() + .statusCode(201) + .header("Location", "/reservations/1"); + + Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class); + assertThat(count).isEqualTo(1); + + RestAssured.given().log().all() + .when().delete("/reservations/1") + .then().log().all() + .statusCode(204); + + Integer countAfterDelete = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class); + assertThat(countAfterDelete).isEqualTo(0); + } +} From 9f4ec6274357fa9c4b91eb9449d48eb3987e949f Mon Sep 17 00:00:00 2001 From: haeyoon1 Date: Sun, 17 Nov 2024 23:14:44 +0900 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 34 +++++-------- .../java/roomescape/dao/ReservationDao.java | 45 ++++++++++++++++ .../roomescape/dto/ReservationRequestDto.java | 27 ++++++++++ ...ation.java => ReservationResponseDto.java} | 11 ++-- .../java/roomescape/entity/Reservation.java | 37 ++++++++++++++ .../repository/ReservationRepository.java | 38 ++++---------- .../service/ReservationService.java | 51 +++++++++++++++++++ src/main/resources/schema.sql | 2 +- src/test/java/roomescape/MissionStepTest.java | 2 +- .../java/roomescape/MissionStepTest2.java | 2 +- 10 files changed, 190 insertions(+), 59 deletions(-) create mode 100644 src/main/java/roomescape/dao/ReservationDao.java create mode 100644 src/main/java/roomescape/dto/ReservationRequestDto.java rename src/main/java/roomescape/dto/{Reservation.java => ReservationResponseDto.java} (60%) create mode 100644 src/main/java/roomescape/entity/Reservation.java create mode 100644 src/main/java/roomescape/service/ReservationService.java diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 9cdf5ca5b..c9dbb157e 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -8,23 +8,20 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; -import roomescape.dto.Reservation; -import roomescape.exception.InvalidValueException; -import roomescape.exception.NotFoundReservationException; -import roomescape.repository.ReservationRepository; +import roomescape.dto.ReservationRequestDto; +import roomescape.dto.ReservationResponseDto; +import roomescape.service.ReservationService; import java.net.URI; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicLong; @Controller public class ReservationController { - private final ReservationRepository reservationRepository; + private final ReservationService reservationService; - public ReservationController(ReservationRepository repository) { - this.reservationRepository = repository; + public ReservationController(ReservationService reservationService) { + this.reservationService = reservationService; } // 홈화면 @@ -36,21 +33,17 @@ public String reservationPage() { //예약 조회 @ResponseBody @GetMapping("/reservations") - public List list() { - return reservationRepository.findAll(); + public ResponseEntity> list() { + List reservations = reservationService.getAllReservations(); + return ResponseEntity.ok(reservations); } //예약 추가 @ResponseBody @PostMapping("/reservations") - public ResponseEntity create(@RequestBody Reservation newReservation) { - if (newReservation.getName() == null || newReservation.getName().isEmpty() || - newReservation.getDate() == null || newReservation.getDate().isEmpty() || - newReservation.getTime() == null || newReservation.getTime().isEmpty()) { - throw new InvalidValueException("예약 추가에 필요한 인자값이 비어있습니다."); - } + public ResponseEntity create(@RequestBody ReservationRequestDto newReservationDto) { - Reservation reservation = reservationRepository.insert(newReservation); + ReservationResponseDto reservation = reservationService.createReservation(newReservationDto); return ResponseEntity.created(URI.create("/reservations/" + reservation.getId())) .body(reservation); @@ -59,10 +52,7 @@ public ResponseEntity create(@RequestBody Reservation newReservatio //예약 삭제 @DeleteMapping("/reservations/{id}") public ResponseEntity delete(@PathVariable Long id) { -// 수정예정 Reservation reservation = reservationRepository.fin -// .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); - - reservationRepository.delete(id); + reservationService.deleteReservation(id); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/roomescape/dao/ReservationDao.java b/src/main/java/roomescape/dao/ReservationDao.java new file mode 100644 index 000000000..a942ca7a3 --- /dev/null +++ b/src/main/java/roomescape/dao/ReservationDao.java @@ -0,0 +1,45 @@ +package roomescape.dao; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; +import roomescape.entity.Reservation; + +import java.util.List; + +@Repository +public class ReservationDao { + + private final JdbcTemplate jdbcTemplate; + + public ReservationDao(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + public List findAll(){ + String sql = "SELECT id, name, date, time FROM reservation"; + + return jdbcTemplate.query( + sql, (resultSet, rowNum) -> new Reservation( + resultSet.getLong("id"), + resultSet.getString("name"), + resultSet.getString("date"), + resultSet.getTimestamp("time").toLocalDateTime() + )); + } + + public Reservation insert(Reservation reservation) { + String sql = "INSERT INTO reservation(name, date, time) VALUES (?, ?, ?)"; + jdbcTemplate.update(sql, reservation.getName(), reservation.getDate(), reservation.getTime()); + + String query = "SELECT id FROM reservation ORDER BY id DESC LIMIT 1"; + Long id = jdbcTemplate.queryForObject(query, Long.class); + + return new Reservation(id, reservation.getName(), reservation.getDate(), reservation.getTime()); + } + + public void delete(Long id) { + String sql = "DELETE FROM reservation WHERE id = ?"; + jdbcTemplate.update(sql, id); + } + +} diff --git a/src/main/java/roomescape/dto/ReservationRequestDto.java b/src/main/java/roomescape/dto/ReservationRequestDto.java new file mode 100644 index 000000000..b96ba1f69 --- /dev/null +++ b/src/main/java/roomescape/dto/ReservationRequestDto.java @@ -0,0 +1,27 @@ +package roomescape.dto; + +import java.time.LocalDateTime; + +public class ReservationRequestDto { + private String name; + private String date; + private LocalDateTime time; + + public ReservationRequestDto(String name, String date, LocalDateTime time) { + this.name = name; + this.date = date; + this.time = time; + } + + public String getName() { + return name; + } + + public String getDate() { + return date; + } + + public LocalDateTime getTime() { + return time; + } +} diff --git a/src/main/java/roomescape/dto/Reservation.java b/src/main/java/roomescape/dto/ReservationResponseDto.java similarity index 60% rename from src/main/java/roomescape/dto/Reservation.java rename to src/main/java/roomescape/dto/ReservationResponseDto.java index dc4a784ae..3ad189302 100644 --- a/src/main/java/roomescape/dto/Reservation.java +++ b/src/main/java/roomescape/dto/ReservationResponseDto.java @@ -1,13 +1,15 @@ package roomescape.dto; -public class Reservation { +import java.time.LocalDate; +import java.time.LocalDateTime; +public class ReservationResponseDto { private Long id; private String name; private String date; - private String time; + private LocalDateTime time; - public Reservation(Long id, String name, String date, String time) { + public ReservationResponseDto(Long id, String name, String date, LocalDateTime time) { this.id = id; this.name = name; this.date = date; @@ -26,8 +28,7 @@ public String getDate() { return date; } - public String getTime() { + public LocalDateTime getTime() { return time; } - } diff --git a/src/main/java/roomescape/entity/Reservation.java b/src/main/java/roomescape/entity/Reservation.java new file mode 100644 index 000000000..30138b6f3 --- /dev/null +++ b/src/main/java/roomescape/entity/Reservation.java @@ -0,0 +1,37 @@ +package roomescape.entity; + +import java.time.LocalDateTime; + +public class Reservation { + private Long id; + private String name; + private String date; + private LocalDateTime time; + + public Reservation(Long id, String name, String date, LocalDateTime time) { + this.id = id; + this.name = name; + this.date = date; + this.time = time; + } + + public Reservation(String name, String date, LocalDateTime time) { + this(null, name, date, time); + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getDate() { + return date; + } + + public LocalDateTime getTime() { + return time; + } +} diff --git a/src/main/java/roomescape/repository/ReservationRepository.java b/src/main/java/roomescape/repository/ReservationRepository.java index f4d0e6de0..920916f21 100644 --- a/src/main/java/roomescape/repository/ReservationRepository.java +++ b/src/main/java/roomescape/repository/ReservationRepository.java @@ -3,52 +3,32 @@ import org.springframework.http.ResponseEntity; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; -import roomescape.dto.Reservation; +import roomescape.dao.ReservationDao; +import roomescape.entity.Reservation; import java.util.List; @Repository public class ReservationRepository { - private final JdbcTemplate jdbcTemplate; + private final ReservationDao reservationDao; - public ReservationRepository(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; + public ReservationRepository(ReservationDao reservationDao) { + this.reservationDao = reservationDao; } - //예약 조회 public List findAll() { - String sql = "SELECT id, name, date, time FROM reservation"; - - return jdbcTemplate.query( - sql, (resultSet, rowNum) -> new Reservation( - resultSet.getLong("id"), - resultSet.getString("name"), - resultSet.getString("date"), - resultSet.getString("time") - )); + return reservationDao.findAll(); } //예약 추가 public Reservation insert(Reservation reservation) { - try { - String sql = "INSERT INTO reservation(name, date, time) VALUES (?, ?, ?)"; - jdbcTemplate.update(sql, reservation.getName(), reservation.getDate(), reservation.getTime()); - - String query = "SELECT id FROM reservation ORDER BY id DESC LIMIT 1"; - Long id = jdbcTemplate.queryForObject(query, Long.class); - - return new Reservation(id, reservation.getName(), reservation.getDate(), reservation.getTime()); - } catch (Exception ex) { - throw new RuntimeException("오류가 발생하였습니다."); - } + return reservationDao.insert(reservation); } //예약 삭제 - public ResponseEntity delete(Long id) { - String sql = "DELETE FROM reservation WHERE id = ?"; - jdbcTemplate.update(sql, Long.valueOf(id)); - return ResponseEntity.noContent().build(); + public void delete(Long id) { + reservationDao.delete(id); } } diff --git a/src/main/java/roomescape/service/ReservationService.java b/src/main/java/roomescape/service/ReservationService.java new file mode 100644 index 000000000..88e0193f6 --- /dev/null +++ b/src/main/java/roomescape/service/ReservationService.java @@ -0,0 +1,51 @@ +package roomescape.service; + +import org.springframework.stereotype.Service; +import roomescape.dto.ReservationRequestDto; +import roomescape.dto.ReservationResponseDto; +import roomescape.entity.Reservation; +import roomescape.repository.ReservationRepository; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +public class ReservationService { + + private final ReservationRepository reservationRepository; + + public ReservationService(ReservationRepository reservationRepository) { + this.reservationRepository = reservationRepository; + } + + public List getAllReservations(){ + return reservationRepository.findAll() + .stream() + .map(this::toResponseDto) + .collect(Collectors.toList()); + } + + public ReservationResponseDto createReservation(ReservationRequestDto requestDto){ + + Reservation reservation = new Reservation( + requestDto.getName(), + requestDto.getDate(), + requestDto.getTime() + ); + Reservation savedReservation = reservationRepository.insert(reservation); + return toResponseDto(savedReservation); + } + + public void deleteReservation(Long id){ + reservationRepository.delete(id); + } + + private ReservationResponseDto toResponseDto(Reservation reservation) { + return new ReservationResponseDto( + reservation.getId(), + reservation.getName(), + reservation.getDate(), + reservation.getTime() + ); + } +} diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index 8d9ab2754..55063b774 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -3,6 +3,6 @@ CREATE TABLE reservation id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, date VARCHAR(255) NOT NULL, - time VARCHAR(255) NOT NULL, + time Timestamp NOT NULL, PRIMARY KEY (id) ); diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 1cd3587a4..c2fd98592 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -34,7 +34,7 @@ public class MissionStepTest { .when().get("/reservations") .then().log().all() .statusCode(200) - .body("size()", is(3)); // 아직 생성 요청이 없으니 Controller에서 임의로 넣어준 Reservation 갯수 만큼 검증하거나 0개임을 확인하세요. + .body("size()", is(0)); // 아직 생성 요청이 없으니 Controller에서 임의로 넣어준 Reservation 갯수 만큼 검증하거나 0개임을 확인하세요. } @Test diff --git a/src/test/java/roomescape/MissionStepTest2.java b/src/test/java/roomescape/MissionStepTest2.java index 490cb26ea..b738a5143 100644 --- a/src/test/java/roomescape/MissionStepTest2.java +++ b/src/test/java/roomescape/MissionStepTest2.java @@ -7,7 +7,7 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.test.annotation.DirtiesContext; -import roomescape.dto.Reservation; +import roomescape.entity.Reservation; import java.sql.Connection; import java.sql.SQLException;