-
Notifications
You must be signed in to change notification settings - Fork 119
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 Core] 정다영 미션 제출합니다. #274
base: day024
Are you sure you want to change the base?
Changes from all commits
6ec0522
cc9cecb
2b8857c
a11027e
0e1d276
77d7d76
85045b2
1a8b0fb
daaff1f
f70e5eb
6a38973
d9ba166
d436151
5242bc4
c43e527
52fb4c0
2443995
23c4741
d9f0591
d07daf8
1f4e8b1
98fa170
b1f8f59
6860177
9564f6e
0f7a02b
9f787e8
369ed2e
7b9ff9e
ccc556e
39d4e57
badc33e
8e38268
24b7879
05053eb
810a6a0
819f180
b0dcc7a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
# Spring JDBC | ||
|
||
<h3>5단계 요구사항</h3> | ||
|
||
h2 데이터베이스를 활용하여 데이터를 저장하도록 수정 | ||
- [x] gradle 의존성 추가 | ||
- [x] 테이블 스키마 정의 | ||
- [x] 데이터베이스 설정 | ||
- [x] 요구 사항 테스트 진행 | ||
|
||
<h3>6단계 요구사항</h3> | ||
|
||
예약 조회 API 처리 로직에서 저장된 예약을 조회할 때 데이터베이스를 활용하도록 수정 | ||
- [x] 데이터를 조회하는 기능을 구현 | ||
- SQL - SELECT 쿼리 | ||
- JdbcTemplate | ||
- [x] 요구 사항 테스트 추가 | ||
|
||
<h3>7단계 요구사항</h3> | ||
데이터 추가/삭제하기 | ||
|
||
- [x] 예약 추가/취소 API 처리 로직에서 데이터베이스를 활용하도록 수정 | ||
- 기존에 사용하던 List 및 AtomicLong 제거 | ||
- [x] 요구 사항 테스트 추가 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package roomescape.DAO; | ||
|
||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert; | ||
import org.springframework.stereotype.Repository; | ||
import roomescape.domain.Reservation; | ||
import roomescape.domain.Time; | ||
|
||
import javax.sql.DataSource; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
@Repository | ||
public class ReservationDAO { | ||
|
||
private final JdbcTemplate jdbcTemplate; | ||
private final SimpleJdbcInsert simpleJdbcInsert; | ||
|
||
public ReservationDAO(DataSource dataSource) { | ||
this.jdbcTemplate = new JdbcTemplate(dataSource); | ||
this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) | ||
.withTableName("reservation") | ||
.usingGeneratedKeyColumns("id"); | ||
} | ||
|
||
public List<Reservation> findAll() { | ||
String sql = "SELECT r.id, r.name, r.date, t.id as time_id, t.time FROM reservation r INNER JOIN time t ON r.time_id = t.id"; | ||
return jdbcTemplate.query(sql, (rs, rowNum) -> { | ||
long id = rs.getLong("id"); | ||
String name = rs.getString("name"); | ||
String date = rs.getString("date"); | ||
Time time = new Time(rs.getLong("time_id"), rs.getString("time")); | ||
return new Reservation(id, name, date, time); | ||
}); | ||
} | ||
|
||
public Reservation findById(long id) { | ||
String sql = "SELECT r.id, r.name, r.date, t.id as time_id, t.time FROM reservation r INNER JOIN time t ON r.time_id = t.id WHERE r.id = ?"; | ||
return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> { | ||
long reservationId = rs.getLong("id"); | ||
String name = rs.getString("name"); | ||
String date = rs.getString("date"); | ||
Time time = new Time(rs.getLong("time_id"), rs.getString("time")); | ||
return new Reservation(reservationId, name, date, time); | ||
}); | ||
} | ||
|
||
public long save(Reservation reservation) { | ||
Map<String, Object> parameters = new HashMap<>(); | ||
parameters.put("name", reservation.getName()); | ||
parameters.put("date", reservation.getDate()); | ||
parameters.put("time_id", reservation.getTime().getId()); | ||
|
||
Number key = simpleJdbcInsert.executeAndReturnKey(parameters); | ||
return key.longValue(); | ||
} | ||
|
||
public long deleteById(long id) { | ||
String sql = "DELETE FROM reservation WHERE id = ?"; | ||
int rowsAffected = jdbcTemplate.update(sql, id); | ||
return rowsAffected > 0 ? id : -1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rowsAffected가 0인 경우에는 controller에서 예외처리를 하셨는데 |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package roomescape.DAO; | ||
|
||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.jdbc.core.simple.SimpleJdbcInsert; | ||
import org.springframework.stereotype.Repository; | ||
import roomescape.domain.Time; | ||
|
||
import javax.sql.DataSource; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
@Repository | ||
public class TimeDAO { | ||
private final JdbcTemplate jdbcTemplate; | ||
private final SimpleJdbcInsert simpleJdbcInsert; | ||
|
||
public TimeDAO(DataSource dataSource) { | ||
this.jdbcTemplate = new JdbcTemplate(dataSource); | ||
this.simpleJdbcInsert = new SimpleJdbcInsert(jdbcTemplate) | ||
.withTableName("time") | ||
.usingGeneratedKeyColumns("id"); | ||
} | ||
|
||
public List<Time> findAll() { | ||
String sql = "SELECT id, time FROM time"; | ||
return jdbcTemplate.query(sql, (rs, rowNum) -> new Time(rs.getLong("id"), rs.getString("time"))); | ||
} | ||
|
||
public Time findById(long id) { | ||
String sql = "SELECT id, time FROM time WHERE id = ?"; | ||
return jdbcTemplate.queryForObject(sql, new Object[]{id}, (rs, rowNum) -> new Time(rs.getLong("id"), rs.getString("time"))); | ||
} | ||
|
||
public long save(Time time) { | ||
Map<String, Object> parameters = new HashMap<>(); | ||
parameters.put("time", time.getTime()); | ||
|
||
Number key = simpleJdbcInsert.executeAndReturnKey(parameters); | ||
return key.longValue(); | ||
} | ||
|
||
public long deleteById(long id) { | ||
String sql = "DELETE FROM time WHERE id = ?"; | ||
int rowsAffected = jdbcTemplate.update(sql, id); | ||
return rowsAffected > 0 ? id : -1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. reservationDAO 와 동일합니다! |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
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"; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.*; | ||
import roomescape.domain.Reservation; | ||
import roomescape.DAO.ReservationDAO; | ||
import roomescape.exception.NotFoundReservationException; | ||
import roomescape.service.ReservationService; | ||
|
||
import javax.sql.DataSource; | ||
import java.net.URI; | ||
import java.util.List; | ||
|
||
@Controller | ||
public class ReservationController { | ||
private final String NOT_FOUND_RESERVATION_MESSAGE = "삭제할 예약을 찾을 수 없습니다."; | ||
private final ReservationService reservationService; | ||
|
||
@Autowired | ||
public ReservationController(ReservationService reservationService) { | ||
this.reservationService = reservationService; | ||
} | ||
|
||
@GetMapping("/reservation") | ||
public String newReservation() { | ||
return "new-reservation"; | ||
} | ||
|
||
@GetMapping("/reservations") | ||
public ResponseEntity<List<Reservation>> getReservations() { | ||
List<Reservation> reservationList = reservationService.findAll(); | ||
return ResponseEntity.ok(reservationList); | ||
} | ||
|
||
@PostMapping("/reservations") | ||
public ResponseEntity<Reservation> addReservation(@RequestBody Reservation request) { | ||
|
||
long id = reservationService.save(request); | ||
Reservation reservation = reservationService.findById(id); | ||
URI location = URI.create("/reservations/" + id); | ||
|
||
return ResponseEntity.created(location).body(reservation); | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. findById와 save 메서드를 분리하신 이유가 있을까요? |
||
@DeleteMapping("/reservations/{id}") | ||
public ResponseEntity<Void> cancelReservation(@PathVariable long id) { | ||
long deletedId = reservationService.deleteById(id); | ||
|
||
if (deletedId == -1) { | ||
throw new NotFoundReservationException(NOT_FOUND_RESERVATION_MESSAGE); | ||
} | ||
|
||
URI location = URI.create("/reservations/" + deletedId); | ||
ResponseEntity.noContent().location(location).build(); | ||
|
||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.*; | ||
import roomescape.domain.Time; | ||
import roomescape.service.TimeService; | ||
|
||
import javax.sql.DataSource; | ||
import java.net.URI; | ||
import java.util.List; | ||
|
||
@Controller | ||
public class TimeController { | ||
private final TimeService timeService; | ||
|
||
@Autowired | ||
public TimeController(TimeService timeService) { | ||
this.timeService = timeService; | ||
} | ||
|
||
@GetMapping("/time") | ||
public String times() { | ||
return "time"; | ||
} | ||
|
||
@PostMapping("/times") | ||
public ResponseEntity<Time> addTime(@RequestBody Time request) { | ||
long id = timeService.save(request); | ||
Time time = timeService.findById(id); | ||
URI location = URI.create("/times/" + id); | ||
|
||
return ResponseEntity.created(location).body(time); | ||
} | ||
|
||
@GetMapping("/times") | ||
public ResponseEntity<List<Time>> getTimes() { | ||
List<Time> timeList = timeService.findAll(); | ||
return ResponseEntity.ok(timeList); | ||
} | ||
|
||
@DeleteMapping("/times/{id}") | ||
public ResponseEntity<Void> deleteTime(@PathVariable long id) { | ||
long deletedId = timeService.deleteById(id); | ||
if (deletedId == -1) { | ||
return ResponseEntity.notFound().build(); | ||
} | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package roomescape.domain; | ||
|
||
import roomescape.exception.InvalidRequestException; | ||
|
||
public class Reservation { | ||
private Long id; | ||
private String name; | ||
private String date; | ||
private Time time; | ||
|
||
private final String INVALID_NAME_REQUEST_MESSAGE = "이름 정보가 공백입니다."; | ||
private final String INVALID_DATE_REQUEST_MESSAGE = "날짜 정보가 공백입니다."; | ||
private final String INVALID_TIME_REQUEST_MESSAGE = "시간 정보가 공백입니다."; | ||
|
||
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 String getDate() { | ||
return date; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Time getTime() { | ||
return time; | ||
} | ||
|
||
public void Validate(){ | ||
nameValidate(); | ||
dateValidate(); | ||
timeValidate(); | ||
} | ||
|
||
public void nameValidate() { | ||
if (isBlank(name)) { | ||
throw new InvalidRequestException(INVALID_NAME_REQUEST_MESSAGE); | ||
} | ||
} | ||
|
||
public void dateValidate() { | ||
if (isBlank(date)) { | ||
throw new InvalidRequestException(INVALID_DATE_REQUEST_MESSAGE); | ||
} | ||
} | ||
|
||
public void timeValidate() { | ||
if (isBlank(time.getTime())) { | ||
throw new InvalidRequestException(INVALID_TIME_REQUEST_MESSAGE); | ||
} | ||
} | ||
|
||
private boolean isBlank(String str) { | ||
return str == null || str.trim().isEmpty(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package roomescape.domain; | ||
|
||
public class Time { | ||
private Long id; | ||
private String 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; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
공통 피드백에서 나온 내용을 잘 반영하셨네요!