-
Notifications
You must be signed in to change notification settings - Fork 134
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] 안준영 미션 제출합니다. #306
base: main
Are you sure you want to change the base?
Changes from 31 commits
316a28e
86dcc4d
633f3fa
cc436f5
9f2966a
fcfc498
ddb26a9
598103c
be66739
08c7387
6c5bfc9
35a3e5a
cc73923
48c3027
deb6d02
ce883c0
e6ad343
b7b92b0
c5b300e
1a7d4cb
520a3db
9a92583
878d9dd
80f0f20
976c1de
12561a7
7246d92
bb9ddc2
cadabba
d55847c
4f515e3
e47f4a0
6d117be
f93e66f
cbec7ba
57bbf2e
ee69a26
8c9ff70
3a3a85b
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,72 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.util.UriComponentsBuilder; | ||
import roomescape.domain.Reservation; | ||
import roomescape.dao.RoomDAO; | ||
import roomescape.dto.ReservationDto; | ||
import roomescape.service.ReservationService; | ||
import roomescape.service.TimeService; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@Controller | ||
public class RoomescapeController { | ||
|
||
private final RoomDAO RoomDAO; | ||
private final ReservationService reservationService; | ||
|
||
public RoomescapeController(RoomDAO roomDAO, TimeService timeService, ReservationService reservationService) { | ||
this.RoomDAO = roomDAO; | ||
this.reservationService = reservationService; | ||
} | ||
|
||
@GetMapping("/reservation") | ||
public String reservation() { | ||
return "new-reservation"; | ||
} | ||
|
||
@GetMapping("/reservations") | ||
@ResponseBody | ||
public ResponseEntity<List<ReservationDto>> getAllReservations(){ | ||
List<ReservationDto> reservations = RoomDAO.findAll().stream() | ||
.map(reservation -> new ReservationDto(reservation.getName(), reservation.getDate(), reservation.getTime())) | ||
.collect(Collectors.toList()); | ||
return new ResponseEntity<>(reservations, HttpStatus.OK); | ||
} | ||
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.
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. 컨트롤러에서는 클라이언트와의 소통을 하는 계층이르모 |
||
|
||
@PostMapping("/reservations") | ||
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.
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.
|
||
public ResponseEntity<?> createReservation(@RequestBody ReservationDto reservationDto) { | ||
try { | ||
Reservation reservation = reservationService.addReservation(reservationDto); | ||
URI location = UriComponentsBuilder.fromPath("/reservations/{id}") | ||
.buildAndExpand(reservation.getId()) | ||
.toUri(); | ||
return ResponseEntity.created(location).body(reservation); | ||
} catch (IllegalArgumentException e) { | ||
return ResponseEntity.badRequest().body(e.getMessage()); | ||
} | ||
} | ||
Comment on lines
+36
to
+47
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.
return ResponseEntity.status(HttpStatus.CREATED)
.header("Location 헤더 설정")
.header("필요한 다른 헤더들~~")
.body("본문 객체"); 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. 추가로 Controller에서 try-catch 블럭을 통해 예외를 잡아서 처리하는 것보다는 미션 학습 자료에 있는 |
||
|
||
@DeleteMapping("/reservations/{id}") | ||
@ResponseBody | ||
public ResponseEntity<Reservation> deleteReservation(@PathVariable int id){ | ||
if (RoomDAO.findById(id) != null) { | ||
RoomDAO.delete(id); | ||
return new ResponseEntity<>(HttpStatus.NO_CONTENT); | ||
} | ||
// 예약이 없는 경우 Exception 발생 | ||
throw new IllegalArgumentException("삭제할 예약이 없습니다."); | ||
} | ||
|
||
Junyeong-An marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@ExceptionHandler(IllegalArgumentException.class) | ||
public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException e) { | ||
return new ResponseEntity<>(e.getMessage(), HttpStatus.BAD_REQUEST); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package roomescape.controller; | ||
|
||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import roomescape.domain.Time; | ||
import roomescape.dto.TimeDto; | ||
import roomescape.dto.TimeResDto; | ||
import roomescape.service.TimeService; | ||
|
||
import java.util.List; | ||
|
||
@RestController | ||
@RequestMapping("/times") | ||
public class TimeController { | ||
private final TimeService timeService; | ||
|
||
public TimeController(TimeService timeService) { | ||
this.timeService = timeService; | ||
} | ||
|
||
@PostMapping | ||
@ResponseBody | ||
public ResponseEntity<TimeResDto> addTime(@RequestBody TimeDto timeDto) { | ||
TimeResDto timeResDto = timeService.addTime(timeDto); | ||
HttpHeaders headers = new HttpHeaders(); | ||
headers.add("Location", "/times/" + timeResDto.id()); | ||
return new ResponseEntity<>(timeResDto, headers, HttpStatus.CREATED); | ||
} | ||
Junyeong-An marked this conversation as resolved.
Show resolved
Hide resolved
|
||
@GetMapping | ||
public ResponseEntity<List<TimeResDto>> getAllTimes() { | ||
List<TimeResDto> times = timeService.getAllTimes(); | ||
return new ResponseEntity<>(times, HttpStatus.OK); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
public ResponseEntity<Void> deleteTime(@PathVariable int id) { | ||
timeService.deleteTime(id); | ||
return new ResponseEntity<>(HttpStatus.NO_CONTENT); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,58 @@ | ||||||||||||||
package roomescape.dao; | ||||||||||||||
|
||||||||||||||
import org.springframework.dao.EmptyResultDataAccessException; | ||||||||||||||
import org.springframework.jdbc.core.JdbcTemplate; | ||||||||||||||
import org.springframework.stereotype.Repository; | ||||||||||||||
import roomescape.domain.Reservation; | ||||||||||||||
import roomescape.domain.Time; | ||||||||||||||
|
||||||||||||||
import java.util.List; | ||||||||||||||
|
||||||||||||||
@Repository | ||||||||||||||
public class RoomDAO { | ||||||||||||||
private final JdbcTemplate jdbcTemplate; | ||||||||||||||
|
||||||||||||||
public RoomDAO(JdbcTemplate jdbcTemplate) { | ||||||||||||||
this.jdbcTemplate = jdbcTemplate; | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public List<Reservation> findAll() { | ||||||||||||||
return jdbcTemplate.query("SELECT 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", | ||||||||||||||
(resultSet, rowNum) -> new Reservation( | ||||||||||||||
resultSet.getInt("reservation_id"), | ||||||||||||||
resultSet.getString("name"), | ||||||||||||||
resultSet.getString("date"), | ||||||||||||||
new Time(resultSet.getInt("time_id"), resultSet.getString("time_value")) | ||||||||||||||
)); | ||||||||||||||
} | ||||||||||||||
Comment on lines
+19
to
+28
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. 문자열을 더하기 연산으로 나누다 보니 가독성이 조금 떨어지는 것 같아요.
|
||||||||||||||
|
||||||||||||||
public void insert(Reservation reservation) { | ||||||||||||||
jdbcTemplate.update("INSERT INTO reservation (name, date, time_id) VALUES (?, ?, ?)", | ||||||||||||||
reservation.getName(), reservation.getDate(), reservation.getTime().getId()); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public void delete(int id) { | ||||||||||||||
jdbcTemplate.update("DELETE FROM reservation WHERE id = ?", id); | ||||||||||||||
} | ||||||||||||||
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.
Suggested change
|
||||||||||||||
|
||||||||||||||
public int getId(Reservation reservation) { | ||||||||||||||
return jdbcTemplate.queryForObject("SELECT id FROM reservation WHERE name = ? AND date = ? AND time_id = ?", | ||||||||||||||
Integer.class, reservation.getName(), reservation.getDate(), reservation.getTime().getId()); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
public Reservation findById(int id) { | ||||||||||||||
try { | ||||||||||||||
return jdbcTemplate.queryForObject("SELECT 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 WHERE r.id = ?", | ||||||||||||||
(resultSet, rowNum) -> new Reservation( | ||||||||||||||
resultSet.getInt("reservation_id"), | ||||||||||||||
resultSet.getString("name"), | ||||||||||||||
resultSet.getString("date"), | ||||||||||||||
new Time(resultSet.getInt("time_id"), resultSet.getString("time_value")) | ||||||||||||||
), id); | ||||||||||||||
} catch (EmptyResultDataAccessException e) { | ||||||||||||||
throw new IllegalArgumentException("찾는 id가 존재하지 않습니다!"); | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package roomescape.dao; | ||
|
||
import org.springframework.dao.EmptyResultDataAccessException; | ||
import org.springframework.jdbc.core.JdbcTemplate; | ||
import org.springframework.stereotype.Repository; | ||
import roomescape.domain.Time; | ||
|
||
import java.util.List; | ||
|
||
@Repository | ||
public class TimeDAO { | ||
private final JdbcTemplate jdbcTemplate; | ||
|
||
public TimeDAO(JdbcTemplate jdbcTemplate) { | ||
this.jdbcTemplate = jdbcTemplate; | ||
} | ||
|
||
public void insert(Time time) { | ||
jdbcTemplate.update("INSERT INTO time (time) VALUES (?)", | ||
time.getTime()); | ||
} | ||
|
||
public int getId(Time time) { | ||
try { | ||
return jdbcTemplate.queryForObject( | ||
"SELECT id FROM time WHERE time = ? LIMIT 1", | ||
Integer.class, time.getTime() | ||
); | ||
} catch (Exception e) { | ||
throw new RuntimeException("찾는 id가 존재하지 않습니다!"); | ||
} | ||
} | ||
|
||
public List<Time> findAll() { | ||
return jdbcTemplate.query("SELECT * FROM time", (rs, rowNum) -> | ||
new Time(rs.getInt("id"), rs.getString("time")) | ||
); | ||
} | ||
|
||
public void delete(int id) { | ||
jdbcTemplate.update("DELETE FROM time WHERE id = ?", id); | ||
} | ||
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. public void deletebyId(int id) {
jdbcTemplate.update("DELETE FROM reservation WHERE id = ?", id);
} 준영이 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. 일관성을 위해 그게 더 좋은 것 같네요 감사합니다! |
||
|
||
public Time findByTime(String time) { | ||
try { | ||
return jdbcTemplate.queryForObject("SELECT id, time FROM time WHERE time = ? LIMIT 1", | ||
(resultSet, rowNum) -> new Time(resultSet.getInt("id"), resultSet.getString("time")), | ||
time); | ||
} catch (EmptyResultDataAccessException e) { | ||
return null; | ||
} | ||
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. try-catch 문을 사용해도 좋지만 코드가 지저분해 보일 수 있습니다. 다른 방식의 예외처리를 생각해 보시거나 검증 로직을 추가해도 좋을 거 같습니다. |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package roomescape.domain; | ||
|
||
public class Reservation { | ||
private int id; | ||
|
||
private String name; | ||
private String date; | ||
private Time time; | ||
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. id와 나머지 필드를 줄바꿈을 통해 구분한 특별한 이유가 있나요? 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. 특별한 이유는 없습니다... 수정하는 게 좋을 것 같습니다! |
||
|
||
public Reservation(int id, String name, String date, Time time) { | ||
this.id = id; | ||
this.name = name; | ||
this.date = date; | ||
this.time = time; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public int getId() { | ||
return id; | ||
} | ||
|
||
public String getDate() { | ||
return date; | ||
} | ||
|
||
public Time getTime() { | ||
return time; | ||
} | ||
|
||
public void setId(int id) { | ||
this.id = id; | ||
} | ||
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. setter를 사용하신 이유가 있나요? 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. 필요없는 것 같아 삭제했습니다...😅 |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package roomescape.domain; | ||
|
||
public class Time { | ||
int id; | ||
String time; | ||
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.
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. 클래스 외부에서 내부로 접근하지 못하게 막을 수 있어 정보은닉 및 객체는 자신의 데이터를 스스로 관리하기 때문에 캡슐화가 가능합니다. |
||
|
||
public Time(int id, String time) { | ||
this.id = id; | ||
this.time = time; | ||
} | ||
|
||
public String getTime() { | ||
return time; | ||
} | ||
|
||
public void setTime(String time) { | ||
this.time = time; | ||
} | ||
|
||
public int getId() { | ||
return id; | ||
} | ||
|
||
public void setId(int id) { | ||
this.id = id; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package roomescape.dto; | ||
|
||
import roomescape.domain.Time; | ||
|
||
public record ReservationDto( | ||
String name, String date, Time time | ||
) { | ||
public static ReservationDto from(String name, String date, Time time) { | ||
return new ReservationDto(name, date, time); | ||
} | ||
} | ||
|
||
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. record와 정적팩토리 메서드를 사용하신 이유가 궁금합니다! 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.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package roomescape.dto; | ||
|
||
public record TimeDto( | ||
String time | ||
) { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package roomescape.dto; | ||
|
||
import roomescape.domain.Time; | ||
|
||
public record TimeResDto( | ||
int id, String time | ||
) { | ||
public static TimeResDto from(Time time) { | ||
return new TimeResDto(time.getId(), time.getTime()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package roomescape.service; | ||
|
||
import org.springframework.stereotype.Service; | ||
import roomescape.dao.RoomDAO; | ||
import roomescape.domain.Reservation; | ||
import roomescape.domain.Time; | ||
import roomescape.dto.ReservationDto; | ||
import roomescape.dto.TimeResDto; | ||
|
||
@Service | ||
public class ReservationService { | ||
private final RoomDAO roomDAO; | ||
private final TimeService timeService; | ||
Comment on lines
+13
to
+16
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.
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. 서비스에서 다른 서비스단을 의존성 주입 받으면 재사용성을 할 수 있다는 장점이 있지만 mvc패턴이 제대로 지켜지지 않아 복잡도가 증가하고 단위 테스트를 할 때도 의존성이 증가해 어려움이 있습니다. |
||
|
||
public ReservationService(RoomDAO roomDAO, TimeService timeService) { | ||
this.roomDAO = roomDAO; | ||
this.timeService = timeService; | ||
} | ||
|
||
public Reservation addReservation(ReservationDto reservationDto) { | ||
String name = reservationDto.name(); | ||
String date = reservationDto.date(); | ||
String timeString = reservationDto.time().getTime(); | ||
|
||
TimeResDto timeResDto = timeService.findByTime(timeString); | ||
Time time = new Time(timeResDto.id(), timeResDto.time()); | ||
if (time == null) { | ||
throw new IllegalArgumentException("시간을 찾을 수 없습니다."); | ||
} | ||
|
||
Reservation reservation = new Reservation(0, name, date, time); | ||
roomDAO.insert(reservation); | ||
int id = roomDAO.getId(reservation); | ||
reservation.setId(id); | ||
return reservation; | ||
} | ||
} |
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.
TimeService를 매개변수로 포함하신 이유가 있으신가요?
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.
사용되지 않는데 잘못 포함한 것 같습니다... 😅