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

[Spring MVC + JDBC + CORE] 김민창 미션 제출합니다. #368

Open
wants to merge 10 commits into
base: idle2534
Choose a base branch
from
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,15 @@ repositories {
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
compileOnly 'org.projectlombok:lombok:1.18.34'
annotationProcessor 'org.projectlombok:lombok'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
runtimeOnly 'com.h2database:h2'
}

test {
Expand Down
60 changes: 60 additions & 0 deletions src/main/java/roomescape/controller/ReservationController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package roomescape.controller;

import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
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 roomescape.domain.Reservation;
import roomescape.domain.Reservation.NotFoundReservationException;
import roomescape.dto.ReservationRequestDto;
import roomescape.service.ReservationService;

@Controller
@RequiredArgsConstructor
public class ReservationController {
private final ReservationService reservationService;

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

@GetMapping("/reservations")
public ResponseEntity<List<Reservation>> reservations() {
List<Reservation> reservations = reservationService.getReservations();
return ResponseEntity.ok(reservations);
}

@PostMapping("/reservations")
public ResponseEntity<Reservation> addReservation(@RequestBody @Validated ReservationRequestDto reservationRequestDto) {
try {
Long.parseLong(reservationRequestDto.getTime());
} catch (NumberFormatException e) {
return ResponseEntity.badRequest().build();
}

Reservation reservation = reservationService.addReservation(reservationRequestDto);
return ResponseEntity
.created(URI.create("/reservations/" + reservation.getId()))
.body(reservation);
}

@DeleteMapping("/reservations/{id}")
public ResponseEntity<Reservation> deleteReservation(@PathVariable Long id) {
reservationService.removeReservation(id);
return ResponseEntity.noContent().build();
}

@ExceptionHandler(NotFoundReservationException.class)
public ResponseEntity<Void> handleException(NotFoundReservationException e) {
return ResponseEntity.badRequest().build();
}
}
48 changes: 48 additions & 0 deletions src/main/java/roomescape/controller/TimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package roomescape.controller;

import java.net.URI;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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 roomescape.domain.Time;
import roomescape.dto.TimeRequestDto;
import roomescape.service.TimeService;

@Controller
@RequiredArgsConstructor
public class TimeController {

private final TimeService timeService;

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

@GetMapping("/times")
public ResponseEntity<List<Time>> getTimes() {
List<Time> times = timeService.getTimes();
return ResponseEntity.ok(times);
}

@PostMapping("/times")
public ResponseEntity<Time> times(@RequestBody TimeRequestDto timeRequestDto) {
Time time = timeService.addTime(timeRequestDto);
return ResponseEntity
.created(URI.create("/times/" + time.getId()))
.body(time);
}

@DeleteMapping("/times/{id}")
public ResponseEntity<Time> deleteTime(@PathVariable Long id) {
timeService.removeTime(id);
return ResponseEntity.noContent().build();
}
}
55 changes: 55 additions & 0 deletions src/main/java/roomescape/dao/ReservationDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package roomescape.dao;

import java.sql.PreparedStatement;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
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.ReservationRequestDto;

@Repository
@RequiredArgsConstructor
public class ReservationDao {

private final JdbcTemplate jdbcTemplate;

public List<Reservation> findAll() {
return jdbcTemplate.query("SELECT "

Choose a reason for hiding this comment

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

java 17부터는 여러 라인의 문자열을 나타낼 떄
"""
"""
로 감쌀 수 있는 문법이 있어요 한번 확인해보시면 좋을 것 같습니다.

+ "r.id AS reservation_id, "
+ "r.name, "
+ "r.date, "
+ "t.id AS time_id, "
+ "t.time AS time_value "
+ "FROM reservation AS r INNER JOIN time AS t ON r.time_id = t.id", (rs, rowNum) ->
new Reservation(
rs.getLong("reservation_id"),
rs.getString("name"),
rs.getString("date"),
new Time(rs.getLong("time_id"), rs.getString("time_value"))
));
}

public Reservation save(ReservationRequestDto reservationRequestDto) {

Choose a reason for hiding this comment

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

Dao를 만드셨군요!!

Dto랑 Dao는 무엇인지?
둘은 mvc 중에 어디에 속하는지 궁금해요.

KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO reservation (name, date, time_id) VALUES (?, ?, ?)",
new String[]{"id"}
);
ps.setString(1, reservationRequestDto.getName());
ps.setString(2, reservationRequestDto.getDate());
ps.setLong(3, Long.parseLong(reservationRequestDto.getTime()));
return ps;
}, keyHolder);

return new Reservation(keyHolder.getKey().longValue(), reservationRequestDto.getName(), reservationRequestDto.getDate());
}

