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

Step2 아토 #2

Open
wants to merge 27 commits into
base: hyxrxn
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
639f695
[방탈출 예약 관리 - 1~3단계] 아토(이혜린) 미션 제출합니다. (#43)
hyxrxn Apr 17, 2024
22e85c6
feat: 데이터베이스 연동
hyxrxn Apr 22, 2024
8d5e7fa
refactor(ReservationController): 예약 내역 조회 시 데이터베이스 활용
hyxrxn Apr 23, 2024
114446c
refactor(ReservationController): 예약 내역 추가 및 삭제 시 데이터베이스 활용
hyxrxn Apr 23, 2024
b3f2d74
fix(ReservationController): 예약 추가 및 삭제 시 페이지 미갱신 문제 수정
hyxrxn Apr 23, 2024
b97eba1
feat(AdminController): 시간 관리 페이지 응답
hyxrxn Apr 25, 2024
d027c6c
fix: html 네비게이션 바 버튼 링크 수정
hyxrxn Apr 25, 2024
c0d56ce
feat(schema.sql): 예약 시간 스키마 추가
hyxrxn Apr 25, 2024
6fb9f5b
feat(TimeController): 예약 시간 조회, 추가 및 삭제
hyxrxn Apr 25, 2024
98ae4d0
refactor(ReservationController): api 명세에 맞춰 상태 코드 수정
hyxrxn Apr 25, 2024
a30029b
feat(AdminController): 예약 페이지 응답
hyxrxn Apr 25, 2024
ae0c874
feat(ReservationController): 시간을 테이블에서 선택해서 예약 추가, 삭제 및 조회
hyxrxn Apr 26, 2024
eb2777a
refactor: 패키지 분리
hyxrxn Apr 26, 2024
b2be619
refactor(Controller): 가독성 개선
hyxrxn Apr 26, 2024
08e273a
feat(ReservationTimeDao): reservation_time 테이블 접근 책임 분리
hyxrxn Apr 27, 2024
78952eb
feat(ReservationDao): reservation 테이블 접근 책임 분리
hyxrxn Apr 27, 2024
d02fd4b
refactor(ReservationTimeDao): dto 대신 도메인을 파라미터로 받도록 변경
hyxrxn Apr 27, 2024
1ff3c24
refactor(ReservationDao): dto 대신 도메인을 파라미터로 받도록 변경
hyxrxn Apr 27, 2024
537ae1c
test: DynamicTest 활용해 연속적인 테스트 진행
hyxrxn Apr 27, 2024
c914a99
refactor: 필드가 불변하도록 변경
hyxrxn Apr 28, 2024
a8d9f06
refactor(MissionStepTest): 테스트 이름 설정
hyxrxn Apr 28, 2024
cc2ac8d
feat(TimeController): body 유효성 검증
hyxrxn Apr 28, 2024
31c3bb6
feat(ReservationController): body 유효성 검증
hyxrxn Apr 28, 2024
a5136cb
refactor(TimeController): 해당 시간의 예약이 존재하는지 확인 후 삭제
hyxrxn Apr 28, 2024
bbb56ad
feat(TimeService): 예약 시간 관련 비즈니스 플로우 책임 분리
hyxrxn Apr 28, 2024
724c60c
feat(ReservationService): 예약 관련 비즈니스 플로우 책임 분리
hyxrxn Apr 28, 2024
5a1fa50
test(EndToEndTest): 삭제가 잘 되었는지 확인
hyxrxn Apr 28, 2024
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
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-validation'
runtimeOnly 'com.h2database:h2'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RoomescapeApplication {
public class RoomEscapeApplication {

public static void main(String[] args) {
SpringApplication.run(RoomescapeApplication.class, args);
SpringApplication.run(RoomEscapeApplication.class, args);
}

}
47 changes: 47 additions & 0 deletions src/main/java/roomescape/controller/api/ReservationController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.controller.api;

import jakarta.validation.Valid;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 roomescape.dto.reservation.ReservationRequest;
import roomescape.dto.reservation.ReservationResponse;
import roomescape.service.ReservationService;

@RequestMapping("/reservations")
@Controller
public class ReservationController {

private final ReservationService reservationService;

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

@GetMapping("")
public ResponseEntity<List<ReservationResponse>> reservations() {
List<ReservationResponse> reservationResponses = reservationService.reservations();

return ResponseEntity.ok(reservationResponses);
}

@PostMapping("")
public ResponseEntity<ReservationResponse> create(@RequestBody @Valid ReservationRequest reservationRequest) {
ReservationResponse reservationResponse = reservationService.createReservation(reservationRequest);

return ResponseEntity.ok(reservationResponse);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
reservationService.deleteReservation(id);

return ResponseEntity.ok().build();
}
}
48 changes: 48 additions & 0 deletions src/main/java/roomescape/controller/api/TimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package roomescape.controller.api;

import jakarta.validation.Valid;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
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 roomescape.dto.reservationtime.ReservationTimeRequest;
import roomescape.dto.reservationtime.ReservationTimeResponse;
import roomescape.service.TimeService;

@RequestMapping("/times")
@Controller
public class TimeController {

private final TimeService timeService;

public TimeController(TimeService timeService) {
this.timeService = timeService;
}

@GetMapping("")
public ResponseEntity<List<ReservationTimeResponse>> times() {
List<ReservationTimeResponse> reservationTimeResponses = timeService.times();

return ResponseEntity.ok(reservationTimeResponses);
}

@PostMapping("")
public ResponseEntity<ReservationTimeResponse> create(
@RequestBody @Valid ReservationTimeRequest reservationTimeRequest) {
ReservationTimeResponse reservationTimeResponse = timeService.createTime(reservationTimeRequest);

return ResponseEntity.ok(reservationTimeResponse);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
timeService.deleteTime(id);

return ResponseEntity.ok().build();
}
}
25 changes: 25 additions & 0 deletions src/main/java/roomescape/controller/web/AdminController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.controller.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/admin")
@Controller
public class AdminController {

@GetMapping("")
public String admin() {
return "admin/index";
}

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

@GetMapping("/time")
public String time() {
return "admin/time";
}
}
13 changes: 13 additions & 0 deletions src/main/java/roomescape/controller/web/HomeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package roomescape.controller.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HomeController {

@GetMapping("")
public String index() {
return "redirect:/admin";
}
}
91 changes: 91 additions & 0 deletions src/main/java/roomescape/dao/ReservationDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package roomescape.dao;

import java.sql.Date;
import java.time.LocalTime;
import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Component;
import roomescape.domain.Reservation;
import roomescape.domain.ReservationTime;

@Component
public class ReservationDao {

private static final RowMapper<Reservation> RESERVATION_ROW_MAPPER = (resultSet, rowNum) -> {
Long timeId = resultSet.getLong("time_id");
LocalTime time = resultSet.getTime("start_at").toLocalTime();

return new Reservation(
resultSet.getLong("id"),
resultSet.getString("name"),
resultSet.getString("date"),
new ReservationTime(timeId, time));
};

private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert simpleJdbcInsert;

public ReservationDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate.getDataSource())
.withTableName("reservation")
.usingGeneratedKeyColumns("id");
}

public List<Reservation> findAllReservations() {
String sql = """
select
r.id as reservation_id,
r.name,
r.date,
t.id as time_id,
t.start_at as time_value
from reservation as r
inner join reservation_time as t
on r.time_id = t.id
""";

return jdbcTemplate.query(sql, RESERVATION_ROW_MAPPER);
}

public Reservation findReservation(Long id) {
String sql = """
select
r.id as reservation_id,
r.name,
r.date,
t.id as time_id,
t.start_at as time_value
from reservation as r
inner join reservation_time as t
on r.time_id = t.id
where r.id = ?
""";

return jdbcTemplate.queryForObject(sql, RESERVATION_ROW_MAPPER, id);
}

public Long saveReservation(Reservation reservation) {
return simpleJdbcInsert.executeAndReturnKey(
Map.of(
"name", reservation.getName(),
"date", Date.valueOf(reservation.getDate()),
"time_id", reservation.getTime().getId()
))
.longValue();
}

public void deleteReservation(Long id) {
jdbcTemplate.update("delete from reservation where id = ?", id);
}

public boolean hasReservationOf(Long id) {
String sql = "SELECT COUNT(*) FROM RESERVATION WHERE time_id = ?";
int count = jdbcTemplate.queryForObject(sql, Integer.class, id);

return count > 0;
}
}
47 changes: 47 additions & 0 deletions src/main/java/roomescape/dao/ReservationTimeDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.dao;

