Skip to content

Commit 320c5f9

Browse files
authored
고생하셨습니다.
🎉 PR 머지 완료! 🎉
1 parent 13c25ff commit 320c5f9

17 files changed

+378
-2
lines changed

build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ repositories {
1313
}
1414

1515
dependencies {
16-
implementation 'org.springframework.boot:spring-boot-starter'
16+
implementation 'org.springframework.boot:spring-boot-starter-web'
17+
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
18+
implementation 'org.springframework.boot:spring-boot-starter-validation'
1719
testImplementation 'org.springframework.boot:spring-boot-starter-test'
1820
testImplementation 'io.rest-assured:rest-assured:5.3.1'
1921
}

src/main/java/roomescape/RoomescapeApplication.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,4 @@ public class RoomescapeApplication {
88
public static void main(String[] args) {
99
SpringApplication.run(RoomescapeApplication.class, args);
1010
}
11-
1211
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package roomescape.controller;
2+
3+
import org.springframework.stereotype.Controller;
4+
import org.springframework.web.bind.annotation.GetMapping;
5+
6+
@Controller
7+
public class HomeController {
8+
@GetMapping("/")
9+
public String home() {
10+
return "home";
11+
}
12+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package roomescape.controller;
2+
3+
import jakarta.validation.Valid;
4+
import java.net.URI;
5+
import java.util.List;
6+
import org.springframework.http.HttpStatus;
7+
import org.springframework.http.ResponseEntity;
8+
import org.springframework.stereotype.Controller;
9+
import org.springframework.web.bind.annotation.DeleteMapping;
10+
import org.springframework.web.bind.annotation.GetMapping;
11+
import org.springframework.web.bind.annotation.PathVariable;
12+
import org.springframework.web.bind.annotation.PostMapping;
13+
import org.springframework.web.bind.annotation.RequestBody;
14+
import org.springframework.web.bind.annotation.ResponseBody;
15+
import org.springframework.web.bind.annotation.ResponseStatus;
16+
import roomescape.dto.ReservationCreateRequest;
17+
import roomescape.dto.ReservationCreateResponse;
18+
import roomescape.model.Reservation;
19+
import roomescape.service.ReservationService;
20+
21+
@Controller
22+
public class ReservationController {
23+
private final ReservationService reservationService;
24+
25+
public ReservationController(ReservationService reservationService) {
26+
this.reservationService = reservationService;
27+
}
28+
29+
/*
30+
* View Mapping
31+
*/
32+
33+
@GetMapping("/reservation")
34+
public String reservation() {
35+
return "reservation";
36+
}
37+
38+
/*
39+
* API Mapping
40+
*/
41+
42+
@ResponseBody
43+
@GetMapping("/reservations")
44+
public List<Reservation> getReservations() {
45+
return reservationService.getReservations();
46+
}
47+
48+
@ResponseBody
49+
@PostMapping("/reservations")
50+
public ResponseEntity<ReservationCreateResponse> createReservation(@RequestBody @Valid ReservationCreateRequest request) {
51+
Reservation reservation = reservationService.createReservation(request);
52+
53+
URI location = URI.create("/reservations/" + reservation.id());
54+
return ResponseEntity.created(location).body(ReservationCreateResponse.from(reservation));
55+
}
56+
57+
@ResponseBody
58+
@ResponseStatus(HttpStatus.NO_CONTENT)
59+
@DeleteMapping("/reservations/{id}")
60+
public void deleteReservation(@PathVariable int id) {
61+
reservationService.deleteReservation(id);
62+
}
63+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package roomescape.dto;
2+
3+
public record ErrorResponse(String message) { }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package roomescape.dto;
2+
3+
import jakarta.validation.constraints.NotBlank;
4+
import jakarta.validation.constraints.NotNull;
5+
import java.time.LocalDate;
6+
import java.time.LocalTime;
7+
import roomescape.validation.ValidDate;
8+
import roomescape.validation.ValidTime;
9+
10+
public record ReservationCreateRequest(
11+
@NotBlank(message = "이름은 공백일 수 없습니다.")
12+
String name,
13+
14+
@ValidDate(message = "날짜 형식이 올바르지 않습니다. 예: yyyy-MM-dd")
15+
String date,
16+
17+
@ValidTime(message = "시간 형식이 올바르지 않습니다. 예: HH:mm")
18+
String time
19+
) { }
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package roomescape.dto;
2+
3+
import java.time.LocalDate;
4+
import java.time.LocalTime;
5+
import roomescape.model.Reservation;
6+
7+
public record ReservationCreateResponse(int id, String name, LocalDate date, LocalTime time) {
8+
public static ReservationCreateResponse from(Reservation reservation) {
9+
return new ReservationCreateResponse(reservation.id(), reservation.name(), reservation.date(), reservation.time());
10+
}
11+
}
12+
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package roomescape.exception;
2+
3+
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
4+
import org.springframework.http.HttpStatus;
5+
import org.springframework.http.ResponseEntity;
6+
import org.springframework.http.converter.HttpMessageNotReadableException;
7+
import org.springframework.web.bind.MethodArgumentNotValidException;
8+
import org.springframework.web.bind.annotation.ControllerAdvice;
9+
import org.springframework.web.bind.annotation.ExceptionHandler;
10+
import roomescape.dto.ErrorResponse;
11+
12+
@ControllerAdvice
13+
public class GlobalExceptionHandler {
14+
@ExceptionHandler(ReservationNotFoundException.class)
15+
public ResponseEntity<ErrorResponse> handleReservationNotFoundException(ReservationNotFoundException e) {
16+
return new ResponseEntity<>(new ErrorResponse(e.getMessage()), HttpStatus.BAD_REQUEST);
17+
}
18+
19+
@ExceptionHandler(ReservationValidationException.class)
20+
public ResponseEntity<ErrorResponse> handleReservationValidationException(ReservationValidationException e) {
21+
return new ResponseEntity<>(new ErrorResponse(e.getMessage()), HttpStatus.BAD_REQUEST);
22+
}
23+
24+
@ExceptionHandler(MethodArgumentNotValidException.class)
25+
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException e) {
26+
String message = e.getBindingResult().getAllErrors().stream().map((err) -> err.getDefaultMessage()).findFirst().orElse("입력 값 검증 실패");
27+
28+
return new ResponseEntity<>(new ErrorResponse(message), HttpStatus.BAD_REQUEST);
29+
}
30+
31+
@ExceptionHandler(Exception.class)
32+
public ResponseEntity<ErrorResponse> handleFallbackException() {
33+
return new ResponseEntity<>(new ErrorResponse("내부 서버 오류가 발생했습니다."), HttpStatus.INTERNAL_SERVER_ERROR);
34+
}
35+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package roomescape.exception;
2+
3+
public class ReservationNotFoundException extends RuntimeException {
4+
public ReservationNotFoundException(String message) {
5+
super(message);
6+
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package roomescape.exception;
2+
3+
public class ReservationValidationException extends RuntimeException {
4+
public ReservationValidationException(String message) {
5+
super(message);
6+
}
7+
}

0 commit comments

Comments
 (0)