From 6ec0522eb14681aba839e13eea8c27f06285e168 Mon Sep 17 00:00:00 2001 From: day024 <92675692+day024@users.noreply.github.com> Date: Fri, 10 May 2024 16:43:23 +0900 Subject: [PATCH 01/36] Create README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..1389293ab --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +#Spring MVC + +

1단계 요구사항

+localhost:8080 요청 시 아래 화면과 같이 어드민 메인 페이지가 응답할 수 있도록 구현하세요. From cc9cecbe74b52afd47dddd3bb15487a13a6d0260 Mon Sep 17 00:00:00 2001 From: day024 <92675692+day024@users.noreply.github.com> Date: Fri, 10 May 2024 16:43:33 +0900 Subject: [PATCH 02/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1389293ab..0a093b866 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -#Spring MVC +# Spring MVC

1단계 요구사항

localhost:8080 요청 시 아래 화면과 같이 어드민 메인 페이지가 응답할 수 있도록 구현하세요. From 2b8857ccf98d01ab8f19a840a82e3d2fb00af328 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 16:45:14 +0900 Subject: [PATCH 03/36] =?UTF-8?q?feat:=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20homeController=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 +++ src/main/java/roomescape/HomeController.java | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/main/java/roomescape/HomeController.java diff --git a/build.gradle b/build.gradle index 57267157c..b11bfe1be 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,10 @@ repositories { } dependencies { + implementation 'org.springframework.boot:spring-boot-starter-web' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter' + testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' } diff --git a/src/main/java/roomescape/HomeController.java b/src/main/java/roomescape/HomeController.java new file mode 100644 index 000000000..e61379f36 --- /dev/null +++ b/src/main/java/roomescape/HomeController.java @@ -0,0 +1,13 @@ +package roomescape; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class HomeController { + + @GetMapping("/") + public String home() { + return "home"; + } +} \ No newline at end of file From a11027ed306190c75e8564231a072a3c9aba2e82 Mon Sep 17 00:00:00 2001 From: day024 <92675692+day024@users.noreply.github.com> Date: Fri, 10 May 2024 20:54:52 +0900 Subject: [PATCH 04/36] =?UTF-8?q?docs:=202=EB=8B=A8=EA=B3=84=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a093b866..7ac9f726e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,16 @@ # Spring MVC

1단계 요구사항

-localhost:8080 요청 시 아래 화면과 같이 어드민 메인 페이지가 응답할 수 있도록 구현하세요. +- [x] localhost:8080 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현 + +

2단계 요구사항

+ +**예약 페이지** +- [ ] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 + - 어드민 메인 페이지는 templates/reservation.html 파일 사용 +- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 + - /reservation 요청 시 templates/reservation.html을 응답하도록 구현 + +**예약 목록 조회 API** +- [ ] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 +- [ ] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 From 0e1d27697cff3b7968743daaa702aa127475830b Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 20:56:08 +0900 Subject: [PATCH 05/36] =?UTF-8?q?feat:=20[2=EB=8B=A8=EA=B3=84]=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=91=EB=8B=B5=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 --- README.md | 13 ++++++++++++- .../java/roomescape/RoomescapeApplication.java | 11 +++++++++++ .../{ => controller}/HomeController.java | 3 ++- .../controller/ReservationController.java | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 2 deletions(-) rename src/main/java/roomescape/{ => controller}/HomeController.java (87%) create mode 100644 src/main/java/roomescape/controller/ReservationController.java diff --git a/README.md b/README.md index 0a093b866..bcd4a7537 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,15 @@ # Spring MVC

1단계 요구사항

-localhost:8080 요청 시 아래 화면과 같이 어드민 메인 페이지가 응답할 수 있도록 구현하세요. +- [x] localhost:8080 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현 + +

2단계 요구사항

+**예약 페이지** +- [ ] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 + - 어드민 메인 페이지는 templates/reservation.html 파일 사용 +- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 + - /reservation 요청 시 templates/reservation.html을 응답하도록 구현 + +**예약 목록 조회 API** +- [ ] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 +- [ ] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 \ No newline at end of file diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java index 702706791..02fa8dd35 100644 --- a/src/main/java/roomescape/RoomescapeApplication.java +++ b/src/main/java/roomescape/RoomescapeApplication.java @@ -2,6 +2,9 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.view.InternalResourceViewResolver; @SpringBootApplication public class RoomescapeApplication { @@ -9,4 +12,12 @@ public static void main(String[] args) { SpringApplication.run(RoomescapeApplication.class, args); } + @Bean + public ViewResolver getViewResolver() { + InternalResourceViewResolver resolver = new InternalResourceViewResolver(); + resolver.setPrefix("/WEB-INF/views/"); + resolver.setSuffix(".html"); + return resolver; + } + } diff --git a/src/main/java/roomescape/HomeController.java b/src/main/java/roomescape/controller/HomeController.java similarity index 87% rename from src/main/java/roomescape/HomeController.java rename to src/main/java/roomescape/controller/HomeController.java index e61379f36..9d34d747c 100644 --- a/src/main/java/roomescape/HomeController.java +++ b/src/main/java/roomescape/controller/HomeController.java @@ -1,4 +1,4 @@ -package roomescape; +package roomescape.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @@ -10,4 +10,5 @@ public class HomeController { public String home() { return "home"; } + } \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java new file mode 100644 index 000000000..9b270347b --- /dev/null +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -0,0 +1,15 @@ +package roomescape.controller; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + + +@Controller +public class ReservationController { + + @GetMapping("/reservation") + public String reservation() { + return "reservation"; + + } +} \ No newline at end of file From 77d7d761445be8ed3c012a55ff891c73a7f77a04 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 20:57:30 +0900 Subject: [PATCH 06/36] =?UTF-8?q?feat:=20[2=EB=8B=A8=EA=B3=84]=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9D=91=EB=8B=B5=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 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bcd4a7537..1ee26d6ea 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@

2단계 요구사항

**예약 페이지** -- [ ] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 +- [x] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 - 어드민 메인 페이지는 templates/reservation.html 파일 사용 -- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 +- [x] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 - /reservation 요청 시 templates/reservation.html을 응답하도록 구현 **예약 목록 조회 API** From 1a8b0fb2f9591a2a49942564e1146b902419df60 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 20:59:57 +0900 Subject: [PATCH 07/36] =?UTF-8?q?docs:=202=EB=8B=A8=EA=B3=84=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index db7d4f789..7b9062eea 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,19 @@ - [x] localhost:8080 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현

2단계 요구사항

-<<<<<<< HEAD + **예약 페이지** - [x] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 - 어드민 메인 페이지는 templates/reservation.html 파일 사용 -- [x] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 -======= +- [x] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 **예약 페이지** - [ ] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 - 어드민 메인 페이지는 templates/reservation.html 파일 사용 -- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 ->>>>>>> a11027ed306190c75e8564231a072a3c9aba2e82 +- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 - /reservation 요청 시 templates/reservation.html을 응답하도록 구현 **예약 목록 조회 API** -- [ ] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 -<<<<<<< HEAD -- [ ] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 -======= +- [ ] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 - [ ] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 ->>>>>>> a11027ed306190c75e8564231a072a3c9aba2e82 + From daaff1fc395ed849a982c7a46ceb1b242965ee9e Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 21:48:20 +0900 Subject: [PATCH 08/36] =?UTF-8?q?feat:=202=EB=8B=A8=EA=B3=84=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 ++---- .../controller/ReservationController.java | 18 +++++++++- .../java/roomescape/domain/Reservation.java | 33 +++++++++++++++++++ src/test/java/roomescape/MissionStepTest.java | 15 +++++++++ 4 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/main/java/roomescape/domain/Reservation.java diff --git a/README.md b/README.md index 7b9062eea..7199b2621 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,7 @@ - 어드민 메인 페이지는 templates/reservation.html 파일 사용 - [x] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 -**예약 페이지** -- [ ] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 - - 어드민 메인 페이지는 templates/reservation.html 파일 사용 -- [ ] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 - - /reservation 요청 시 templates/reservation.html을 응답하도록 구현 - **예약 목록 조회 API** -- [ ] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 -- [ ] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 +- [x] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 +- [x] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 9b270347b..fb2bd4eac 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -1,15 +1,31 @@ package roomescape.controller; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import roomescape.domain.Reservation; +import java.util.ArrayList; +import java.util.List; @Controller public class ReservationController { + private List reservations = new ArrayList<>(); @GetMapping("/reservation") public String reservation() { return "reservation"; + } + + @GetMapping("/reservations") + public ResponseEntity> getReservations() { + + List reservationList = new ArrayList<>(); + reservationList.add(new Reservation(1, "브라운", "2023-01-01", "10:00")); + reservationList.add(new Reservation(2, "브라운", "2023-01-02", "11:00")); + return ResponseEntity.status(HttpStatus.OK).body(reservationList); } -} \ No newline at end of file +} diff --git a/src/main/java/roomescape/domain/Reservation.java b/src/main/java/roomescape/domain/Reservation.java new file mode 100644 index 000000000..c03669d5c --- /dev/null +++ b/src/main/java/roomescape/domain/Reservation.java @@ -0,0 +1,33 @@ +package roomescape.domain; + +import java.time.LocalDateTime; + +public class Reservation { + private int id; + private String name; + private String date; + private String time; + + public Reservation(int id, String name, String date, String time) { + this.id = id; + this.name = name; + this.date = date; + this.time = time; + } + + public int getId() { + return id; + } + + public String getDate() { + return date; + } + + public String getName() { + return name; + } + + public String getTime() { + return time; + } +} \ No newline at end of file diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index cf4efbe91..bafd430a9 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,18 @@ 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(2)); + } } From f70e5ebd5f1bdab59c416b7dafe80e9022741522 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Fri, 10 May 2024 21:51:02 +0900 Subject: [PATCH 09/36] =?UTF-8?q?docs:=203=EB=8B=A8=EA=B3=84=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 7199b2621..c9e23dad0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Spring MVC

