Skip to content
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

[4 - 9단계 방탈출 예약 관리] 로빈(임수빈) 미션 제출합니다. #155

Merged
merged 18 commits into from
Apr 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 76 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,17 @@
- [x] 예약 조회 API 명세를 따라 예약 관리 페이지 로드 시 호출되는 예약 목록 조회 API를 구현한다.
- [x] API 명세를 따라 예약 추가 API 와 삭제 API를 구현한다.
- [x] 예약 추가와 취소가 잘 동작한다.
- [x] 이상의 요구 사항을 데이터베이스와 연동하도록 한다.

- [x] 방탈출 시간표에 따라 방탈출 예약 시 시간을 선택하는 방식으로 수정한다.
- [x] API 명세를 따라 시간 관리 API를 구현한다.
- [x] 페이지는 templates/admin/time.html 파일을 이용한다.

- [x] 기존에 구현한 예약 기능에서 시간을 시간 테이블에 저장된 값만 선택할 수 있도록 수정한다.
- [x] templates/admin/reservation.html 을 사용한다.

- [x] 레이어드 아키텍처를 적용하여 레이어별 책임과 역할에 따라 클래스를 분리한다.
- [x] 분리한 클래스는 매번 새로 생성하지 않고 스프링 빈으로 등록한다.

# API 명세

Expand All @@ -27,14 +38,11 @@
{
"id": 1,
"name": "브라운",
"date": "2023-01-01",
"time": "10:00"
},
{
"id": 2,
"name": "브라운",
"date": "2023-01-02",
"time": "11:00"
"date": "2023-08-05",
"time": {
"id": 1,
"startAt": "10:00"
}
}
]
```
Expand All @@ -51,7 +59,7 @@
{
"date": "2023-08-05",
"name": "브라운",
"time": "15:40"
"timeId": 1
}
```