public int delete(Long id) {
return jdbcTemplate.update("DELETE FROM reservation WHERE id = ?", id);
}
}
58 changes: 58 additions & 0 deletions src/main/java/roomescape/dao/TimeDao.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package roomescape.dao;

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

@Repository
@RequiredArgsConstructor
public class TimeDao {
private final JdbcTemplate jdbcTemplate;

public List<Time> findAll() {
return jdbcTemplate.query("SELECT * FROM time", (rs, rowNum) ->
new Time(
rs.getLong("id"),
rs.getString("time")
));
}

public Optional<Time> findById(Long id) {
try {
Time time = jdbcTemplate.queryForObject("SELECT * FROM time WHERE id = (?)", (rs, rowNum) ->
new Time(
rs.getLong("id"),
rs.getString("time")),
id);
return Optional.of(time);
} catch (EmptyResultDataAccessException e) {
return Optional.empty();
}
}

public Time save(TimeRequestDto timeRequestDto) {
KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(connection -> {
PreparedStatement ps = connection.prepareStatement(
"INSERT INTO time (time) VALUES (?)",
new String[] {"id"}
);
ps.setString(1, timeRequestDto.getTime());
return ps;
}, keyHolder);

return new Time(keyHolder.getKey().longValue(), timeRequestDto.getTime());
}

public int delete(Long id) {
return jdbcTemplate.update("DELETE FROM time WHERE id = ?", id);
}
}
25 changes: 25 additions & 0 deletions src/main/java/roomescape/domain/Reservation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class Reservation {
public static class NotFoundReservationException extends RuntimeException{}

private Long id;
private String name;
private String date;
private Time time;

public Reservation(Long id, String name, String date) {
this.id = id;
this.name = name;
this.date = date;
}
}
18 changes: 18 additions & 0 deletions src/main/java/roomescape/domain/Time.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package roomescape.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@AllArgsConstructor
@NoArgsConstructor

Choose a reason for hiding this comment

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

AllArgsConstructor와 NoArgsConstructor 둘 모두 필요한 생성자인가요??

@Getter
@Setter
public class Time {
public static class NotFoundTimeException extends RuntimeException {}

Long id;

String time;
}
17 changes: 17 additions & 0 deletions src/main/java/roomescape/dto/ReservationRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package roomescape.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.Getter;

@Getter
public class ReservationRequestDto {

@NotBlank
private String name;

@NotBlank
private String date;

@NotBlank
private String time;
}
14 changes: 14 additions & 0 deletions src/main/java/roomescape/dto/TimeRequestDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package roomescape.dto;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@AllArgsConstructor
@NoArgsConstructor
@Getter
public class TimeRequestDto {

private String time;
}
14 changes: 14 additions & 0 deletions src/main/java/roomescape/service/ReservationService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package roomescape.service;

import java.util.List;
import roomescape.domain.Reservation;
import roomescape.dto.ReservationRequestDto;

public interface ReservationService {

List<Reservation> getReservations();

Reservation addReservation(ReservationRequestDto reservationRequestDto);

void removeReservation(Long id);

Choose a reason for hiding this comment

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

ReservationService와 ServiceImpl을 나누셨군요. 그렇게 구현하신 이유가 있을까요??

}
38 changes: 38 additions & 0 deletions src/main/java/roomescape/service/ReservationServiceImpl.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package roomescape.service;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import roomescape.dao.ReservationDao;
import roomescape.dao.TimeDao;
import roomescape.domain.Reservation;
import roomescape.domain.Reservation.NotFoundReservationException;
import roomescape.domain.Time;
import roomescape.dto.ReservationRequestDto;

@Service
@RequiredArgsConstructor
public class ReservationServiceImpl implements ReservationService {

private final ReservationDao reservationDao;
private final TimeDao timeDao;

@Override
public List<Reservation> getReservations() {
return reservationDao.findAll();
}

@Override
public Reservation addReservation(final ReservationRequestDto reservationRequestDto) {
Reservation reservation = reservationDao.save(reservationRequestDto);
Time time = timeDao.findById(Long.parseLong(reservationRequestDto.getTime())).orElseThrow();
reservation.setTime(time);
return reservation;
}

@Override
public void removeReservation(final Long id) {
if (reservationDao.delete(id) == 0)
throw new NotFoundReservationException();
}
}
14 changes: 14 additions & 0 deletions src/main/java/roomescape/service/TimeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package roomescape.service;

import java.util.List;
import roomescape.domain.Time;
import roomescape.dto.TimeRequestDto;

public interface TimeService {

List<Time> getTimes();

Time addTime(TimeRequestDto timeRequestDto);

void removeTime(Long id);
}
Loading