-
Notifications
You must be signed in to change notification settings - Fork 83
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
[1 - 3 단계 방탈출 사용자 예약] 로빈(임수빈) 미션 제출합니다. #29
Changes from 67 commits
64335cd
9d575fe
258c9b6
dbb1b8b
202216d
bae62c9
fc59282
65733d0
1bbadab
a14d390
2da2b7a
4f222f4
6a4ebb7
60e2f88
80b2371
a5ca6d4
36fe37e
3e37f25
9d83ffe
6f1be1a
c75c485
4d4c985
44c1974
af7f7e6
31df8bd
564ecaf
550f4cd
d1c9bee
1cfec9a
37c3bc1
cb113fd
42c2415
8a42260
584df82
f6966e1
9adfa8d
24c83c6
5f25eaf
b4b52b4
cc62f4b
f690708
1e96e33
06bb27c
2255391
ee5b115
77a3e24
173699c
3689dc7
0516901
3c472a3
b55ca91
2789dae
c6f2992
6ec052d
ad587b5
ddf88b1
e36c497
3961bb6
1378a92
093f68b
1024c7e
258466c
8c4efbc
c7c5033
0391803
c7f2dad
2416896
e8e7a6f
62cef24
1561f7e
c9b2f37
92e8519
a1ed68a
5d02747
eb38c7d
9881fc7
239c241
20fddde
e12b17e
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 |
---|---|---|
@@ -1,23 +1,26 @@ | ||
# 요구사항 문서 | ||
|
||
- [x] localhost:8080/admin 요청 시 어드민 메인 페이지가 응답할 수 있도록 구현한다. | ||
- [x] 어드민 메인 페이지는 templates/admin/index.html 파일을 이용한다. | ||
- [x] localhost:8080/admin/reservation 요청 시 아래 화면과 같이 예약 관리 페이지가 응답할 수 있도록 구현한다. | ||
- [x] 페이지는 templates/admin/reservation-legacy.html 파일을 이용한다. | ||
- [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] 분리한 클래스는 매번 새로 생성하지 않고 스프링 빈으로 등록한다. | ||
- [x] API 명세를 현재 프론트엔드 코드가 잘 동작할 수 있도록 수정 | ||
- [x] 예약 시간에 대한 제약 조건 추가 | ||
- [x] 중복된 예약 시간 생성 요청 시 에러 | ||
- [x] ISO 8601 표준에 따른 hh:mm 포맷에 해당하지 않는 요청 시 에러 | ||
- [x] 예약이 있는 예약 시간을 삭제 요청 시 에러 | ||
- [x] 예약에 대한 제약 조건 추가 | ||
- [x] 동일한 날짜와 시간, 테마에 예약 생성 요청 시 에러 | ||
- [x] 존재하지 않는 시간에 예약 생성 요청 시 에러 | ||
- [x] ISO 8601 표준에 따른 YYYY-MM-dd 포맷에 해당하지 않는 날짜가 포함된 예약 생성 요청 시 에러 | ||
- [x] 지나간 날짜와 시간의 예약 요청 시 에러 | ||
- [x] 이름이 비어있는 예약 요청 시 에러 | ||
- [x] 존재하지 않는 테마 예약 생성 요청시 에러 | ||
- [x] 테마 값이 비어있는 예약 요청 시 에러 | ||
|
||
- [x] 테마에 대한 제약 조건 추가 | ||
- [x] 테마 이름, 설명, 썸네일 이미자가 비어 있을 경우 에러 | ||
- [x] 중복된 이름의 테마 생성 요청시 에러 | ||
- [x] 예약이 있는 테마를 삭제 요청시 에러 | ||
|
||
- [ ] 사용자 예약 기능 추가 | ||
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. ❓ |
||
- [x] 인기 테마 기능 추가 | ||
|
||
# API 명세 | ||
|
||
|
@@ -43,6 +46,12 @@ | |
"id": 1, | ||
"startAt": "10:00" | ||
} | ||
"theme" : { | ||
"id": 1, | ||
"name": "이름", | ||
"description": "설명", | ||
"thumbnail": "썸네일" | ||
} | ||
} | ||
] | ||
``` | ||
|
@@ -59,15 +68,17 @@ | |
{ | ||
"date": "2023-08-05", | ||
"name": "브라운", | ||
"timeId": 1 | ||
"timeId": 1, | ||
"themeId": 1 | ||
} | ||
``` | ||
|
||
### Response | ||
|
||
> HTTP/1.1 200 | ||
> HTTP/1.1 201 | ||
> | ||
> Content-Type: application/json | ||
> Location: /reservations/{id} | ||
|
||
```JSON | ||
{ | ||
|
@@ -77,6 +88,12 @@ | |
"time": { | ||
"id": 1, | ||
"startAt": "10:00" | ||
}, | ||
"theme": { | ||
"id": 1, | ||
"name": "이름", | ||
"description": "설명", | ||
"thumbnail": "썸네일" | ||
} | ||
} | ||
``` | ||
|
@@ -89,7 +106,7 @@ | |
|
||
### Response | ||
|
||
> HTTP/1.1 200 | ||
> HTTP/1.1 204 | ||
|
||
## 시간 추가 API | ||
|
||
|
@@ -106,8 +123,9 @@ | |
|
||
### response | ||
|
||
> HTTP/1.1 200 | ||
> HTTP/1.1 201 | ||
> Content-Type: application/json | ||
> Location: /times/{id} | ||
|
||
```JSON | ||
{ | ||
|
@@ -144,4 +162,87 @@ | |
|
||
### response | ||
|
||
> HTTP/1.1 204 | ||
|
||
## 테마 조회 API | ||
|
||
### request | ||
|
||
> GET /themes HTTP/1.1 | ||
|
||
### response | ||
|
||
> HTTP/1.1 200 | ||
> Content-Type: application/json | ||
|
||
```json | ||
[ | ||
{ | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
] | ||
``` | ||
|
||
## 테마 추가 API | ||
|
||
### request | ||
|
||
> POST /themes HTTP/1.1 | ||
> content-type: application/json | ||
|
||
```json | ||
{ | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
``` | ||
|
||
### response | ||
|
||
> HTTP/1.1 201 | ||
> Location: /themes/1 | ||
> Content-Type: application/json | ||
|
||
```json | ||
{ | ||
"id": 1, | ||
"name": "레벨2 탈출", | ||
"description": "우테코 레벨2를 탈출하는 내용입니다.", | ||
"thumbnail": "https://i.pinimg.com/236x/6e/bc/46/6ebc461a94a49f9ea3b8bbe2204145d4.jpg" | ||
} | ||
``` | ||
|
||
## 테마 삭제 API | ||
|
||
### request | ||
|
||
> DELETE /themes/1 HTTP/1.1 | ||
|
||
### response | ||
|
||
> HTTP/1.1 204 | ||
|
||
## 예약 가능 시간 조회 API | ||
|
||
### Request | ||
|
||
> GET /availableTimes?date=${date}&themeId=${themeId} | ||
|
||
### response | ||
|
||
> HTTP/1.1 200 | ||
> Content-Type: application/json | ||
|
||
```json | ||
[ | ||
{ | ||
"id": 0, | ||
"startAt": "02:53", | ||
"isBooked": false | ||
} | ||
] | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package roomescape.controller; | ||
|
||
import java.time.LocalDate; | ||
import java.util.List; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import roomescape.dto.AvailableTimeResponse; | ||
import roomescape.service.AvailableTimeService; | ||
|
||
@RestController | ||
@RequestMapping("/availableTimes") | ||
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. Time이 아닌 AvailableTimes를 사용한 이유는 무엇인가요! RESTFUL API에 대해 알아볼까요? 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. 이를 URL Path로 명시하는 것과, Url Param으로 명시하는 것은 어떠한 차이가 있을까요? |
||
public class AvailableTimeController { | ||
|
||
private final AvailableTimeService availableTimeService; | ||
|
||
public AvailableTimeController(AvailableTimeService availableTimeService) { | ||
this.availableTimeService = availableTimeService; | ||
} | ||
|
||
@GetMapping() | ||
public List<AvailableTimeResponse> findByThemeAndDate(@RequestParam LocalDate date, @RequestParam long themeId) { | ||
return availableTimeService.findByThemeAndDate(date, themeId); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package roomescape.controller; | ||
|
||
import java.net.URI; | ||
import java.time.LocalDate; | ||
import java.util.List; | ||
import org.springframework.http.ResponseEntity; | ||
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.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import roomescape.dto.ThemeRequest; | ||
import roomescape.dto.ThemeResponse; | ||
import roomescape.service.ThemeService; | ||
|
||
@RestController | ||
@RequestMapping("/themes") | ||
public class ThemeController { | ||
private final ThemeService themeService; | ||
|
||
public ThemeController(ThemeService themeService) { | ||
this.themeService = themeService; | ||
} | ||
|
||
@GetMapping | ||
public List<ThemeResponse> findAll() { | ||
return themeService.findAll(); | ||
} | ||
|
||
@GetMapping("/ranking") | ||
public List<ThemeResponse> findAndOrderByPopularity(@RequestParam LocalDate start, | ||
@RequestParam LocalDate end, | ||
@RequestParam int count) { | ||
return themeService.findAndOrderByPopularity(start, end, count); | ||
} | ||
|
||
@PostMapping | ||
public ResponseEntity<ThemeResponse> save(@RequestBody ThemeRequest themeRequest) { | ||
ThemeResponse saved = themeService.save(themeRequest); | ||
return ResponseEntity.created(URI.create("/themes/" + saved.id())) | ||
.body(saved); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity<Void> delete(@PathVariable long id) { | ||
themeService.delete(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
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.
이 부분은 그러면 리팩터링해보도록 하는 것으로 하죠 💪