Expand All @@ -66,7 +74,10 @@
"id": 1,
"name": "브라운",
"date": "2023-08-05",
"time": "15:40"
"time": {
"id": 1,
"startAt": "10:00"
}
}
```

Expand All @@ -79,3 +90,58 @@
### Response

> HTTP/1.1 200

## 시간 추가 API

### request

> POST /times HTTP/1.1
> content-type: application/json

```JSON
{
"startAt": "10:00"
}
```

### response

> HTTP/1.1 200
> Content-Type: application/json

```JSON
{
"id": 1,
"startAt": "10:00"
}
```

## 시간 조회 API

### request

> GET /times HTTP/1.1

### response

> HTTP/1.1 200
> Content-Type: application/json

```JSON
[
{
"id": 1,
"startAt": "10:00"
}
]
```

## 시간 삭제 API

### request

> DELETE /times/1 HTTP/1.1

### response

> HTTP/1.1 200
7 changes: 6 additions & 1 deletion src/main/java/roomescape/controller/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ public String mainPage() {

@GetMapping("/reservation")
public String reservationPage() {
return "admin/reservation-legacy";
return "admin/reservation";
}

@GetMapping("/time")
public String reservationTimePage() {
return "admin/time";
}
}
28 changes: 9 additions & 19 deletions src/main/java/roomescape/controller/ReservationController.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,31 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import roomescape.domain.Reservation;
import roomescape.dto.ReservationRequest;
import roomescape.dto.ReservationResponse;
import roomescape.storage.ReservationStorage;
import roomescape.service.ReservationService;

@RestController
@RequestMapping("/reservations")
public class ReservationController {
private final ReservationStorage reservationStorage;
private final ReservationService reservationService;

public ReservationController(ReservationStorage reservationStorage) {
this.reservationStorage = reservationStorage;
public ReservationController(ReservationService reservationService) {
this.reservationService = reservationService;
}

@PostMapping
public ReservationResponse saveReservation(@RequestBody ReservationRequest reservationRequest) {
Reservation reservation = reservationStorage.save(reservationRequest);
return toResponse(reservation);
}

private ReservationResponse toResponse(Reservation reservation) {
return new ReservationResponse(reservation.getId(),
reservation.getName(), reservation.getDate(), reservation.getTime());
return reservationService.save(reservationRequest);
}

@GetMapping
public List<ReservationResponse> findAllReservations() {
return reservationStorage.findAllReservations()
.stream()
.map(this::toResponse)
.toList();
return reservationService.findAll();
}

@DeleteMapping("/{reservationId}")
public void delete(@PathVariable long reservationId) {
reservationStorage.delete(reservationId);
@DeleteMapping("/{id}")
public void delete(@PathVariable long id) {
reservationService.delete(id);
}
}
38 changes: 38 additions & 0 deletions src/main/java/roomescape/controller/ReservationTimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package roomescape.controller;

import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import roomescape.dto.ReservationTimeRequest;
import roomescape.dto.ReservationTimeResponse;
import roomescape.service.ReservationTimeService;

@RestController
@RequestMapping("/times")
public class ReservationTimeController {
private final ReservationTimeService reservationTimeService;

public ReservationTimeController(ReservationTimeService reservationTimeService) {
this.reservationTimeService = reservationTimeService;
}

@PostMapping
public ReservationTimeResponse save(@RequestBody ReservationTimeRequest reservationTimeRequest) {
return reservationTimeService.save(reservationTimeRequest);
}

@GetMapping
public List<ReservationTimeResponse> findAll() {
return reservationTimeService.findAll();
}

@DeleteMapping("/{id}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요기엔 id로만 써주셨네요!
어느방향이든 일관성을 맞춰주세요

public void delete(@PathVariable long id) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 미션에서 특이한 점은 API 명세의 응답 상태코드가 일관성 없이 왔다갔다 수정된다는 것이었습니다...
아무리 고민해봐도 무슨 의도가 담긴 것인지 모르겠어서 모두 200 OK 로 응답하도록 했습니다.

상태코드에 대해서 참고자료를 보셨었나요?
구체적으로 어떤 부분이 이해가 안된지 말씀주시면 같이 이야기해봐도 좋을거같아요.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이번 미션에서 특이한 점은 API 명세의 응답 상태코드가 일관성 없이 왔다갔다 수정된다는 것이었습니다...
아무리 고민해봐도 무슨 의도가 담긴 것인지 모르겠어서 모두 200 OK 로 응답하도록 했습니다.

상태코드에 대해서 참고자료를 보셨었나요? 구체적으로 어떤 부분이 이해가 안된지 말씀주시면 같이 이야기해봐도 좋을거같아요.

결론 : LMS 내의 오타(?)가 굴린 스노우볼이었다.

LMS 에서 미션 설명 해주는 페이지에서
image

이런식으로 테스트 코드를 제공해 줬는데요, 지금은 LMS가 수정되었지만 PR 보내는 시점에만 해도 테스트 코드에서 상태 코드를 검증하는 부분이 API 명세와는 다르게 200이 아닌 특화된 상태코드였습니다. 이마저도 다음 단계 설명에서 제공해주는 테스트코드는 또 200으로 검증하기도 했습니다... 이 부분을 코치님들한테 여쭤보았을 때 모호하게 대답해주셔서 그저 200 으로 지정했습니다.

reservationTimeService.delete(id);
}
}
69 changes: 62 additions & 7 deletions src/main/java/roomescape/domain/Reservation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Objects;

public class Reservation implements Comparable<Reservation> {
private final long id;
private final Long id;
private final String name;
private final LocalDateTime dateTime;
private final LocalDate date;
private final ReservationTime time;

public Reservation(long id, String name, LocalDateTime dateTime) {
public Reservation(long id, Reservation reservationBeforeSave) {
this(id, reservationBeforeSave.name, reservationBeforeSave.date, reservationBeforeSave.time);
}

public Reservation(Long id, String name, LocalDate date, ReservationTime time) {
this.id = id;
this.name = name;
this.dateTime = dateTime;
this.date = date;
this.time = time;
}

@Override
public int compareTo(Reservation other) {
return dateTime.compareTo(other.dateTime);
LocalDateTime dateTime = LocalDateTime.of(date, time.getStartAt());
LocalDateTime otherDateTime = LocalDateTime.of(other.date, other.time.getStartAt());
return dateTime.compareTo(otherDateTime);
}

public boolean hasSameId(long id) {
Expand All @@ -33,10 +42,56 @@ public String getName() {
}

public LocalDate getDate() {
return dateTime.toLocalDate();
return date;
}

public LocalTime getTime() {
return dateTime.toLocalTime();
return time.getStartAt();
}

public ReservationTime getReservationTime() {
return time;
}

@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (date != null ? date.hashCode() : 0);
result = 31 * result + (time != null ? time.hashCode() : 0);
return result;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

Reservation that = (Reservation) o;

if (!Objects.equals(id, that.id)) {
return false;
}
if (!Objects.equals(name, that.name)) {
return false;
}
if (!Objects.equals(date, that.date)) {
return false;
}
return Objects.equals(time, that.time);
}

@Override
public String toString() {
return "Reservation{" +
"id=" + id +
", name='" + name + '\'' +
", date=" + date +
", time=" + time +
'}';
}
}
58 changes: 58 additions & 0 deletions src/main/java/roomescape/domain/ReservationTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package roomescape.domain;

import java.time.LocalTime;
import java.util.Objects;

public class ReservationTime {
private final Long id;
private final LocalTime startAt;

public ReservationTime(LocalTime startAt) {
this(null, startAt);
}

public ReservationTime(Long id, LocalTime startAt) {
this.id = id;
this.startAt = startAt;
}

public Long getId() {
return id;
}

public LocalTime getStartAt() {
return startAt;
}

@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (startAt != null ? startAt.hashCode() : 0);
return result;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

ReservationTime that = (ReservationTime) o;

if (!Objects.equals(id, that.id)) {
return false;
}
return Objects.equals(startAt, that.startAt);
}

@Override
public String toString() {
return "ReservationTime{" +
"id=" + id +
", startAt=" + startAt +
'}';
}
}
3 changes: 1 addition & 2 deletions src/main/java/roomescape/dto/ReservationRequest.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package roomescape.dto;

import java.time.LocalDate;
import java.time.LocalTime;

public record ReservationRequest(LocalDate date, String name, LocalTime time) {
public record ReservationRequest(LocalDate date, String name, long timeId) {
}
3 changes: 1 addition & 2 deletions src/main/java/roomescape/dto/ReservationResponse.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package roomescape.dto;

import java.time.LocalDate;
import java.time.LocalTime;

public record ReservationResponse(long id, String name, LocalDate date, LocalTime time) {
public record ReservationResponse(long id, String name, LocalDate date, ReservationTimeResponse time) {
}
6 changes: 6 additions & 0 deletions src/main/java/roomescape/dto/ReservationTimeRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package roomescape.dto;

import java.time.LocalTime;

public record ReservationTimeRequest(LocalTime startAt) {
}
Loading