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
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'io.rest-assured:rest-assured:5.3.1'
testImplementation 'org.assertj:assertj-core:3.24.2'
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 'com.h2database:h2'
}

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

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(InvalidReservationException.class)
public ResponseEntity<String> handleInvalidReservationException(InvalidReservationException ex) {
return ResponseEntity.badRequest().body(ex.getMessage());
}
}
7 changes: 7 additions & 0 deletions src/main/java/roomescape/InvalidReservationException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape;

public class InvalidReservationException extends RuntimeException {
public InvalidReservationException(String message) {
super(message);
}
}
7 changes: 7 additions & 0 deletions src/main/java/roomescape/InvalidTimeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package roomescape;

public class InvalidTimeException extends RuntimeException {
public InvalidTimeException(String message) {
super(message);
}
}
12 changes: 12 additions & 0 deletions src/main/java/roomescape/controller/HomeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package roomescape.controller;

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

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import roomescape.InvalidReservationException;
import roomescape.model.Reservation;
import roomescape.model.Time;
import roomescape.repository.ReservationRepository;

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


@RestController
@RequestMapping("/reservations")
public class ReservationAPIController {
private final ReservationRepository reservationRepository;

@Autowired
public ReservationAPIController(ReservationRepository reservationRepository) {
this.reservationRepository = reservationRepository;
}
@GetMapping
public List<Reservation> getReservations() {
return reservationRepository.findAll();
}
@PostMapping
public ResponseEntity<Reservation> addReservation(@RequestBody Map<String, String> params) {
String name=params.get("name");
String date=params.get("date");
String timeIdStr=params.get("time_id");

if (timeIdStr==null) {
throw new InvalidReservationException("timeid 값 오류");
}

if (name == null || name.isBlank() || date == null || date.isBlank()) {
throw new InvalidReservationException("name, date, time 모두 필요합니다.");
}

Long timeId = Long.valueOf(timeIdStr);
Time time = new Time();
time.setId(timeId);

Reservation reservation = new Reservation(null, name, date, time);
Reservation saved= reservationRepository.save(reservation);

return ResponseEntity
.created( URI.create("/reservations/" + reservation.getId()))
.body(saved);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteReservation(@PathVariable Long id) {
boolean deleted = reservationRepository.deleteById(id);

if (!deleted) {
throw new InvalidReservationException("삭제 중 오류 발생");
}

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import roomescape.model.Reservation;
import roomescape.repository.ReservationRepository;

import java.util.ArrayList;
import java.util.List;


@Controller
public class ReservationController {
private final ReservationRepository reservationRepository;

public ReservationController(ReservationRepository reservationRepository) {
this.reservationRepository = reservationRepository;
}

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

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

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import roomescape.InvalidTimeException;
import roomescape.model.Time;
import roomescape.repository.ReservationRepository;
import roomescape.repository.TimeRepository;

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

@RestController
@RequestMapping("/times")
public class TimeAPIController {
private final TimeRepository timeRepository;

public TimeAPIController(TimeRepository timeRepository) {
this.timeRepository = timeRepository;
}
@GetMapping
public List<Time> getReservations() {
return timeRepository.findAll();
}
@PostMapping
public ResponseEntity<Time> addTime(@RequestBody Map<String,String> params){
String t = params.get("time");
if (t == null || t.isBlank()) {
throw new InvalidTimeException("time값이 필요합니다.");
}

Time time = new Time(null,t);
Time saved = timeRepository.save(time);

return ResponseEntity
.created(URI.create("/times/"+saved.getId()))
.body(saved);
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteTime(@PathVariable Long id){
boolean deleted = timeRepository.deleteById(id);
if (!deleted) {
throw new InvalidTimeException("삭제 오류 발생");
}
return ResponseEntity.noContent().build();
}
}
25 changes: 25 additions & 0 deletions src/main/java/roomescape/controller/TimeController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package roomescape.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import roomescape.model.Time;
import roomescape.repository.TimeRepository;

import java.util.ArrayList;
import java.util.List;


@Controller
public class TimeController {
private final TimeRepository timeRepository;

public TimeController(TimeRepository timeRepository) {
this.timeRepository = timeRepository;
}

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

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

public class Reservation {
Copy link

Choose a reason for hiding this comment

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

현재 기본 생성자가 없네요. 만약 Reservation 클래스를 컨트롤러에서 DTO 로 사용한다면 POST 요청에서 RequestBody 로 사용할텐데요, 클라에서 전달한 JSON 본문이 Reservation 객체로 역직렬화되어야 합니다. 하지만 기본 생성자가 없으면 이 역직렬화가 실패해요!

Lombok 에서 생성자를 만들어주는 어노테이션을 찾아볼까요? 이 글 에서 세 가지 어노테이션을 잘 설명해주고 있습니다

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

public Reservation(Long id, String name, String date, Time time) {
this.id = id;
this.name = name;
this.date = date;
this.time = time;
}
public Long getId() { return id;}
public void setId(Long id) { this.id = id;}

public String getName() { return name;}
public void setName(String name) { this.name = name;}

public String getDate() { return date; }
public void setDate(String date) { this.date = date; }

public Time getTime() { return time; }
public void setTime(Time time) { this.time = time; }
}

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

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

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

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

public String getTime() { return time;}
public void setTime(String time) { this.time = time;}
}

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

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import roomescape.model.Reservation;
import roomescape.model.Time;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Repository
public class ReservationRepository {

private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert jdbcInsert;

public ReservationRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.jdbcInsert = new SimpleJdbcInsert(jdbcTemplate)
.withTableName("reservation")
.usingGeneratedKeyColumns("id");
}

public List<Reservation> findAll() {
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 " +
"LEFT JOIN time t ON r.time_id = t.id";
return jdbcTemplate.query(sql, (rs, rowNum) -> {
Time time = new Time(rs.getLong("time_id"), rs.getString("time_value"));
return new Reservation(
rs.getLong("reservation_id"),
rs.getString("name"),
rs.getString("date"),
time
);
});
}

public Reservation save(Reservation reservation) {
Map<String, Object> params = new HashMap<>();
params.put("name", reservation.getName());
params.put("date", reservation.getDate());
params.put("time_id", reservation.getTime());

Number key = jdbcInsert.executeAndReturnKey(params);
reservation.setId(key.longValue());
return reservation;

}
public boolean deleteById(Long id){
String sql= "DELETE From reservation WHERE id = ?";
int deleteRows = jdbcTemplate.update(sql, id);
return deleteRows > 0;
}
}
47 changes: 47 additions & 0 deletions src/main/java/roomescape/repository/TimeRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package roomescape.repository;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
import org.springframework.stereotype.Repository;
import roomescape.model.Time;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Repository
public class TimeRepository {

private final JdbcTemplate jdbcTemplate;
private final SimpleJdbcInsert jdbcInsert;

public TimeRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
this.jdbcInsert = new SimpleJdbcInsert(jdbcTemplate)
.withTableName("time")
.usingGeneratedKeyColumns("id");
}

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

public Time save(Time time) {
Map<String, Object> params = new HashMap<>();
params.put("time", time.getTime());

Number key = jdbcInsert.executeAndReturnKey(params);
time.setId(key.longValue());
return time;
}

public boolean deleteById(Long id) {
String sql = "DELETE FROM time WHERE id = ?";
int deletedRows = jdbcTemplate.update(sql,id);
return deletedRows > 0;
}
}
3 changes: 3 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
spring.datasource.url=jdbc:h2:mem:database;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true

Loading