1단계 요구사항

+ - [x] localhost:8080 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현

2단계 요구사항

@@ -13,4 +14,10 @@ **예약 목록 조회 API** - [x] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 - [x] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 +- [ ] 요구사항 테스트 + +

3단계 요구사항

+- [ ] 예약 추가 API 구현 +- [ ] 삭제 API를 구현 +- [ ] 요구사항 테스트 \ No newline at end of file From 6a38973ef3629f6634312a98a4a6a255a971a713 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 12 May 2024 21:06:29 +0900 Subject: [PATCH 10/36] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20API=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../controller/ReservationController.java | 21 +++++++--- src/test/java/roomescape/MissionStepTest.java | 39 +++++++++++++++++++ 3 files changed, 56 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c9e23dad0..7e083cee1 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ **예약 목록 조회 API** - [x] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 - [x] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 -- [ ] 요구사항 테스트 +- [x] 요구사항 테스트

3단계 요구사항

-- [ ] 예약 추가 API 구현 +- [x] 예약 추가 API 구현 - [ ] 삭제 API를 구현 - [ ] 요구사항 테스트 \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index fb2bd4eac..ea1f30796 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -3,16 +3,17 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.*; import roomescape.domain.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 final AtomicLong index = new AtomicLong(0); //예약을 위한 ID @GetMapping("/reservation") public String reservation() { @@ -21,11 +22,19 @@ public String reservation() { @GetMapping("/reservations") public ResponseEntity> getReservations() { - List reservationList = new ArrayList<>(); - reservationList.add(new Reservation(1, "브라운", "2023-01-01", "10:00")); - reservationList.add(new Reservation(2, "브라운", "2023-01-02", "11:00")); - return ResponseEntity.status(HttpStatus.OK).body(reservationList); } + + @PostMapping("/reservations") + public ResponseEntity addReservation(@RequestBody Reservation request) { + int id = (int) index.incrementAndGet(); + Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime()); + reservations.add(reservation); + return ResponseEntity.status(HttpStatus.CREATED) + .header("Location", "/reservations/" + id) + .body(reservation); + } + + } diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index bafd430a9..a4494ca42 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) @@ -31,4 +36,38 @@ public class MissionStepTest { .statusCode(200) .body("size()", is(2)); } + + @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 d9ba166062d61dd46feffa236ea1e76c8aacfadd Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 13 May 2024 00:03:45 +0900 Subject: [PATCH 11/36] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 30 +++++++-- .../java/roomescape/domain/Reservation.java | 6 +- src/test/java/roomescape/MissionStepTest.java | 65 ++++++++++--------- 3 files changed, 62 insertions(+), 39 deletions(-) diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index ea1f30796..455fa172d 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -6,14 +6,17 @@ import org.springframework.web.bind.annotation.*; import roomescape.domain.Reservation; +import java.lang.reflect.Member; +import java.net.URI; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.atomic.AtomicLong; @Controller public class ReservationController { private List reservations = new ArrayList<>(); - private final AtomicLong index = new AtomicLong(0); //예약을 위한 ID + private final AtomicLong index = new AtomicLong(0); @GetMapping("/reservation") public String reservation() { @@ -23,17 +26,32 @@ public String reservation() { @GetMapping("/reservations") public ResponseEntity> getReservations() { List reservationList = new ArrayList<>(); - return ResponseEntity.status(HttpStatus.OK).body(reservationList); + return ResponseEntity.ok(reservations); } + @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { - int id = (int) index.incrementAndGet(); + long id = index.incrementAndGet(); Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime()); reservations.add(reservation); - return ResponseEntity.status(HttpStatus.CREATED) - .header("Location", "/reservations/" + id) - .body(reservation); + + URI location = URI.create("/reservations/" + id); + + return ResponseEntity.created(location).body(reservation); + } + + + @DeleteMapping("/reservations/{id}") + public ResponseEntity cancelReservation(@PathVariable long id) { + Reservation reservation = reservations.stream() + .filter(it -> Objects.equals(it.getId(), id)) + .findFirst() + .orElseThrow(IllegalArgumentException::new); + + reservations.remove(reservation); + + return ResponseEntity.noContent().build(); // 성공(204) 상태 코드 반환 } diff --git a/src/main/java/roomescape/domain/Reservation.java b/src/main/java/roomescape/domain/Reservation.java index c03669d5c..9e230aea5 100644 --- a/src/main/java/roomescape/domain/Reservation.java +++ b/src/main/java/roomescape/domain/Reservation.java @@ -3,19 +3,19 @@ import java.time.LocalDateTime; public class Reservation { - private int id; + private long id; private String name; private String date; private String time; - public Reservation(int id, String name, String date, 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 int getId() { + public long getId() { return id; } diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index a4494ca42..990b1fe9b 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -2,6 +2,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.annotation.DirtiesContext; @@ -14,7 +15,6 @@ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class MissionStepTest { - @Test void 일단계() { RestAssured.given().log().all() @@ -34,40 +34,45 @@ public class MissionStepTest { .when().get("/reservations") .then().log().all() .statusCode(200) - .body("size()", is(2)); + .body("size()", is(0)); } - @Test - void 삼단계() { - Map params = new HashMap<>(); - params.put("name", "브라운"); - params.put("date", "2023-08-05"); - params.put("time", "15:40"); + @Nested + class 삼단계 { + @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() + .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().get("/reservations") + .then().log().all() + .statusCode(200) + .body("size()", is(1)); - RestAssured.given().log().all() - .when().delete("/reservations/1") - .then().log().all() - .statusCode(204); + } + @Test + void 예약_취소_확인() { + RestAssured.given().log().all() + .when().delete("/reservations/1") + .then().log().all() + .statusCode(204); + + RestAssured.given().log().all() + .when().get("/reservations") + .then().log().all(); + } - RestAssured.given().log().all() - .when().get("/reservations") - .then().log().all() - .statusCode(200) - .body("size()", is(0)); } } From d4361516f01a9766a66d5a10debac01b34935675 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 13 May 2024 00:12:49 +0900 Subject: [PATCH 12/36] =?UTF-8?q?docs:=204=EB=8B=A8=EA=B3=84=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7e083cee1..28bafb05c 100644 --- a/README.md +++ b/README.md @@ -19,5 +19,9 @@

3단계 요구사항

- [x] 예약 추가 API 구현 -- [ ] 삭제 API를 구현 -- [ ] 요구사항 테스트 \ No newline at end of file +- [x] 삭제 API 구현 +- [x] 요구사항 테스트 + +

4단계 요구사항

