-
Notifications
You must be signed in to change notification settings - Fork 132
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] 정연희 미션 제출합니다 #278
base: spig0126
Are you sure you want to change the base?
Changes from all commits
d0ef878
4cf1889
dcc87b3
170d340
f292798
1022775
abbd3ff
6ac0428
e127140
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,34 @@ | ||
package roomescape.advice; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.MethodArgumentNotValidException; | ||
import org.springframework.web.bind.annotation.ControllerAdvice; | ||
import org.springframework.web.bind.annotation.ExceptionHandler; | ||
|
||
import roomescape.exception.DatabaseOperationException; | ||
import roomescape.exception.ReservationNotFoundException; | ||
import roomescape.exception.TimeNotFoundException; | ||
|
||
@ControllerAdvice | ||
public class GlobalControllerAdvice { | ||
@ExceptionHandler(ReservationNotFoundException.class) | ||
public ResponseEntity<String> handleReservationNotFoundException(ReservationNotFoundException ex) { | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); | ||
} | ||
|
||
@ExceptionHandler(DatabaseOperationException.class) | ||
public ResponseEntity<String> handleDatabaseOperationException(DatabaseOperationException ex) { | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage()); | ||
} | ||
|
||
@ExceptionHandler(MethodArgumentNotValidException.class) | ||
public ResponseEntity<String> handleValidationExceptions(MethodArgumentNotValidException ex) { | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); | ||
} | ||
|
||
@ExceptionHandler(TimeNotFoundException.class) | ||
public ResponseEntity handleTimeNotFoundException(TimeNotFoundException ex) { | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package roomescape.controller; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.stereotype.Controller; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import jakarta.validation.Valid; | ||
|
||
import roomescape.domain.Reservation; | ||
import roomescape.service.ReservationService; | ||
|
||
@Controller | ||
public class ReservationController { | ||
@Autowired | ||
private ReservationService reservationService; | ||
|
||
@GetMapping("/reservation") | ||
public String reservation() { | ||
return "new-reservation"; | ||
} | ||
|
||
@GetMapping("/reservations") | ||
@ResponseBody | ||
public ResponseEntity<List<Reservation>> getReservations(){ | ||
List<Reservation> reservations = reservationService.getAllReservations(); | ||
return ResponseEntity.ok(reservations); | ||
} | ||
|
||
@GetMapping("/reservations/{id}") | ||
@ResponseBody | ||
public ResponseEntity<Reservation> getReservation(@PathVariable long id){ | ||
Reservation reservation = reservationService.getReservationById(id); | ||
return ResponseEntity.ok(reservation); | ||
} | ||
|
||
@PostMapping("/reservations") | ||
@ResponseBody | ||
public ResponseEntity<Reservation> createReservation(@Valid @RequestBody Reservation reservation) { | ||
Reservation newReservation = reservationService.createReservation(reservation); | ||
String uri = "/reservations/" + newReservation.getId(); | ||
return ResponseEntity.created(URI.create(uri)).body(newReservation); | ||
} | ||
|
||
@DeleteMapping("/reservations/{id}") | ||
public ResponseEntity<Void> deleteReservation(@PathVariable long id){ | ||
reservationService.deleteReservation(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package roomescape.controller; | ||
|
||
import jakarta.validation.Valid; | ||
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 java.net.URI; | ||
import java.util.List; | ||
|
||
@Controller | ||
public class TimeController { | ||
@Autowired | ||
private TimeService timeService; | ||
|
||
@GetMapping("/time") | ||
public String time() { | ||
return "time"; | ||
} | ||
|
||
@GetMapping("/times") | ||
public ResponseEntity<List<Time>> getTimes() { | ||
List<Time> times = timeService.getAllTimes(); | ||
return ResponseEntity.ok(times); | ||
} | ||
|
||
@GetMapping("/times/{id}") | ||
@ResponseBody | ||
public ResponseEntity<Time> getTimeById(@PathVariable long id) { | ||
Time time = timeService.getTimeById(id); | ||
return ResponseEntity.ok(time); | ||
} | ||
|
||
@PostMapping("/times") | ||
@ResponseBody | ||
public ResponseEntity<Time> addTime(@Valid @RequestBody Time time) { | ||
Time newTime = timeService.createTime(time); | ||
String uri = "/times/" + newTime.getId(); | ||
return ResponseEntity.created(URI.create(uri)).body(newTime); | ||
} | ||
|
||
@DeleteMapping("/times/{id}") | ||
public ResponseEntity<Void> deleteTime(@PathVariable long id) { | ||
timeService.deleteTimeById(id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package roomescape.domain; | ||
|
||
import jakarta.persistence.*; | ||
import jakarta.validation.constraints.NotBlank; | ||
|
||
@Entity | ||
public class Reservation { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private long id; | ||
|
||
@NotBlank(message="Name cannot be empty") | ||
private String name; | ||
|
||
@NotBlank(message="Date cannot be empty") | ||
private String date; | ||
|
||
@ManyToOne | ||
private Time time; | ||
|
||
public Reservation(){} | ||
|
||
public long getId() {return this.id;} | ||
public String getName() {return this.name;} | ||
public String getDate() {return this.date;} | ||
public Time getTime() {return this.time;} | ||
|
||
public long setId(long id) {return this.id = id;} | ||
public String setName(String name) {return this.name = name;} | ||
public String setDate(String date) {return this.date = date;} | ||
public Time setTime(Time time) {return this.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. 무분별한 setter 선언은 객체지향 프로그래밍을 지키기 어렵게 하기 때문에 지양하는 것이 좋습니다..! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package roomescape.domain; | ||
|
||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.validation.constraints.NotBlank; | ||
|
||
@Entity | ||
public class Time { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private long id; | ||
|
||
@NotBlank(message="Time cannot be empty") | ||
private String time; | ||
|
||
public Time(){} | ||
|
||
public Time(String id) { | ||
this.id = setId(Long.parseLong(id)); | ||
} | ||
public long getId() {return this.id;} | ||
public String getTime() {return this.time;} | ||
|
||
public long setId(long id) {return this.id = id;} | ||
public String setTime(String time) {return this.time = time;} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package roomescape.exception; | ||
|
||
public class TimeNotFoundException extends RuntimeException { | ||
public TimeNotFoundException(String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package roomescape.repository; | ||
|
||
import org.springframework.stereotype.Repository; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import roomescape.domain.Reservation; | ||
|
||
@Repository | ||
public interface ReservationRepository extends JpaRepository<Reservation, Long> { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package roomescape.repository; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
import roomescape.domain.Time; | ||
|
||
@Repository | ||
public interface TimeRepository extends JpaRepository<Time, Long> { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package roomescape.service; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Service; | ||
import roomescape.domain.Reservation; | ||
import roomescape.domain.Time; | ||
import roomescape.exception.ReservationNotFoundException; | ||
import roomescape.exception.TimeNotFoundException; | ||
import roomescape.repository.ReservationRepository; | ||
import roomescape.repository.TimeRepository; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
public class ReservationService { | ||
@Autowired | ||
private ReservationRepository reservationRepository; | ||
|
||
@Autowired | ||
private TimeRepository timeRepository; | ||
|
||
public List<Reservation> getAllReservations() { | ||
return reservationRepository.findAll(); | ||
} | ||
|
||
public Reservation getReservationById(long id) { | ||
if(!reservationRepository.existsById(id)) { | ||
throw new ReservationNotFoundException("Reservation with id " + id + " not found"); | ||
} | ||
return reservationRepository.getReferenceById(id); | ||
} | ||
|
||
|
||
public Reservation createReservation(Reservation reservation) { | ||
Time time = reservation.getTime(); | ||
if(!timeRepository.existsById(time.getId())) { | ||
throw new TimeNotFoundException("Time with id " + time.getId() + " not found"); | ||
} | ||
reservation.setTime(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. setter를 사용하지 않아도 reservation 객체의 time 필드는 그대로 일것 같습니다. |
||
return reservationRepository.save(reservation); | ||
} | ||
|
||
public void deleteReservation(long id) { | ||
if(!reservationRepository.existsById(id)) { | ||
throw new ReservationNotFoundException("Reservation with id " + id + " not found"); | ||
} | ||
Reservation reservation = getReservationById(id); | ||
reservationRepository.delete(reservation); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package roomescape.service; | ||
|
||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.stereotype.Service; | ||
|
||
import roomescape.domain.Time; | ||
import roomescape.exception.TimeNotFoundException; | ||
import roomescape.repository.TimeRepository; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
public class TimeService { | ||
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. 서비스 계층을 나눠주셨군요? 계층을 나눴을 때의 장점은 어떤 것이 있었나요? |
||
@Autowired | ||
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. 필드 주입의 단점을 알려주세요! |
||
private TimeRepository timeRepository; | ||
|
||
public List<Time> getAllTimes() { | ||
return timeRepository.findAll(); | ||
} | ||
|
||
public Time getTimeById(long id) { | ||
if (!timeRepository.existsById(id)) { | ||
throw new TimeNotFoundException("Time with id " + id + " not found"); | ||
} | ||
return timeRepository.getReferenceById(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 createTime(Time time) { | ||
return timeRepository.save(time); | ||
} | ||
|
||
public void deleteTimeById(long id) { | ||
if (!timeRepository.existsById(id)) { | ||
throw new TimeNotFoundException("Time with id " + id + " not found"); | ||
} | ||
Time time = getTimeById(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.
|
||
timeRepository.delete(time); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
CREATE TABLE time | ||
( | ||
id BIGINT NOT NULL AUTO_INCREMENT, | ||
time VARCHAR(255) NOT NULL, | ||
PRIMARY KEY (id) | ||
); | ||
|
||
CREATE TABLE reservation | ||
( | ||
id BIGINT NOT NULL AUTO_INCREMENT, | ||
name VARCHAR(255) NOT NULL, | ||
date VARCHAR(255) NOT NULL, | ||
time_id BIGINT, | ||
PRIMARY KEY (id), | ||
FOREIGN KEY (time_id) REFERENCES time(id) | ||
); |
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.
서비스 계층을 잘 분리해주셔서 컨트롤러 로직이 깔끔해보입니다!! :+1