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 JDBC] 정민주 미션 제출합니다. #396

Merged
merged 11 commits into from
Feb 11, 2025
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
runtimeOnly 'com.h2database:h2'
}

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

import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -14,35 +12,36 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import roomescape.entity.Reservation;
import roomescape.entity.repository.ReservationRepository;
import roomescape.exception.NotFoundException;
import roomescape.exception.ReservationException;

@RestController
public class ReservationController {

private final AtomicLong idGenerator = new AtomicLong(0);
private final ReservationRepository reservationRepository;

private final List<Reservation> reservations = new ArrayList<>();
public ReservationController(ReservationRepository reservationRepository) {
this.reservationRepository = reservationRepository;
}

@GetMapping("/reservations")
public List<Reservation> getReservations() {
return reservations;
return reservationRepository.findAll();
}

@PostMapping("/reservations")
public ResponseEntity<Reservation> createReservation(@RequestBody Reservation reservation) {
reservation.setId(idGenerator.incrementAndGet());
reservations.add(reservation);

URI location = URI.create("/reservations/" + reservation.getId());
return ResponseEntity.created(location).body(reservation);
final Reservation save = reservationRepository.save(reservation);
URI location = URI.create("/reservations/" + save.getId());
return ResponseEntity.created(location).body(save);
}

@DeleteMapping("/reservations/{id}")
public ResponseEntity<Void> deleteReservation(@PathVariable Long id) {
boolean removed = reservations.removeIf(reservation -> reservation.getId().equals(id));
final int countOfDeleted = reservationRepository.deleteById(id);

if (!removed) {
if (countOfDeleted <= 0) {
throw new NotFoundException("해당 id를 가진 예약을 찾을 수 없습니다.");
}

Expand All @@ -56,5 +55,4 @@ public ResponseEntity<String> handleException(ReservationException e) {

return ResponseEntity.status(status).body(message);
}

}
21 changes: 16 additions & 5 deletions src/main/java/roomescape/entity/Reservation.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,34 @@

public class Reservation {

private Long id;
private final Long id;
private final Name name;
private final Date date;
private final Time time;

public Reservation(Long id, String name, String date, String time) {
this.id = id;
this.name = Name.of(name);
this.date = Date.of(date);
this.time = Time.of(time);
}

public Reservation(String name, String date, String time) {
this.id = null;
this.name = Name.of(name);
this.date = Date.of(date);
this.time = Time.of(time);
}

public Long getId() {
return id;
private Reservation() {
this.id = null;
this.name = null;
this.date = null;
this.time = null;
}

public void setId(Long id) {
this.id = id;
public Long getId() {
return id;
}

public String getName() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.entity.repository;

import java.util.List;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import roomescape.entity.Reservation;

@Repository
public class ReservationRepository {

private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert simpleJdbcInsert;

public ReservationRepository(JdbcTemplate jdbcTemplate, DataSource source) {
this.jdbcTemplate = jdbcTemplate;
this.simpleJdbcInsert = new SimpleJdbcInsert(source);
this.simpleJdbcInsert.setTableName("reservation");
this.simpleJdbcInsert.usingGeneratedKeyColumns("id");

Choose a reason for hiding this comment

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

이 부분은 참고 사항인데 해당 부분을 이렇게도 표현이 가능하네요

this.simpleJdbcInsert = new SimpleJdbcInsert(source)
            .withTableName("reservation")
            .usingGeneratedKeyColumns("id");

Copy link
Author

Choose a reason for hiding this comment

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

아하 저렇게 하는게 더 가독성이 좋아보이네요 반영해두겠습니다!!

}

public List<Reservation> findAll() {
String sql = "SELECT * FROM reservation";
return jdbcTemplate.query(sql, (rs, rowNum) ->
new Reservation(
rs.getString("name"),
rs.getString("date"),
rs.getString("time")));
}

Choose a reason for hiding this comment

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

image

현재 id를 불러오지 않아서 findAll()을 했을 때 예약 번호가 잘 나타나지 않네요 수정 부탁드립니다!


public Reservation save(Reservation reservation) {
SqlParameterSource params = new MapSqlParameterSource()
.addValue("name", reservation.getName())
.addValue("date", reservation.getDate())
.addValue("time", reservation.getTime());
long id = simpleJdbcInsert.executeAndReturnKey(params).longValue();
return new Reservation(id, reservation.getName(), reservation.getDate(), reservation.getTime());
}

public int deleteById(Long id) {
String sql = "DELETE FROM reservation WHERE id = ?";
return jdbcTemplate.update(sql, id);
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:database
8 changes: 8 additions & 0 deletions src/main/resources/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE reservation
(
id BIGINT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
date DATE NOT NULL,
time VARCHAR(5) NOT NULL,
PRIMARY KEY (id)
);
80 changes: 80 additions & 0 deletions src/test/java/roomescape/JdbcStepTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package roomescape;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.annotation.DirtiesContext;
import roomescape.entity.Reservation;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD)
public class JdbcStepTest {

@Autowired
private JdbcTemplate jdbcTemplate;

@Test
void 오단계() {
try (Connection connection = jdbcTemplate.getDataSource().getConnection()) {
assertThat(connection).isNotNull();
assertThat(connection.getCatalog()).isEqualTo("DATABASE");
assertThat(connection.getMetaData().getTables(null, null, "RESERVATION", null).next()).isTrue();
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

@Test
void 육단계() {
jdbcTemplate.update("INSERT INTO reservation (name, date, time) VALUES (?, ?, ?)", "브라운", "2023-08-05",
"15:40");

List<Reservation> reservations = RestAssured.given().log().all()
.when().get("/reservations")
.then().log().all()
.statusCode(200).extract()
.jsonPath().getList(".", Reservation.class);

Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);

assertThat(reservations.size()).isEqualTo(count);
}

@Test
void 칠단계() {
Map<String, String> params = new HashMap<>();
params.put("name", "브라운");
params.put("date", "2023-08-05");
params.put("time", "10:00");

RestAssured.given().log().all()
.contentType(ContentType.JSON)
.body(params)
.when().post("/reservations")
.then().log().all()
.statusCode(201)
.header("Location", "/reservations/1");

Integer count = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(count).isEqualTo(1);

RestAssured.given().log().all()
.when().delete("/reservations/1")
.then().log().all()
.statusCode(204);

Integer countAfterDelete = jdbcTemplate.queryForObject("SELECT count(1) from reservation", Integer.class);
assertThat(countAfterDelete).isEqualTo(0);
}

}