+- [ ] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 +- [ ] 그외의 예외상황 처리하기 \ No newline at end of file From 5242bc432c432435f7b788886a5c22ea2a5d2944 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 13 May 2024 00:31:21 +0900 Subject: [PATCH 13/36] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=ED=85=8C=EC=8A=A4=ED=8A=B8=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/exception/Excetpion.java | 8 ++++++ .../controller/ReservationController.java | 2 +- src/test/java/roomescape/MissionStepTest.java | 27 ++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/main/java/exception/Excetpion.java diff --git a/src/main/java/exception/Excetpion.java b/src/main/java/exception/Excetpion.java new file mode 100644 index 000000000..d8b36197b --- /dev/null +++ b/src/main/java/exception/Excetpion.java @@ -0,0 +1,8 @@ +package exception; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; + +public class Excetpion { + +} diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 455fa172d..cf425a730 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -47,7 +47,7 @@ public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() .filter(it -> Objects.equals(it.getId(), id)) .findFirst() - .orElseThrow(IllegalArgumentException::new); + .orElse(null); reservations.remove(reservation); diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 990b1fe9b..22a19ca67 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -64,6 +64,7 @@ class 삼단계 { } @Test void 예약_취소_확인() { + RestAssured.given().log().all() .when().delete("/reservations/1") .then().log().all() @@ -71,8 +72,32 @@ class 삼단계 { RestAssured.given().log().all() .when().get("/reservations") - .then().log().all(); + .then().log().all() + .statusCode(200) + .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 c43e527a2a1add290c51911d0f51116443b9fbb1 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 13 May 2024 01:47:42 +0900 Subject: [PATCH 14/36] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]InvalidReque?= =?UTF-8?q?stException=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/exception/Excetpion.java | 8 -------- .../roomescape/ReservationExceptionHandler.java | 15 +++++++++++++++ .../controller/ReservationController.java | 11 ++++++++--- .../exception/InvalidRequestException.java | 8 ++++++++ src/test/java/roomescape/MissionStepTest.java | 2 +- 5 files changed, 32 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/exception/Excetpion.java create mode 100644 src/main/java/roomescape/ReservationExceptionHandler.java create mode 100644 src/main/java/roomescape/exception/InvalidRequestException.java diff --git a/src/main/java/exception/Excetpion.java b/src/main/java/exception/Excetpion.java deleted file mode 100644 index d8b36197b..000000000 --- a/src/main/java/exception/Excetpion.java +++ /dev/null @@ -1,8 +0,0 @@ -package exception; - -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ExceptionHandler; - -public class Excetpion { - -} diff --git a/src/main/java/roomescape/ReservationExceptionHandler.java b/src/main/java/roomescape/ReservationExceptionHandler.java new file mode 100644 index 000000000..c5509c087 --- /dev/null +++ b/src/main/java/roomescape/ReservationExceptionHandler.java @@ -0,0 +1,15 @@ +package roomescape; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import roomescape.exception.InvalidRequestException; + +@ControllerAdvice +public class ReservationExceptionHandler { + @ExceptionHandler(InvalidRequestException.class) + public ResponseEntity handleInvalidRequestException(InvalidRequestException e) { + return ResponseEntity.badRequest().build(); + } + +} diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index cf425a730..d52b1f7fe 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -1,12 +1,12 @@ package roomescape.controller; -import org.springframework.http.HttpStatus; +import io.micrometer.common.util.StringUtils; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import roomescape.domain.Reservation; +import roomescape.exception.InvalidRequestException; -import java.lang.reflect.Member; import java.net.URI; import java.util.ArrayList; import java.util.List; @@ -32,6 +32,10 @@ public ResponseEntity> getReservations() { @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { + if (StringUtils.isBlank(request.getName()) || StringUtils.isBlank(request.getDate()) || StringUtils.isBlank(request.getTime())) { + throw new InvalidRequestException("예약 정보에 공백이 입력되었습니다."); + } + long id = index.incrementAndGet(); Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime()); reservations.add(reservation); @@ -42,6 +46,7 @@ public ResponseEntity addReservation(@RequestBody Reservation reque } + @DeleteMapping("/reservations/{id}") public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() @@ -51,7 +56,7 @@ public ResponseEntity cancelReservation(@PathVariable long id) { reservations.remove(reservation); - return ResponseEntity.noContent().build(); // 성공(204) 상태 코드 반환 + return ResponseEntity.noContent().build(); } diff --git a/src/main/java/roomescape/exception/InvalidRequestException.java b/src/main/java/roomescape/exception/InvalidRequestException.java new file mode 100644 index 000000000..b9a1cd406 --- /dev/null +++ b/src/main/java/roomescape/exception/InvalidRequestException.java @@ -0,0 +1,8 @@ +package roomescape.exception; + +public class InvalidRequestException extends RuntimeException { + public InvalidRequestException(String message) { + super(message); + } +} + diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 22a19ca67..8826b910b 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -94,7 +94,7 @@ class 삼단계 { .then().log().all() .statusCode(400); - // 삭제할 예약이 없는 경우 + //삭제할 예약이 없는 경우 RestAssured.given().log().all() .when().delete("/reservations/1") .then().log().all() From 52fb4c0bf488f0c4dad90a7fe823d00efa38f808 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 13 May 2024 01:53:22 +0900 Subject: [PATCH 15/36] =?UTF-8?q?feat:=20[4=EB=8B=A8=EA=B3=84]NotFoundRese?= =?UTF-8?q?rvationException=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/ReservationExceptionHandler.java | 6 ++++++ .../java/roomescape/controller/ReservationController.java | 3 ++- .../roomescape/exception/NotFoundReservationException.java | 7 +++++++ .../java/roomescape/exception/ReservationException.java | 7 +++++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/main/java/roomescape/exception/NotFoundReservationException.java create mode 100644 src/main/java/roomescape/exception/ReservationException.java diff --git a/src/main/java/roomescape/ReservationExceptionHandler.java b/src/main/java/roomescape/ReservationExceptionHandler.java index c5509c087..9e297c5b0 100644 --- a/src/main/java/roomescape/ReservationExceptionHandler.java +++ b/src/main/java/roomescape/ReservationExceptionHandler.java @@ -4,6 +4,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import roomescape.exception.InvalidRequestException; +import roomescape.exception.NotFoundReservationException; @ControllerAdvice public class ReservationExceptionHandler { @@ -12,4 +13,9 @@ public ResponseEntity handleInvalidRequestException(InvalidRequestException e) { return ResponseEntity.badRequest().build(); } + @ExceptionHandler(NotFoundReservationException.class) + public ResponseEntity handleNotFoundReservationException(NotFoundReservationException e) { + return ResponseEntity.badRequest().build(); + } + } diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index d52b1f7fe..74e8b1e8b 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.*; import roomescape.domain.Reservation; import roomescape.exception.InvalidRequestException; +import roomescape.exception.NotFoundReservationException; import java.net.URI; import java.util.ArrayList; @@ -52,7 +53,7 @@ public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() .filter(it -> Objects.equals(it.getId(), id)) .findFirst() - .orElse(null); + .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); reservations.remove(reservation); diff --git a/src/main/java/roomescape/exception/NotFoundReservationException.java b/src/main/java/roomescape/exception/NotFoundReservationException.java new file mode 100644 index 000000000..fc783c22b --- /dev/null +++ b/src/main/java/roomescape/exception/NotFoundReservationException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class NotFoundReservationException extends ReservationException { + public NotFoundReservationException(String message) { + super(message); + } +} diff --git a/src/main/java/roomescape/exception/ReservationException.java b/src/main/java/roomescape/exception/ReservationException.java new file mode 100644 index 000000000..35178e682 --- /dev/null +++ b/src/main/java/roomescape/exception/ReservationException.java @@ -0,0 +1,7 @@ +package roomescape.exception; + +public class ReservationException extends RuntimeException { + public ReservationException(String message) { + super(message); + } +} From 2443995532a06c2e5d3c81f82e29deffddfa22e9 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Tue, 14 May 2024 11:30:48 +0900 Subject: [PATCH 16/36] =?UTF-8?q?fix:=20=EA=B3=B5=EB=B0=B1=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 +++++-- .../ReservationExceptionHandler.java | 2 +- .../roomescape/RoomescapeApplication.java | 23 ------------------- .../controller/ReservationController.java | 4 +--- .../exception/InvalidRequestException.java | 3 +-- .../NotFoundReservationException.java | 2 +- .../exception/ReservationException.java | 2 +- 7 files changed, 11 insertions(+), 33 deletions(-) delete mode 100644 src/main/java/roomescape/RoomescapeApplication.java diff --git a/README.md b/README.md index 28bafb05c..68162ad55 100644 --- a/README.md +++ b/README.md @@ -23,5 +23,9 @@ - [x] 요구사항 테스트

4단계 요구사항

-- [ ] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 -- [ ] 그외의 예외상황 처리하기 \ No newline at end of file + +- [x] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 + - 필수 인자가 없는경우 + - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 +- [ ] 그외의 예외상황 처리하기 + - 형식이 어긋난 경우 \ No newline at end of file diff --git a/src/main/java/roomescape/ReservationExceptionHandler.java b/src/main/java/roomescape/ReservationExceptionHandler.java index 9e297c5b0..e6d86e19d 100644 --- a/src/main/java/roomescape/ReservationExceptionHandler.java +++ b/src/main/java/roomescape/ReservationExceptionHandler.java @@ -18,4 +18,4 @@ public ResponseEntity handleNotFoundReservationException(NotFoundReservationExce return ResponseEntity.badRequest().build(); } -} +} \ No newline at end of file diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java deleted file mode 100644 index 02fa8dd35..000000000 --- a/src/main/java/roomescape/RoomescapeApplication.java +++ /dev/null @@ -1,23 +0,0 @@ -package roomescape; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.annotation.Bean; -import org.springframework.web.servlet.ViewResolver; -import org.springframework.web.servlet.view.InternalResourceViewResolver; - -@SpringBootApplication -public class RoomescapeApplication { - public static void main(String[] args) { - SpringApplication.run(RoomescapeApplication.class, args); - } - - @Bean - public ViewResolver getViewResolver() { - InternalResourceViewResolver resolver = new InternalResourceViewResolver(); - resolver.setPrefix("/WEB-INF/views/"); - resolver.setSuffix(".html"); - return resolver; - } - -} diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 74e8b1e8b..11c93e3e2 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -47,7 +47,6 @@ public ResponseEntity addReservation(@RequestBody Reservation reque } - @DeleteMapping("/reservations/{id}") public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() @@ -60,5 +59,4 @@ public ResponseEntity cancelReservation(@PathVariable long id) { return ResponseEntity.noContent().build(); } - -} +} \ No newline at end of file diff --git a/src/main/java/roomescape/exception/InvalidRequestException.java b/src/main/java/roomescape/exception/InvalidRequestException.java index b9a1cd406..4b610f68d 100644 --- a/src/main/java/roomescape/exception/InvalidRequestException.java +++ b/src/main/java/roomescape/exception/InvalidRequestException.java @@ -4,5 +4,4 @@ public class InvalidRequestException extends RuntimeException { public InvalidRequestException(String message) { super(message); } -} - +} \ No newline at end of file diff --git a/src/main/java/roomescape/exception/NotFoundReservationException.java b/src/main/java/roomescape/exception/NotFoundReservationException.java index fc783c22b..ea8ffbe8f 100644 --- a/src/main/java/roomescape/exception/NotFoundReservationException.java +++ b/src/main/java/roomescape/exception/NotFoundReservationException.java @@ -4,4 +4,4 @@ public class NotFoundReservationException extends ReservationException { public NotFoundReservationException(String message) { super(message); } -} +} \ No newline at end of file diff --git a/src/main/java/roomescape/exception/ReservationException.java b/src/main/java/roomescape/exception/ReservationException.java index 35178e682..cc0e6892d 100644 --- a/src/main/java/roomescape/exception/ReservationException.java +++ b/src/main/java/roomescape/exception/ReservationException.java @@ -4,4 +4,4 @@ public class ReservationException extends RuntimeException { public ReservationException(String message) { super(message); } -} +} \ No newline at end of file From 23c474139796e023388c2f1db301d1e1fbfbc2d8 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Thu, 16 May 2024 00:00:45 +0900 Subject: [PATCH 17/36] =?UTF-8?q?fix:=20=EC=98=88=EC=99=B8=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EC=83=81=EC=88=98=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/RoomescapeApplication.java | 11 +++++++++++ .../roomescape/controller/ReservationController.java | 7 +++++-- 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 src/main/java/roomescape/RoomescapeApplication.java diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java new file mode 100644 index 000000000..a2819b79b --- /dev/null +++ b/src/main/java/roomescape/RoomescapeApplication.java @@ -0,0 +1,11 @@ +package roomescape; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RoomescapeApplication { + public static void main(String[] args) { + SpringApplication.run(RoomescapeApplication.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 11c93e3e2..26667498b 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -16,6 +16,9 @@ @Controller public class ReservationController { + private final String InvalidRequestExceptionMessage = "예약 정보에 공백이 입력되었습니다."; + private final String NotFoundReservationExceptionMessage = "삭제할 예약을 찾을 수 없습니다."; + private List reservations = new ArrayList<>(); private final AtomicLong index = new AtomicLong(0); @@ -34,7 +37,7 @@ public ResponseEntity> getReservations() { @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { if (StringUtils.isBlank(request.getName()) || StringUtils.isBlank(request.getDate()) || StringUtils.isBlank(request.getTime())) { - throw new InvalidRequestException("예약 정보에 공백이 입력되었습니다."); + throw new InvalidRequestException(InvalidRequestExceptionMessage); } long id = index.incrementAndGet(); @@ -52,7 +55,7 @@ public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() .filter(it -> Objects.equals(it.getId(), id)) .findFirst() - .orElseThrow(() -> new NotFoundReservationException("예약을 찾을 수 없습니다.")); + .orElseThrow(() -> new NotFoundReservationException(NotFoundReservationExceptionMessage)); reservations.remove(reservation); From d9f05916a9862fbd9b4132ff88eb21b2c4c08def Mon Sep 17 00:00:00 2001 From: DaYeong Date: Thu, 16 May 2024 00:15:40 +0900 Subject: [PATCH 18/36] =?UTF-8?q?fix:=20=EC=98=88=EC=99=B8=20=EB=AC=B8?= =?UTF-8?q?=EA=B5=AC=20=EC=9E=AC=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/roomescape/controller/ReservationController.java | 8 ++++---- src/main/java/roomescape/domain/Reservation.java | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 26667498b..24c1dd925 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -16,8 +16,8 @@ @Controller public class ReservationController { - private final String InvalidRequestExceptionMessage = "예약 정보에 공백이 입력되었습니다."; - private final String NotFoundReservationExceptionMessage = "삭제할 예약을 찾을 수 없습니다."; + private final String INVALID_REQUEST_MESSAGE = "예약 정보에 공백이 입력되었습니다."; + private final String NOT_FOUND_RESERVATION_MESSAGE = "삭제할 예약을 찾을 수 없습니다."; private List reservations = new ArrayList<>(); private final AtomicLong index = new AtomicLong(0); @@ -37,7 +37,7 @@ public ResponseEntity> getReservations() { @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { if (StringUtils.isBlank(request.getName()) || StringUtils.isBlank(request.getDate()) || StringUtils.isBlank(request.getTime())) { - throw new InvalidRequestException(InvalidRequestExceptionMessage); + throw new InvalidRequestException(INVALID_REQUEST_MESSAGE); } long id = index.incrementAndGet(); @@ -55,7 +55,7 @@ public ResponseEntity cancelReservation(@PathVariable long id) { Reservation reservation = reservations.stream() .filter(it -> Objects.equals(it.getId(), id)) .findFirst() - .orElseThrow(() -> new NotFoundReservationException(NotFoundReservationExceptionMessage)); + .orElseThrow(() -> new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE)); reservations.remove(reservation); diff --git a/src/main/java/roomescape/domain/Reservation.java b/src/main/java/roomescape/domain/Reservation.java index 9e230aea5..1aaefa8bb 100644 --- a/src/main/java/roomescape/domain/Reservation.java +++ b/src/main/java/roomescape/domain/Reservation.java @@ -8,6 +8,8 @@ public class Reservation { private String date; private String time; + + public Reservation(long id, String name, String date, String time) { this.id = id; this.name = name; From d07daf82f15bd60a07297c69f9a23cb0e6b33c04 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Thu, 16 May 2024 00:29:28 +0900 Subject: [PATCH 19/36] =?UTF-8?q?fix:=20=EC=9C=A0=ED=9A=A8=EC=84=B1?= =?UTF-8?q?=EA=B2=80=EC=A6=9D=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 5 +---- src/main/java/roomescape/domain/Reservation.java | 16 ++++++++++++++-- .../ReservationExceptionHandler.java | 4 +--- 3 files changed, 16 insertions(+), 9 deletions(-) rename src/main/java/roomescape/{ => exception}/ReservationExceptionHandler.java (83%) diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 24c1dd925..afbbff73f 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -16,7 +16,6 @@ @Controller public class ReservationController { - private final String INVALID_REQUEST_MESSAGE = "예약 정보에 공백이 입력되었습니다."; private final String NOT_FOUND_RESERVATION_MESSAGE = "삭제할 예약을 찾을 수 없습니다."; private List reservations = new ArrayList<>(); @@ -36,9 +35,7 @@ public ResponseEntity> getReservations() { @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { - if (StringUtils.isBlank(request.getName()) || StringUtils.isBlank(request.getDate()) || StringUtils.isBlank(request.getTime())) { - throw new InvalidRequestException(INVALID_REQUEST_MESSAGE); - } + request.validate(); long id = index.incrementAndGet(); Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime()); diff --git a/src/main/java/roomescape/domain/Reservation.java b/src/main/java/roomescape/domain/Reservation.java index 1aaefa8bb..2e2b2aaff 100644 --- a/src/main/java/roomescape/domain/Reservation.java +++ b/src/main/java/roomescape/domain/Reservation.java @@ -1,6 +1,8 @@ package roomescape.domain; -import java.time.LocalDateTime; +import roomescape.exception.InvalidRequestException; + +import java.util.Objects; public class Reservation { private long id; @@ -8,7 +10,7 @@ public class Reservation { private String date; private String time; - + private final String INVALID_REQUEST_MESSAGE = "예약 정보에 공백이 입력되었습니다."; public Reservation(long id, String name, String date, String time) { this.id = id; @@ -32,4 +34,14 @@ public String getName() { public String getTime() { return time; } + + public void validate() { + if (isBlank(name) || isBlank(date) || isBlank(time)) { + throw new InvalidRequestException(INVALID_REQUEST_MESSAGE); + } + } + + private boolean isBlank(String str) { + return str == null || str.trim().isEmpty(); + } } \ No newline at end of file diff --git a/src/main/java/roomescape/ReservationExceptionHandler.java b/src/main/java/roomescape/exception/ReservationExceptionHandler.java similarity index 83% rename from src/main/java/roomescape/ReservationExceptionHandler.java rename to src/main/java/roomescape/exception/ReservationExceptionHandler.java index e6d86e19d..83af9463a 100644 --- a/src/main/java/roomescape/ReservationExceptionHandler.java +++ b/src/main/java/roomescape/exception/ReservationExceptionHandler.java @@ -1,10 +1,8 @@ -package roomescape; +package roomescape.exception; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; -import roomescape.exception.InvalidRequestException; -import roomescape.exception.NotFoundReservationException; @ControllerAdvice public class ReservationExceptionHandler { From 1f4e8b15f57f2b5227b2cc7c36a869cc30bff4b2 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Thu, 16 May 2024 00:37:33 +0900 Subject: [PATCH 20/36] =?UTF-8?q?docs:=20=EC=9A=94=EA=B5=AC=EC=82=AC?= =?UTF-8?q?=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 68162ad55..f8289dc6c 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,4 @@ - [x] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 - 필수 인자가 없는경우 - - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 -- [ ] 그외의 예외상황 처리하기 - - 형식이 어긋난 경우 \ No newline at end of file + - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 \ No newline at end of file From 98fa17032c66d3f009ef3cd3aaf08546c33521af Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 18:46:00 +0900 Subject: [PATCH 21/36] =?UTF-8?q?docs:=20[5=EB=8B=A8=EA=B3=84]=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 ++++++++- build.gradle | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f8289dc6c..6278532a6 100644 --- a/README.md +++ b/README.md @@ -26,4 +26,11 @@ - [x] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 - 필수 인자가 없는경우 - - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 \ No newline at end of file + - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 + +

5단계 요구사항

+h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 +- [ ] gradle 의존성 추가 +- [ ] 테이블 스키마 정의 +- [ ] 데이터베이스 설정 +- [ ] 요구 사항 테스트 진행 \ No newline at end of file diff --git a/build.gradle b/build.gradle index b11bfe1be..bc77142e1 100644 --- a/build.gradle +++ b/build.gradle @@ -19,8 +19,9 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' + } test { useJUnitPlatform() -} +} \ No newline at end of file From b1f8f59d43d2fc95e965bb5d09c1b9cce460a57e Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 18:48:37 +0900 Subject: [PATCH 22/36] =?UTF-8?q?docs:=20[5=EB=8B=A8=EA=B3=84]=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6278532a6..ee649ff71 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우

5단계 요구사항

+ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 - [ ] gradle 의존성 추가 - [ ] 테이블 스키마 정의 From 6860177611d3b6377262213d89f4d68480c42d42 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 18:52:02 +0900 Subject: [PATCH 23/36] =?UTF-8?q?chore:=20jdbc,=20h2=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bc77142e1..c753fe7c2 100644 --- a/build.gradle +++ b/build.gradle @@ -16,10 +16,12 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter' + implementation 'org.springframework.boot:spring-boot-starter-jdbc' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' - + + runtimeOnly 'com.h2database:h2' } test { From 9564f6eeb9440c097c2a8972172837c48971adb5 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 18:56:16 +0900 Subject: [PATCH 24/36] =?UTF-8?q?chore:=20schema=20=ED=8C=8C=EC=9D=BC,=20?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EB=B8=94=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- build.gradle | 2 +- src/main/resources/schema.sql | 8 ++++++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/schema.sql diff --git a/README.md b/README.md index ee649ff71..88ba34fab 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@

5단계 요구사항

h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 -- [ ] gradle 의존성 추가 -- [ ] 테이블 스키마 정의 +- [x] gradle 의존성 추가 +- [x] 테이블 스키마 정의 - [ ] 데이터베이스 설정 - [ ] 요구 사항 테스트 진행 \ No newline at end of file diff --git a/build.gradle b/build.gradle index c753fe7c2..1b4e93e06 100644 --- a/build.gradle +++ b/build.gradle @@ -20,7 +20,7 @@ dependencies { testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' - + runtimeOnly 'com.h2database:h2' } diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql new file mode 100644 index 000000000..f5ef3d5f5 --- /dev/null +++ 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) +); \ No newline at end of file From 0f7a02b21b17bc8f69d8d7aecbb2225790e56b67 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 19:05:59 +0900 Subject: [PATCH 25/36] =?UTF-8?q?chore:=20H2=20DB=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e69de29bb..a68f6a662 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -0,0 +1,4 @@ +# h2-console ??? ?? +spring.h2.console.enabled=true +# db url +spring.datasource.url=jdbc:h2:mem:test \ No newline at end of file From 9f787e875a084c13b63fd5e0409268c9e166e789 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 19:06:42 +0900 Subject: [PATCH 26/36] =?UTF-8?q?chore:=20H2=20DB=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.properties | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a68f6a662..f597afeef 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,4 +1,3 @@ -# h2-console ??? ?? spring.h2.console.enabled=true -# db url -spring.datasource.url=jdbc:h2:mem:test \ No newline at end of file +spring.h2.console.path=/h2-console +spring.datasource.url=jdbc:h2:mem:database \ No newline at end of file From 369ed2e0aa4e5e33f5a253faa467a006a8b32909 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 19:23:23 +0900 Subject: [PATCH 27/36] =?UTF-8?q?test:=20[5=EB=8B=A8=EA=B3=84]=ED=95=99?= =?UTF-8?q?=EC=8A=B5=ED=85=8C=EC=8A=A4=ED=8A=B8=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 + src/test/java/roomescape/MissionStepTest.java | 3 +- src/test/java/roomescape/SpringJdbcTest.java | 31 +++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/test/java/roomescape/SpringJdbcTest.java diff --git a/build.gradle b/build.gradle index 1b4e93e06..2a6203bac 100644 --- a/build.gradle +++ b/build.gradle @@ -18,6 +18,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-jdbc' + testImplementation 'org.assertj:assertj-core:3.20.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'io.rest-assured:rest-assured:5.3.1' diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 8826b910b..6f2600d75 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -100,4 +100,5 @@ class 삼단계 { .then().log().all() .statusCode(400); } -} + +} \ No newline at end of file diff --git a/src/test/java/roomescape/SpringJdbcTest.java b/src/test/java/roomescape/SpringJdbcTest.java new file mode 100644 index 000000000..7b3f3fd36 --- /dev/null +++ b/src/test/java/roomescape/SpringJdbcTest.java @@ -0,0 +1,31 @@ +package roomescape; + +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 java.sql.Connection; +import java.sql.SQLException; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) +public class SpringJdbcTest { + + @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); + } + } +} \ No newline at end of file From 7b9ff9e62f5810c5407cf3ae341a7c0530bff49e Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 19:26:52 +0900 Subject: [PATCH 28/36] =?UTF-8?q?docs:=20[6=EB=8B=A8=EA=B3=84]=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 42 +++++++++++------------------------------- 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 88ba34fab..f343b3fe8 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,17 @@ -# Spring MVC - -

1단계 요구사항

- -- [x] localhost:8080 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현 - -

2단계 요구사항

- -**예약 페이지** -- [x] /reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현 - - 어드민 메인 페이지는 templates/reservation.html 파일 사용 -- [x] Thymeleaf 템플릿엔진을 활용하여 페이지를 응답 - -**예약 목록 조회 API** -- [x] 예약 목록 조회 API , 예약 페이지 요청과 예약 목록 조회 요청 처리 매서드 구현 -- [x] 정상 동작 확인을 위해 임의 데이터를 넣어서 확인 -- [x] 요구사항 테스트 - -

3단계 요구사항

- -- [x] 예약 추가 API 구현 -- [x] 삭제 API 구현 -- [x] 요구사항 테스트 - -

4단계 요구사항

- -- [x] 예약 관련 API 호출 시 에러가 발생하는 경우 중 요청의 문제인 경우 Status Code를 400으로 응답 - - 필수 인자가 없는경우 - - 삭제 할 예약의 식별자로 저장된 예약을 찾을 수 없는 경우 +# Spring JDBC

5단계 요구사항

h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 - [x] gradle 의존성 추가 - [x] 테이블 스키마 정의 -- [ ] 데이터베이스 설정 -- [ ] 요구 사항 테스트 진행 \ No newline at end of file +- [x] 데이터베이스 설정 +- [x] 요구 사항 테스트 진행 + +

6단계 요구사항

+ +예약 조회 API 처리 로직에서 저장된 예약을 조회할 때 데이터베이스를 활용하도록 수정 +- [ ] 데이터를 조회하는 기능을 구현 + - SQL - SELECT 쿼리 + - JdbcTemplate +- [ ] 요구 사항 테스트 추가 \ No newline at end of file From ccc556eaa4fc0da77d546a7ee1c3d853ec910b40 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 19 May 2024 19:37:22 +0900 Subject: [PATCH 29/36] =?UTF-8?q?test:=20[7=EB=8B=A8=EA=B3=84]=20=EC=9A=94?= =?UTF-8?q?=EA=B5=AC=EC=82=AC=ED=95=AD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f343b3fe8..87a9e0965 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,11 @@ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 - [ ] 데이터를 조회하는 기능을 구현 - SQL - SELECT 쿼리 - JdbcTemplate +- [ ] 요구 사항 테스트 추가 + +

7단계 요구사항

+데이터 추가/삭제하기 + +- [ ] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 + - 기존에 사용하던 List 및 AtomicLong 제거 - [ ] 요구 사항 테스트 추가 \ No newline at end of file From 39d4e5705b6829209b837e627af71b2d87079619 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 20 May 2024 13:22:03 +0900 Subject: [PATCH 30/36] =?UTF-8?q?refactor:=20AtomicLong=EC=A0=9C=EA=B1=B0,?= =?UTF-8?q?=20=EC=BF=BC=EB=A6=AC=EB=AC=B8=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../roomescape/controller/HomeController.java | 1 - .../controller/ReservationController.java | 45 ++++++------- .../domain/ReservationRepository.java | 65 +++++++++++++++++++ .../ReservationExceptionHandler.java | 2 - src/main/resources/schema.sql | 3 +- src/test/java/roomescape/MissionStepTest.java | 3 +- src/test/java/roomescape/SpringJdbcTest.java | 7 +- 8 files changed, 96 insertions(+), 34 deletions(-) create mode 100644 src/main/java/roomescape/domain/ReservationRepository.java diff --git a/README.md b/README.md index 87a9e0965..721479d49 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정

6단계 요구사항

예약 조회 API 처리 로직에서 저장된 예약을 조회할 때 데이터베이스를 활용하도록 수정 -- [ ] 데이터를 조회하는 기능을 구현 +- [x] 데이터를 조회하는 기능을 구현 - SQL - SELECT 쿼리 - JdbcTemplate - [ ] 요구 사항 테스트 추가 @@ -19,6 +19,6 @@ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정

7단계 요구사항

데이터 추가/삭제하기 -- [ ] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 +- [x] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 - 기존에 사용하던 List 및 AtomicLong 제거 - [ ] 요구 사항 테스트 추가 \ No newline at end of file diff --git a/src/main/java/roomescape/controller/HomeController.java b/src/main/java/roomescape/controller/HomeController.java index 9d34d747c..5c6201381 100644 --- a/src/main/java/roomescape/controller/HomeController.java +++ b/src/main/java/roomescape/controller/HomeController.java @@ -10,5 +10,4 @@ public class HomeController { public String home() { return "home"; } - } \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index afbbff73f..6ba8d5847 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -1,62 +1,59 @@ package roomescape.controller; -import io.micrometer.common.util.StringUtils; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import roomescape.domain.Reservation; -import roomescape.exception.InvalidRequestException; +import roomescape.domain.ReservationRepository; import roomescape.exception.NotFoundReservationException; +import javax.sql.DataSource; import java.net.URI; -import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicLong; @Controller public class ReservationController { private final String NOT_FOUND_RESERVATION_MESSAGE = "삭제할 예약을 찾을 수 없습니다."; + private final ReservationRepository reservationRepository; - private List reservations = new ArrayList<>(); - private final AtomicLong index = new AtomicLong(0); + public ReservationController(DataSource dataSource) { + this.reservationRepository = new ReservationRepository(dataSource); + } @GetMapping("/reservation") public String reservation() { return "reservation"; } + @ResponseBody @GetMapping("/reservations") public ResponseEntity> getReservations() { - List reservationList = new ArrayList<>(); - return ResponseEntity.ok(reservations); + List reservationList = reservationRepository.findAll(); + return ResponseEntity.ok(reservationList); } - + @ResponseBody @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { request.validate(); - long id = index.incrementAndGet(); - Reservation reservation = new Reservation(id, request.getName(), request.getDate(), request.getTime()); - reservations.add(reservation); - - URI location = URI.create("/reservations/" + id); + long id = reservationRepository.save(request); + Reservation reservation = reservationRepository.findById(id); + URI location = URI.create("/reservations/" + id); // 생성된 예약의 ID를 사용하여 위치 헤더 값을 생성 return ResponseEntity.created(location).body(reservation); } - + @ResponseBody @DeleteMapping("/reservations/{id}") public ResponseEntity cancelReservation(@PathVariable long id) { - Reservation reservation = reservations.stream() - .filter(it -> Objects.equals(it.getId(), id)) - .findFirst() - .orElseThrow(() -> new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE)); - - reservations.remove(reservation); - - return ResponseEntity.noContent().build(); + long deletedId = reservationRepository.deleteById(id); + if (deletedId != -1) { + URI location = URI.create("/reservations/" + deletedId); + return ResponseEntity.noContent().location(location).build(); + } else { + throw new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE); + } } } \ No newline at end of file diff --git a/src/main/java/roomescape/domain/ReservationRepository.java b/src/main/java/roomescape/domain/ReservationRepository.java new file mode 100644 index 000000000..947f73f78 --- /dev/null +++ b/src/main/java/roomescape/domain/ReservationRepository.java @@ -0,0 +1,65 @@ +package roomescape.domain; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.GeneratedKeyHolder; +import org.springframework.jdbc.support.KeyHolder; + +import javax.sql.DataSource; +import java.sql.PreparedStatement; +import java.sql.Statement; +import java.util.List; + +public class ReservationRepository { + private final JdbcTemplate jdbcTemplate; + + public ReservationRepository(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + public List findAll() { + String sql = "SELECT id, name, date, time FROM reservation"; + return jdbcTemplate.query(sql, (rs, rowNum) -> { + long id = rs.getLong("id"); + String name = rs.getString("name"); + String date = rs.getString("date"); + String time = rs.getString("time"); + return new Reservation(id, name, date, time); + }); + } + + public Reservation findById(long id) { + String sql = "SELECT id, name, date, time FROM reservation WHERE id = ?"; + return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> { + long reservationId = rs.getLong("id"); + String name = rs.getString("name"); + String date = rs.getString("date"); + String time = rs.getString("time"); + return new Reservation(reservationId, name, date, time); + }); + } + + public long save(Reservation reservation) { + String sql = "INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)"; + KeyHolder keyHolder = new GeneratedKeyHolder(); + jdbcTemplate.update(connection -> { + PreparedStatement ps = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); + ps.setString(1, reservation.getName()); + ps.setString(2, reservation.getDate()); + ps.setString(3, reservation.getTime()); + return ps; + }, keyHolder); + + return keyHolder.getKey().longValue(); + } + + public long deleteById(long id) { + String sql = "DELETE FROM reservation WHERE id = ?"; + int rowsAffected = jdbcTemplate.update(sql, id); + if (rowsAffected > 0) { + return id; + } else { + return -1; + } + } + +} \ No newline at end of file diff --git a/src/main/java/roomescape/exception/ReservationExceptionHandler.java b/src/main/java/roomescape/exception/ReservationExceptionHandler.java index 83af9463a..ce8799f2f 100644 --- a/src/main/java/roomescape/exception/ReservationExceptionHandler.java +++ b/src/main/java/roomescape/exception/ReservationExceptionHandler.java @@ -10,10 +10,8 @@ public class ReservationExceptionHandler { public ResponseEntity handleInvalidRequestException(InvalidRequestException e) { return ResponseEntity.badRequest().build(); } - @ExceptionHandler(NotFoundReservationException.class) public ResponseEntity handleNotFoundReservationException(NotFoundReservationException e) { return ResponseEntity.badRequest().build(); } - } \ No newline at end of file diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql index f5ef3d5f5..e1b1bac33 100644 --- a/src/main/resources/schema.sql +++ b/src/main/resources/schema.sql @@ -1,5 +1,4 @@ -CREATE TABLE reservation -( +CREATE TABLE reservation ( id BIGINT NOT NULL AUTO_INCREMENT, name VARCHAR(255) NOT NULL, date VARCHAR(255) NOT NULL, diff --git a/src/test/java/roomescape/MissionStepTest.java b/src/test/java/roomescape/MissionStepTest.java index 6f2600d75..0b57d3167 100644 --- a/src/test/java/roomescape/MissionStepTest.java +++ b/src/test/java/roomescape/MissionStepTest.java @@ -62,6 +62,7 @@ class 삼단계 { .body("size()", is(1)); } + @Test void 예약_취소_확인() { @@ -76,7 +77,6 @@ class 삼단계 { .statusCode(200) .body("size()", is(0)); } - } @Test @@ -100,5 +100,4 @@ class 삼단계 { .then().log().all() .statusCode(400); } - } \ No newline at end of file diff --git a/src/test/java/roomescape/SpringJdbcTest.java b/src/test/java/roomescape/SpringJdbcTest.java index 7b3f3fd36..c6030690f 100644 --- a/src/test/java/roomescape/SpringJdbcTest.java +++ b/src/test/java/roomescape/SpringJdbcTest.java @@ -1,20 +1,25 @@ 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.domain.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.Assertions.assertThat; @SpringBootTest @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class SpringJdbcTest { - @Autowired private JdbcTemplate jdbcTemplate; From badc33e0af65e41862d5c1168bfbf849ffc08eb6 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 20 May 2024 14:18:36 +0900 Subject: [PATCH 31/36] =?UTF-8?q?test:=20[6=EB=8B=A8=EA=B3=84,7=EB=8B=A8?= =?UTF-8?q?=EA=B3=84]test=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/test/java/roomescape/SpringJdbcTest.java | 49 ++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/test/java/roomescape/SpringJdbcTest.java b/src/test/java/roomescape/SpringJdbcTest.java index c6030690f..4e2b32eec 100644 --- a/src/test/java/roomescape/SpringJdbcTest.java +++ b/src/test/java/roomescape/SpringJdbcTest.java @@ -2,6 +2,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -33,4 +34,52 @@ public class SpringJdbcTest { 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); + } + + @Nested + class 칠단계 { + @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); + } + + @Test + void 데이터_삭제_확인 () { + 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); + } + } } \ No newline at end of file From 8e3826831812c9bb0fa928a2a4c3742f10e9ccbb Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 20 May 2024 22:30:23 +0900 Subject: [PATCH 32/36] =?UTF-8?q?test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roomescape/RoomescapeApplication.java | 11 ---- .../controller/ReservationController.java | 17 +++--- .../java/roomescape/domain/Reservation.java | 2 - .../domain/ReservationRepository.java | 3 +- src/test/java/roomescape/SpringJdbcTest.java | 53 +++++++++---------- 5 files changed, 32 insertions(+), 54 deletions(-) delete mode 100644 src/main/java/roomescape/RoomescapeApplication.java diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java deleted file mode 100644 index a2819b79b..000000000 --- a/src/main/java/roomescape/RoomescapeApplication.java +++ /dev/null @@ -1,11 +0,0 @@ -package roomescape; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class RoomescapeApplication { - public static void main(String[] args) { - SpringApplication.run(RoomescapeApplication.class, args); - } -} \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 6ba8d5847..466a34301 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -25,35 +25,30 @@ public String reservation() { return "reservation"; } - @ResponseBody @GetMapping("/reservations") public ResponseEntity> getReservations() { List reservationList = reservationRepository.findAll(); return ResponseEntity.ok(reservationList); } - @ResponseBody @PostMapping("/reservations") public ResponseEntity addReservation(@RequestBody Reservation request) { request.validate(); long id = reservationRepository.save(request); Reservation reservation = reservationRepository.findById(id); - URI location = URI.create("/reservations/" + id); // 생성된 예약의 ID를 사용하여 위치 헤더 값을 생성 + URI location = URI.create("/reservations/" + id); return ResponseEntity.created(location).body(reservation); } - @ResponseBody @DeleteMapping("/reservations/{id}") public ResponseEntity cancelReservation(@PathVariable long id) { long deletedId = reservationRepository.deleteById(id); - if (deletedId != -1) { - URI location = URI.create("/reservations/" + deletedId); - return ResponseEntity.noContent().location(location).build(); - } else { - throw new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE); - } - } + URI location = URI.create("/reservations/" + deletedId); + ResponseEntity.noContent().location(location).build(); + + return ResponseEntity.noContent().build(); + } } \ No newline at end of file diff --git a/src/main/java/roomescape/domain/Reservation.java b/src/main/java/roomescape/domain/Reservation.java index 2e2b2aaff..514202642 100644 --- a/src/main/java/roomescape/domain/Reservation.java +++ b/src/main/java/roomescape/domain/Reservation.java @@ -2,8 +2,6 @@ import roomescape.exception.InvalidRequestException; -import java.util.Objects; - public class Reservation { private long id; private String name; diff --git a/src/main/java/roomescape/domain/ReservationRepository.java b/src/main/java/roomescape/domain/ReservationRepository.java index 947f73f78..ded037703 100644 --- a/src/main/java/roomescape/domain/ReservationRepository.java +++ b/src/main/java/roomescape/domain/ReservationRepository.java @@ -3,12 +3,14 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.support.GeneratedKeyHolder; import org.springframework.jdbc.support.KeyHolder; +import org.springframework.stereotype.Repository; import javax.sql.DataSource; import java.sql.PreparedStatement; import java.sql.Statement; import java.util.List; +@Repository public class ReservationRepository { private final JdbcTemplate jdbcTemplate; @@ -61,5 +63,4 @@ public long deleteById(long id) { return -1; } } - } \ No newline at end of file diff --git a/src/test/java/roomescape/SpringJdbcTest.java b/src/test/java/roomescape/SpringJdbcTest.java index 4e2b32eec..c6d772cad 100644 --- a/src/test/java/roomescape/SpringJdbcTest.java +++ b/src/test/java/roomescape/SpringJdbcTest.java @@ -18,7 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat; -@SpringBootTest +@SuppressWarnings("NonAsciiCharacters") +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class SpringJdbcTest { @Autowired @@ -26,7 +27,7 @@ public class SpringJdbcTest { @Test void 오단계() { - try (Connection connection = jdbcTemplate.getDataSource().getConnection()) { + try(Connection connection = jdbcTemplate.getDataSource().getConnection()) { assertThat(connection).isNotNull(); assertThat(connection.getCatalog()).isEqualTo("DATABASE"); assertThat(connection.getMetaData().getTables(null, null, "RESERVATION", null).next()).isTrue(); @@ -50,36 +51,30 @@ public class SpringJdbcTest { assertThat(reservations.size()).isEqualTo(count); } - @Nested - class 칠단계 { - @Test - void 데이터_삽입_확인() { - Map params = new HashMap<>(); - params.put("name", "브라운"); - params.put("date", "2023-08-05"); - params.put("time", "10:00"); + @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"); + 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); - } + Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class); + assertThat(count).isEqualTo(1); - @Test - void 데이터_삭제_확인 () { - RestAssured.given().log().all() - .when().delete("/reservations/1") - .then().log().all() - .statusCode(204); + 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); - } + Integer countAfterDelete = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class); + assertThat(countAfterDelete).isEqualTo(0); } } \ No newline at end of file From 24b78790fa0963407f83e736d76c8b6caa56d931 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Mon, 20 May 2024 23:13:17 +0900 Subject: [PATCH 33/36] =?UTF-8?q?feat:=20=EC=82=AD=EC=A0=9Capi=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- .../java/roomescape/controller/ReservationController.java | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 721479d49..72b4db608 100644 --- a/README.md +++ b/README.md @@ -14,11 +14,11 @@ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 - [x] 데이터를 조회하는 기능을 구현 - SQL - SELECT 쿼리 - JdbcTemplate -- [ ] 요구 사항 테스트 추가 +- [x] 요구 사항 테스트 추가

7단계 요구사항

데이터 추가/삭제하기 - [x] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 - 기존에 사용하던 List 및 AtomicLong 제거 -- [ ] 요구 사항 테스트 추가 \ No newline at end of file +- [x] 요구 사항 테스트 추가 \ No newline at end of file diff --git a/src/main/java/roomescape/controller/ReservationController.java b/src/main/java/roomescape/controller/ReservationController.java index 466a34301..f23e5f93a 100644 --- a/src/main/java/roomescape/controller/ReservationController.java +++ b/src/main/java/roomescape/controller/ReservationController.java @@ -46,6 +46,10 @@ public ResponseEntity addReservation(@RequestBody Reservation reque public ResponseEntity cancelReservation(@PathVariable long id) { long deletedId = reservationRepository.deleteById(id); + if (deletedId == -1) { + throw new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE); + } + URI location = URI.create("/reservations/" + deletedId); ResponseEntity.noContent().location(location).build(); From 05053eb0c04964a29f86b4ad82880091dfd2f83b Mon Sep 17 00:00:00 2001 From: day024 <92675692+day024@users.noreply.github.com> Date: Sun, 26 May 2024 22:06:46 +0900 Subject: [PATCH 34/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72b4db608..cf89b3b7f 100644 --- a/README.md +++ b/README.md @@ -21,4 +21,4 @@ h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 - [x] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 - 기존에 사용하던 List 및 AtomicLong 제거 -- [x] 요구 사항 테스트 추가 \ No newline at end of file +- [x] 요구 사항 테스트 추가 From 810a6a0d271b46fedcf9df460e85d2469ff0e3e3 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Sun, 26 May 2024 22:12:22 +0900 Subject: [PATCH 35/36] =?UTF-8?q?fix:=20conflicts=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/roomescape/RoomescapeApplication.java | 11 +++++++++++ src/test/java/roomescape/SpringJdbcTest.java | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 src/main/java/roomescape/RoomescapeApplication.java diff --git a/src/main/java/roomescape/RoomescapeApplication.java b/src/main/java/roomescape/RoomescapeApplication.java new file mode 100644 index 000000000..a2819b79b --- /dev/null +++ b/src/main/java/roomescape/RoomescapeApplication.java @@ -0,0 +1,11 @@ +package roomescape; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RoomescapeApplication { + public static void main(String[] args) { + SpringApplication.run(RoomescapeApplication.class, args); + } +} \ No newline at end of file diff --git a/src/test/java/roomescape/SpringJdbcTest.java b/src/test/java/roomescape/SpringJdbcTest.java index c6d772cad..d89a8ef91 100644 --- a/src/test/java/roomescape/SpringJdbcTest.java +++ b/src/test/java/roomescape/SpringJdbcTest.java @@ -2,7 +2,7 @@ import io.restassured.RestAssured; import io.restassured.http.ContentType; -import org.junit.jupiter.api.Nested; + import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @@ -18,7 +18,7 @@ import static org.assertj.core.api.Assertions.assertThat; -@SuppressWarnings("NonAsciiCharacters") + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) public class SpringJdbcTest { From b0dcc7a0af11913a63d9827605fbf47d8f2a6a30 Mon Sep 17 00:00:00 2001 From: DaYeong Date: Tue, 28 May 2024 02:34:31 +0900 Subject: [PATCH 36/36] rollback --- .../java/roomescape/DAO/ReservationDAO.java | 64 ++++++++++++++ src/main/java/roomescape/DAO/TimeDAO.java | 48 +++++++++++ .../controller/ReservationController.java | 24 +++--- .../roomescape/controller/TimeController.java | 51 +++++++++++ .../java/roomescape/domain/Reservation.java | 36 ++++++-- .../domain/ReservationRepository.java | 66 -------------- src/main/java/roomescape/domain/Time.java | 27 ++++++ .../service/ReservationService.java | 35 ++++++++ .../java/roomescape/service/TimeService.java | 35 ++++++++ src/main/resources/schema.sql | 17 ++-- src/test/java/roomescape/SpringCoreTest.java | 85 +++++++++++++++++++ 11 files changed, 398 insertions(+), 90 deletions(-) create mode 100644 src/main/java/roomescape/DAO/ReservationDAO.java create mode 100644 src/main/java/roomescape/DAO/TimeDAO.java create mode 100644 src/main/java/roomescape/controller/TimeController.java delete mode 100644 src/main/java/roomescape/domain/ReservationRepository.java create mode 100644 src/main/java/roomescape/domain/Time.java create mode 100644 src/main/java/roomescape/service/ReservationService.java create mode 100644 src/main/java/roomescape/service/TimeService.java create mode 100644 src/test/java/roomescape/SpringCoreTest.java diff --git a/src/main/java/roomescape/DAO/ReservationDAO.java b/src/main/java/roomescape/DAO/ReservationDAO.java new file mode 100644 index 000000000..b23976a36 --- /dev/null +++ b/src/main/java/roomescape/DAO/ReservationDAO.java @@ -0,0 +1,64 @@ +package roomescape.DAO; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Repository; +import roomescape.domain.Reservation; +import roomescape.domain.Time; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class ReservationDAO { + + private final JdbcTemplate jdbcTemplate; + private final SimpleJdbcInsert simpleJdbcInsert; + + public ReservationDAO(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("reservation") + .usingGeneratedKeyColumns("id"); + } + + public List findAll() { + String sql = "SELECT r.id, r.name, r.date, t.id as time_id, t.time FROM reservation r INNER JOIN time t ON r.time_id = t.id"; + return jdbcTemplate.query(sql, (rs, rowNum) -> { + long id = rs.getLong("id"); + String name = rs.getString("name"); + String date = rs.getString("date"); + Time time = new Time(rs.getLong("time_id"), rs.getString("time")); + return new Reservation(id, name, date, time); + }); + } + + public Reservation findById(long id) { + String sql = "SELECT r.id, r.name, r.date, t.id as time_id, t.time FROM reservation r INNER JOIN time t ON r.time_id = t.id WHERE r.id = ?"; + return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> { + long reservationId = rs.getLong("id"); + String name = rs.getString("name"); + String date = rs.getString("date"); + Time time = new Time(rs.getLong("time_id"), rs.getString("time")); + return new Reservation(reservationId, name, date, time); + }); + } + + public long save(Reservation reservation) { + Map parameters = new HashMap<>(); + parameters.put("name", reservation.getName()); + parameters.put("date", reservation.getDate()); + parameters.put("time_id", reservation.getTime().getId()); + + Number key = simpleJdbcInsert.executeAndReturnKey(parameters); + return key.longValue(); + } + + public long deleteById(long id) { + String sql = "DELETE FROM reservation WHERE id = ?"; + int rowsAffected = jdbcTemplate.update(sql, id); + return rowsAffected > 0 ? id : -1; + } +} \ No newline at end of file diff --git a/src/main/java/roomescape/DAO/TimeDAO.java b/src/main/java/roomescape/DAO/TimeDAO.java new file mode 100644 index 000000000..01bf0caa1 --- /dev/null +++ b/src/main/java/roomescape/DAO/TimeDAO.java @@ -0,0 +1,48 @@ +package roomescape.DAO; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.simple.SimpleJdbcInsert; +import org.springframework.stereotype.Repository; +import roomescape.domain.Time; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class TimeDAO { + private final JdbcTemplate jdbcTemplate; + private final SimpleJdbcInsert simpleJdbcInsert; + + public TimeDAO(DataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) + .withTableName("time") + .usingGeneratedKeyColumns("id"); + } + + public List