import java.util.List;
import java.util.Map;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Component;
import roomescape.domain.ReservationTime;

@Component
public class ReservationTimeDao {

private static final RowMapper<ReservationTime> RESERVATION_TIME_ROW_MAPPER = (resultSet, rowNum) ->
new ReservationTime(
resultSet.getLong("id"),
resultSet.getTime("start_at").toLocalTime()
);

private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert simpleJdbcInsert;

public ReservationTimeDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate.getDataSource())
.withTableName("reservation_time")
.usingGeneratedKeyColumns("id");
}

public List<ReservationTime> findAllReservationTimes() {
String sql = "select id, start_at from reservation_time";

return jdbcTemplate.query(sql, RESERVATION_TIME_ROW_MAPPER);
}

public Long saveReservationTime(ReservationTime reservationTime) {
return simpleJdbcInsert.executeAndReturnKey(
Map.of(
"start_at", reservationTime.getStartAt()
))
.longValue();
}

public void deleteReservationTime(Long id) {
jdbcTemplate.update("delete from reservation_time where id = ?", id);
}
}
32 changes: 32 additions & 0 deletions src/main/java/roomescape/domain/Reservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package roomescape.domain;

public class Reservation {

private final Long id;
private final String name;
private final String date;
private final ReservationTime time;

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

public Long getId() {
return id;
}

public String getName() {
return name;
}

public String getDate() {
return date;
}

public ReservationTime getTime() {
return time;
}
}
22 changes: 22 additions & 0 deletions src/main/java/roomescape/domain/ReservationTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package roomescape.domain;

