-
Notifications
You must be signed in to change notification settings - Fork 169
[Spring MVC] 민지인 미션제출합니다 #506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: jxxxxxn
Are you sure you want to change the base?
Changes from all commits
d00ac48
5fddb60
a120bd3
b3cf994
81259f3
0ea5bfe
41ff18e
a4a9f6b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package roomescape.controller; | ||
|
|
||
| import jakarta.servlet.http.HttpServletResponse; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.web.bind.annotation.*; | ||
| import roomescape.dto.ReservationAddReq; | ||
| import roomescape.dto.ReservationReq; | ||
| import roomescape.exception.InvalidRequestReservationException; | ||
| import roomescape.exception.NotFoundReservationException; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import java.util.concurrent.atomic.AtomicLong; | ||
|
|
||
| @Controller | ||
| public class ReservationController { | ||
|
|
||
| //AtomicLong: Long 자료형 가지는 Wrapping 클래스. incrementAndGet(): ++x | ||
| private AtomicLong index = new AtomicLong(0); | ||
| private List<ReservationReq> reservations = new ArrayList<>(); | ||
|
|
||
| @GetMapping("/reservation") | ||
| public String reservation(Model model){ | ||
|
|
||
| model.addAttribute(reservations); | ||
| return "reservation"; | ||
| } | ||
|
|
||
| //예약 조회 | ||
| @GetMapping("/reservations") | ||
| @ResponseBody | ||
| public List<ReservationReq> reservations(){ | ||
|
|
||
| return reservations; | ||
| } | ||
|
|
||
| //예약 추가 | ||
| @PostMapping("/reservations") | ||
| @ResponseBody | ||
| @ResponseStatus(HttpStatus.CREATED) | ||
| public ReservationReq addReservation(@RequestBody ReservationAddReq reservation, HttpServletResponse response){ | ||
| if(reservation.getName().isEmpty()||reservation.getDate().isEmpty()||reservation.getTime().isEmpty()){ | ||
| throw new InvalidRequestReservationException("필요한 인자가 없습니다."); | ||
| } | ||
| ReservationReq newReservation =new ReservationReq(index.incrementAndGet(),reservation.getName(),reservation.getDate(),reservation.getTime()); | ||
| reservations.add(newReservation); | ||
|
|
||
| // ResponseEntity 사용하면 header 명시적으로 지정하지 않아도 된다고 한다. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ResponseStatus 를 사용하고 있군요. ResponseEntity 와 차이점을 생각해볼까요? 리턴값을 일관된 구조로 클라에게 전달하기 위해 둘 중 어느 것을 사용해야 할까요? 이 글 을 참고해보면 좋을 것 같아요! |
||
| response.setHeader("Location", "/reservations/" + newReservation.getId()); | ||
| return newReservation; | ||
| } | ||
|
|
||
| //예약 삭제 | ||
| @DeleteMapping("/reservations/{id}") | ||
| @ResponseBody | ||
| @ResponseStatus(HttpStatus.NO_CONTENT) | ||
| public void deleteReservation(@PathVariable Long id){ | ||
| ReservationReq delete=reservations.stream().filter(ReservationReq -> id.equals(ReservationReq.getId())).findAny().orElse(null); | ||
| if(delete==null){ | ||
| throw new NotFoundReservationException("삭제할 예약이 없습니다"); | ||
| } | ||
| reservations.remove(delete); | ||
| } | ||
|
|
||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package roomescape.controller; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
|
|
||
| @Controller | ||
| public class StartController { | ||
|
|
||
| @GetMapping("/") | ||
| public String home(){ | ||
| return "home"; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package roomescape.dto; | ||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| @AllArgsConstructor | ||
| public class ReservationAddReq { | ||
| private String name; | ||
| private String date; //우선 String으로.. 차후 Date로 형변환 필요하면 교체.. | ||
| private String time; //동일!! | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package roomescape.dto; | ||
|
|
||
| import lombok.AllArgsConstructor; | ||
| import lombok.Getter; | ||
|
|
||
| @Getter | ||
| @AllArgsConstructor //기본 생성자 자동 생성 | ||
| public class ReservationReq { | ||
| //캡슐화를 위해서는 private으로 해야 하지만, step12의 코드에서 private으로 하면 JSON이 접근을 못 해서 직렬화 못 하는 에러 발생 | ||
| //해결을 위해 lombok의 getter 추가 | ||
| private Long id; | ||
| private String name; | ||
| private String date; //우선 String으로.. 차후 Date로 형변환 필요하면 교체.. | ||
| private String time; //동일!! | ||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package roomescape.exception; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.ControllerAdvice; | ||
| import org.springframework.web.bind.annotation.ExceptionHandler; | ||
|
|
||
|
|
||
| @ControllerAdvice | ||
| public class ExceptionHandlers { | ||
|
|
||
| @ExceptionHandler(NotFoundReservationException.class) | ||
| public ResponseEntity NotFoundReservationException() { //딱히 메시지에 id 등 추가할 필요를 못 느껴서 매개변수 없앰. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 메서드명과 예외클래스명을 일치시키면 혼동이 발생할 수 있어요. 메서드명을 변경해볼까요? |
||
| return ResponseEntity.badRequest().build(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 현재는 상태코드만 리턴하고 있네요. 예외처리를 하는 이유는 클라에게 오류 정보를 전달하기 위해서예요. 오류 메시지를 담는 적절한 객체를 만들어 전달하면 더 좋을 것 같네요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NotFound 예외는 404 상태코드로 전달하는 게 좋을 것 같아요! 현재는 Bad request 400 코드로 처리하고 있네요! |
||
| } | ||
|
|
||
| @ExceptionHandler(InvalidRequestReservationException.class) | ||
| public ResponseEntity InvalidRequestReservationException(){ | ||
| return ResponseEntity.badRequest().build(); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package roomescape.exception; | ||
|
|
||
| public class InvalidRequestReservationException extends RuntimeException { | ||
| public InvalidRequestReservationException(String message) { | ||
| super(message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package roomescape.exception; | ||
|
|
||
| public class NotFoundReservationException extends RuntimeException { | ||
| public NotFoundReservationException(String message) { | ||
| super(message); | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
파라미터 입력을 어떻게 체크하면 좋을까요? Controller에 Valid 어노테이션을 추가하면 수동으로 검증 코드를 작성하지 않아도 됩니다. DTO 에 정의된 필드가 Controller 에서 ResquestBody 에 들어올 때 검증해주어요. 자세한 내용은 이 글을 참고해볼까요? 그리고 이 어노테이션은 검증 실패 시 어떤 에러를 반환하는지 알아보고 리팩터링 해볼까요?