Skip to content
Open
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
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
}

test {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

@Controller
public class ReservationController {
private static final String VIEW_RESERVATION = "reservation";
private static final String VIEW_RESERVATION = "new-reservation";

@GetMapping("/reservation")
public String reservation() {
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/roomescape/controller/TimeApiController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package roomescape.controller;

import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import roomescape.dto.TimeRequest;
import roomescape.dto.TimeResponse;
import roomescape.service.TimeService;

import java.net.URI;
import java.util.List;

@RestController
@RequestMapping("/times")
@RequiredArgsConstructor
public class TimeApiController {

private final TimeService timeService;

@PostMapping
public ResponseEntity<TimeResponse> create(@RequestBody TimeRequest request) {
TimeResponse response = timeService.create(request);
return ResponseEntity.created(URI.create("/times/" + response.getId()))
.body(response);
}

@GetMapping
public List<TimeResponse> findAll() {
return timeService.findAll();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(@PathVariable Long id) {
timeService.delete(id);
return ResponseEntity.noContent().build();
}
}
14 changes: 14 additions & 0 deletions src/main/java/roomescape/controller/TimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package roomescape.controller;

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

@Controller
public class TimeController {
private static final String VIEW_TIME = "time";

@GetMapping("/time")
public String home() {
return VIEW_TIME;
}
}
10 changes: 5 additions & 5 deletions src/main/java/roomescape/domain/Reservation.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ public class Reservation {
private final Long id;
private final String name;
private final LocalDate date;
private final LocalTime time;
private final Time time;

private Reservation(Long id, String name, LocalDate date, LocalTime time) {
private Reservation(Long id, String name, LocalDate date, Time time) {
validate(name, date, time);
this.id = id;
this.name = name;
this.date = date;
this.time = time;
}

public static Reservation of(Long id, String name, LocalDate date, LocalTime time) {
public static Reservation of(Long id, String name, LocalDate date, Time time) {
return new Reservation(id, name, date, time);
}

private void validate(String name, LocalDate date, LocalTime time) {
private void validate(String name, LocalDate date, Time time) {
List<String> errors = new ArrayList<>();

if (name == null || name.isBlank()) {
Expand Down Expand Up @@ -54,7 +54,7 @@ public LocalDate getDate() {
return date;
}

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

public class Time {
private final Long id;
private final String time;

private Time(Long id, String time) {
validate(time);
this.id = id;
this.time = time;
}

private void validate(String time) {
if (time == null) {
throw new IllegalArgumentException("시간 값은 null일 수 없습니다.");
}
if (time.isBlank()) {
throw new IllegalArgumentException("시간 값은 빈 문자열일 수 없습니다.");
}
}

public static Time of(Long id, String time) {
return new Time(id, time);
}

public static Time of(String time) {
return of(null, time);
}

public Long getId() {
return id;
}

public String getTime() {
return time;
}
}

9 changes: 3 additions & 6 deletions src/main/java/roomescape/dto/ReservationRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ public class ReservationRequest {
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate date;

@NotNull
@JsonFormat(pattern = "HH:mm")
private LocalTime time;
private Long timeId;

protected ReservationRequest() {
}
Expand All @@ -31,8 +29,7 @@ public LocalDate getDate() {
return date;
}

public LocalTime getTime() {
return time;
public Long getTimeId() {
return timeId;
}
}

6 changes: 3 additions & 3 deletions src/main/java/roomescape/dto/ReservationResponse.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ public class ReservationResponse {
private LocalDate date;

@JsonFormat(pattern = "HH:mm")
private LocalTime time;
private TimeResponse time;

public ReservationResponse(Reservation reservation) {
this.id = reservation.getId();
this.name = reservation.getName();
this.date = reservation.getDate();
this.time = reservation.getTime();
this.time = new TimeResponse(reservation.getTime());
}

public Long getId() {
Expand All @@ -35,7 +35,7 @@ public LocalDate getDate() {
return date;
}

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

import jakarta.validation.constraints.NotBlank;

public class TimeRequest {
@NotBlank
private String time;

protected TimeRequest() {};

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

import roomescape.domain.Time;

public class TimeResponse {
private Long id;
private String time;

public TimeResponse(Time time) {
this.id = time.getId();
this.time = time.getTime();
}

public Long getId() {
return id;
}

public String getTime() {
return time;
}
}
57 changes: 44 additions & 13 deletions src/main/java/roomescape/repository/JdbcReservationRepository.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package roomescape.repository;

import java.sql.PreparedStatement;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import roomescape.domain.Reservation;
import roomescape.domain.Time;
import roomescape.dto.ReservationResponse;

@Repository
Expand All @@ -24,34 +29,60 @@ public JdbcReservationRepository(DataSource dataSource) {
.usingGeneratedKeyColumns("id");
}

private final RowMapper<Reservation> rowMapper = (rs, rowNum) -> Reservation.of(
rs.getLong("id"),
rs.getString("name"),
rs.getDate("date").toLocalDate(),
rs.getTime("time").toLocalTime()
);
private final RowMapper<Reservation> rowMapper = (rs, rowNum) -> {
Long reservationId = rs.getLong("reservation_id");
String name = rs.getString("name");
LocalDate date = LocalDate.parse(rs.getString("date"));

Long timeId = rs.getLong("time_id");
String timeValue = rs.getString("time_value");
Time time = Time.of(timeId, timeValue);

return Reservation.of(reservationId, name, date, time);
};

@Override
public List<ReservationResponse> findAll() {
List<Reservation> reservations = jdbcTemplate.query("SELECT * FROM reservation ORDER BY id", rowMapper);
String sql = """
SELECT
r.id AS reservation_id,
r.name,
r.date,
t.id AS time_id,
t.time AS time_value
FROM reservation r
INNER JOIN time t ON r.time_id = t.id
ORDER BY r.id
""";

List<Reservation> reservations = jdbcTemplate.query(sql, rowMapper);
return reservations.stream()
.map(ReservationResponse::new)
.toList();
}


@Override
public ReservationResponse save(Reservation reservation) {
Number key = insert.executeAndReturnKey(Map.of(
"name", reservation.getName(),
"date", reservation.getDate(),
"time", reservation.getTime()
));
String sql = "INSERT INTO reservation (name, date, time_id) VALUES (?, ?, ?)";
KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(con -> {
PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"});
ps.setString(1, reservation.getName());
ps.setString(2, reservation.getDate().toString());
ps.setLong(3, reservation.getTime().getId());
return ps;
}, keyHolder);

Long generatedId = keyHolder.getKey().longValue();
Reservation saved = Reservation.of(
key.longValue(),
generatedId,
reservation.getName(),
reservation.getDate(),
reservation.getTime()
);

return new ReservationResponse(saved);
}

Expand Down
54 changes: 54 additions & 0 deletions src/main/java/roomescape/repository/JdbcTimeRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package roomescape.repository;

import java.sql.PreparedStatement;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Repository;
import roomescape.domain.Time;

@Repository
@RequiredArgsConstructor
public class JdbcTimeRepository implements TimeRepository {

private final JdbcTemplate jdbcTemplate;

private final RowMapper<Time> rowMapper = (rs, rowNum) ->
Time.of(rs.getLong("id"), rs.getString("time"));

@Override
public Time save(Time time) {
String sql = "INSERT INTO time (time) VALUES (?)";
KeyHolder keyHolder = new GeneratedKeyHolder();

jdbcTemplate.update(con -> {
PreparedStatement ps = con.prepareStatement(sql, new String[]{"id"});
ps.setString(1, time.getTime());
return ps;
}, keyHolder);

Long generatedId = keyHolder.getKey().longValue();
return Time.of(generatedId, time.getTime());
}

@Override
public List<Time> findAll() {
return jdbcTemplate.query("SELECT * FROM time", rowMapper);
}

@Override
public void deleteById(Long id) {
jdbcTemplate.update("DELETE FROM time WHERE id = ?", id);
}

@Override
public Optional<Time> findById(Long id) {
List<Time> times = jdbcTemplate.query("SELECT * FROM time WHERE id = ?", rowMapper, id);
return times.stream().findFirst();
}
}

16 changes: 16 additions & 0 deletions src/main/java/roomescape/repository/TimeRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package roomescape.repository;

import java.util.List;
import java.util.Optional;
import roomescape.domain.Time;

public interface TimeRepository {
Time save(Time time);

List<Time> findAll();

void deleteById(Long id);

Optional<Time> findById(Long id);

}
Loading