import java.time.LocalTime;

public class ReservationTime {

private final Long id;
private final LocalTime startAt;

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

public Long getId() {
return id;
}

public LocalTime getStartAt() {
return startAt;
}
}
23 changes: 23 additions & 0 deletions src/main/java/roomescape/dto/reservation/ReservationRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package roomescape.dto.reservation;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import roomescape.domain.Reservation;
import roomescape.domain.ReservationTime;

public record ReservationRequest(
@NotBlank(message = "이름은 공백일 수 없습니다.")
String name,
@NotNull(message = "날짜가 입력되어야 합니다.")
LocalDate date,
@NotNull(message = "시간 아이디가 입력되어야 합니다.")
Long timeId
) {

public Reservation toReservation() {
ReservationTime reservationTime = new ReservationTime(timeId, null);

return new Reservation(null, name, date.toString(), reservationTime);
}
}
21 changes: 21 additions & 0 deletions src/main/java/roomescape/dto/reservation/ReservationResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package roomescape.dto.reservation;

import roomescape.domain.Reservation;
import roomescape.dto.reservationtime.ReservationTimeResponse;

public record ReservationResponse(
Long id,
String name,
String date,
ReservationTimeResponse time
) {

public static ReservationResponse from(Reservation reservation) {
return new ReservationResponse(
reservation.getId(),
reservation.getName(),
reservation.getDate(),
ReservationTimeResponse.from(reservation.getTime())
);
}
}
Loading