From cc91bc1613e0d62bbdc1a0cbdfe621b26032572a Mon Sep 17 00:00:00 2001 From: tjdtn0219 Date: Tue, 28 Nov 2023 03:55:27 +0900 Subject: [PATCH 01/20] =?UTF-8?q?Fix:=20ReservationService=20bringAccommod?= =?UTF-8?q?ation=20=EB=B3=80=EA=B2=BD=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/reservation/service/ReservationService.java | 2 +- .../controller/ReservationRoomController.java | 2 +- .../reservation_room/dto/ReservationRoomCreateRequest.java | 4 +++- .../domain/reservation/service/ReservationServiceTest.java | 3 +-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java index 5339fb7..d289dc7 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java @@ -89,7 +89,7 @@ private List reservationRoomDtosToEntityList(List> getReservationRoomsByReserv reservationRoomService.getReservationRoomsFromReservation(reservationId) ); } - + @PreAuthorize("hasRole('ROLE_USER')") @DeleteMapping public ResponseDto deleteReservationRoom( diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java index 3a01746..2eed91f 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java @@ -12,8 +12,10 @@ public record ReservationRoomCreateRequest( @NotNull Long accommodationId, - @NotNull + @NotBlank String accommodationName, + @NotBlank + String areaCode, @NotNull Long roomTypeId, diff --git a/src/test/java/ybe/mini/travelserver/domain/reservation/service/ReservationServiceTest.java b/src/test/java/ybe/mini/travelserver/domain/reservation/service/ReservationServiceTest.java index 68615ab..daee7a3 100644 --- a/src/test/java/ybe/mini/travelserver/domain/reservation/service/ReservationServiceTest.java +++ b/src/test/java/ybe/mini/travelserver/domain/reservation/service/ReservationServiceTest.java @@ -1,6 +1,5 @@ package ybe.mini.travelserver.domain.reservation.service; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -45,7 +44,7 @@ class ReservationServiceTest implements DummyObjectForRoom, DummyReservationDTO, @Test void createReservation_success() { //given - given(tourAPIService.bringAccommodation(anyLong(), any())).willReturn(dummyAccommodation()); + given(tourAPIService.bringAccommodation(any(), any())).willReturn(dummyAccommodation()); given(tourAPIService.bringRoom(anyLong(), anyLong())).willReturn(dummyRoom(dummyAccommodation())); given(roomRepository.findByRoomTypeId(any())).willReturn(Optional.empty()); given(roomRepository.save(any(Room.class))).willReturn(dummyRoom(dummyAccommodation())); From f1c31d61ae3341885eb5933b326f1618cc1ac73a Mon Sep 17 00:00:00 2001 From: tjdtn0219 Date: Tue, 28 Nov 2023 04:45:43 +0900 Subject: [PATCH 02/20] =?UTF-8?q?Cart*Reservation=20tourAPIService=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/cart/dto/request/CartCreateRequest.java | 5 +++-- .../domain/cart/service/CartService.java | 7 +++++-- .../controller/ReservationController.java | 2 +- .../reservation/service/ReservationService.java | 6 +++++- .../dto/ReservationRoomCreateRequest.java | 14 +++++++++----- src/test/http/cart.http | 7 ++++--- src/test/http/reservation.http | 14 +++++++------- 7 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java index 7f6c192..160314b 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java @@ -7,6 +7,7 @@ import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.Builder; +import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; import java.time.LocalDate; @@ -34,8 +35,8 @@ public record CartCreateRequest( @NotBlank String keyword, - @NotBlank - String areaCode + @NotNull + AreaCode areaCode ) { } \ No newline at end of file diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java index fd8ff95..3ff28a9 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java @@ -5,6 +5,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; +import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; import ybe.mini.travelserver.domain.accommodation.repository.AccommodationRepository; import ybe.mini.travelserver.domain.cart.dto.request.CartCreateRequest; import ybe.mini.travelserver.domain.cart.dto.response.CartCreateResponse; @@ -72,8 +73,10 @@ private Member getMemberById(Long id) { .orElseThrow(MemberNotFoundException::new); } - private Accommodation createAccommodationById(String keyword, String areaCode) { - Accommodation accommodation = tourAPIService.bringAccommodation(keyword, areaCode); + private Accommodation createAccommodationById(String keyword, AreaCode areaCode) { + String areaCodeString = + (areaCode != null) ? String.valueOf(areaCode.getCode()) : null; + Accommodation accommodation = tourAPIService.bringAccommodation(keyword, areaCodeString); return getOrSaveAccommodation(accommodation); } diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java b/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java index 17004ec..e18ea12 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java @@ -30,7 +30,7 @@ public class ReservationController { @PreAuthorize("hasRole('ROLE_USER')") @PostMapping public ResponseDto tryReservation ( - @RequestBody @Valid ReservationCreateRequest createRequest, + @RequestBody ReservationCreateRequest createRequest, @AuthenticationPrincipal PrincipalDetails principalDetails ) { return new ResponseDto<>( diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java index d289dc7..fefd80d 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java @@ -88,8 +88,12 @@ private List reservationRoomDtosToEntityList(List Date: Tue, 28 Nov 2023 15:08:03 +0900 Subject: [PATCH 03/20] =?UTF-8?q?Fix:=20=EB=B0=94=EB=80=8C=EC=96=B4?= =?UTF-8?q?=EC=95=BC=20=ED=95=98=EB=8A=94=20=EB=A1=9C=EC=A7=81=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/room/service/RoomServiceTest.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java b/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java index ea71f56..db451d7 100644 --- a/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java +++ b/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java @@ -29,15 +29,15 @@ class RoomServiceTest extends DummyObjectForService { @Test void bringRoom_success() { // given - given(roomRepository.findById(anyLong())) - .willReturn(Optional.of(dummyRoom(dummyAccommodation()))); - - // when - var actual = roomService.bringRoom(1L); - - // then - var expected = dummyRoomGetResponse(); - Assertions.assertEquals(expected, actual); - then(roomRepository).should().findById(anyLong()); +// given(roomRepository.findById(anyLong())) +// .willReturn(Optional.of(dummyRoom(dummyAccommodation()))); +// +// // when +// var actual = roomService.bringRoom(1L); +// +// // then +// var expected = dummyRoomGetResponse(); +// Assertions.assertEquals(expected, actual); +// then(roomRepository).should().findById(anyLong()); } } \ No newline at end of file From cf3ac2c226f62fb4a947412302035b33ca3f79ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=ED=98=84?= Date: Tue, 28 Nov 2023 15:11:34 +0900 Subject: [PATCH 04/20] =?UTF-8?q?Refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C,?= =?UTF-8?q?=20import=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/AccommodationDetailGetResponse.java | 3 -- .../repository/AccommodationRepository.java | 9 ---- .../service/AccommodationService.java | 41 ++----------------- .../room/controller/RoomController.java | 1 - .../room/repository/RoomRepository.java | 2 - .../domain/room/service/RoomService.java | 18 -------- 6 files changed, 4 insertions(+), 70 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/accommodation/dto/AccommodationDetailGetResponse.java b/src/main/java/ybe/mini/travelserver/domain/accommodation/dto/AccommodationDetailGetResponse.java index ad12281..6708b04 100644 --- a/src/main/java/ybe/mini/travelserver/domain/accommodation/dto/AccommodationDetailGetResponse.java +++ b/src/main/java/ybe/mini/travelserver/domain/accommodation/dto/AccommodationDetailGetResponse.java @@ -3,9 +3,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Builder; import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; -import ybe.mini.travelserver.domain.room.dto.RoomGetResponse; - -import java.util.List; @JsonIgnoreProperties(ignoreUnknown = true) public record AccommodationDetailGetResponse( diff --git a/src/main/java/ybe/mini/travelserver/domain/accommodation/repository/AccommodationRepository.java b/src/main/java/ybe/mini/travelserver/domain/accommodation/repository/AccommodationRepository.java index fb88a1e..8827e47 100644 --- a/src/main/java/ybe/mini/travelserver/domain/accommodation/repository/AccommodationRepository.java +++ b/src/main/java/ybe/mini/travelserver/domain/accommodation/repository/AccommodationRepository.java @@ -3,15 +3,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; -import java.util.List; - public interface AccommodationRepository extends JpaRepository { - - List findByNameContainingAndLocationAreaCode(String keyword, String areaCode); - - List findByNameContaining(String keyword); - - List findByLocationAreaCode(String areaCode); - } diff --git a/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java b/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java index aec6dc7..89758f8 100644 --- a/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java +++ b/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java @@ -2,33 +2,27 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import ybe.mini.travelserver.domain.accommodation.dto.AccommodationDetailGetResponse; import ybe.mini.travelserver.domain.accommodation.dto.AccommodationGetResponse; import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; -import ybe.mini.travelserver.domain.accommodation.repository.AccommodationRepository; import ybe.mini.travelserver.global.api.TourAPIService; import java.util.Collections; import java.util.List; -import java.util.Objects; @Service @RequiredArgsConstructor public class AccommodationService { - private final AccommodationRepository accommodationRepository; private final TourAPIService tourAPIService; public List bringAccommodations( int pageNo, int numOfRows, String keyword, AreaCode areaCode ) { - if (pageNo <= 0) { - return Collections.emptyList(); - } + if (pageNo <= 0) return Collections.emptyList(); String areaCodeString = (areaCode != null) ? String.valueOf(areaCode.getCode()) : null; @@ -39,7 +33,9 @@ public List bringAccommodations( keyword, areaCodeString); - return getResponseList(accommodations); + return accommodations.stream() + .map(AccommodationGetResponse::fromEntity) + .toList(); } public AccommodationDetailGetResponse bringAccommodationFromAPI(String keyword, AreaCode areaCode) { @@ -50,34 +46,5 @@ public AccommodationDetailGetResponse bringAccommodationFromAPI(String keyword, return AccommodationDetailGetResponse.fromEntity(accommodation); } - @Transactional(readOnly = true) - public List bringAccommodations(String keyword, String areaCode) { - List accommodations; - - if (!Objects.isNull(keyword) && !Objects.isNull(areaCode)) { - accommodations = accommodationRepository.findByNameContainingAndLocationAreaCode(keyword, areaCode); - } else if (!Objects.isNull(keyword)) { - accommodations = accommodationRepository.findByNameContaining(keyword); - } else if (!Objects.isNull(areaCode)) { - accommodations = accommodationRepository.findByLocationAreaCode(areaCode); - } else { - accommodations = accommodationRepository.findAll(); - } - - return getResponseList(accommodations); - } - - - private Accommodation bringAccommodation(Long accommodationId) { - return accommodationRepository - .findById(accommodationId).orElseThrow(RuntimeException::new); - } - - private static List getResponseList(List accommodations) { - return accommodations.stream() - .map(AccommodationGetResponse::fromEntity) - .toList(); - } - } diff --git a/src/main/java/ybe/mini/travelserver/domain/room/controller/RoomController.java b/src/main/java/ybe/mini/travelserver/domain/room/controller/RoomController.java index 341fa17..685a80d 100644 --- a/src/main/java/ybe/mini/travelserver/domain/room/controller/RoomController.java +++ b/src/main/java/ybe/mini/travelserver/domain/room/controller/RoomController.java @@ -6,7 +6,6 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import ybe.mini.travelserver.domain.room.dto.RoomGetResponse; import ybe.mini.travelserver.domain.room.dto.RoomGetResponseFromAPI; import ybe.mini.travelserver.domain.room.service.RoomService; import ybe.mini.travelserver.global.common.ResponseDto; diff --git a/src/main/java/ybe/mini/travelserver/domain/room/repository/RoomRepository.java b/src/main/java/ybe/mini/travelserver/domain/room/repository/RoomRepository.java index 11b641e..345ee45 100644 --- a/src/main/java/ybe/mini/travelserver/domain/room/repository/RoomRepository.java +++ b/src/main/java/ybe/mini/travelserver/domain/room/repository/RoomRepository.java @@ -3,12 +3,10 @@ import org.springframework.data.jpa.repository.JpaRepository; import ybe.mini.travelserver.domain.room.entity.Room; -import java.util.List; import java.util.Optional; public interface RoomRepository extends JpaRepository { - List findByAccommodationId(Long accommodationId); Optional findByRoomTypeId(Long roomTypeId); } diff --git a/src/main/java/ybe/mini/travelserver/domain/room/service/RoomService.java b/src/main/java/ybe/mini/travelserver/domain/room/service/RoomService.java index adc4cc8..1450373 100644 --- a/src/main/java/ybe/mini/travelserver/domain/room/service/RoomService.java +++ b/src/main/java/ybe/mini/travelserver/domain/room/service/RoomService.java @@ -2,11 +2,8 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import ybe.mini.travelserver.domain.room.dto.RoomGetResponse; import ybe.mini.travelserver.domain.room.dto.RoomGetResponseFromAPI; import ybe.mini.travelserver.domain.room.entity.Room; -import ybe.mini.travelserver.domain.room.repository.RoomRepository; import ybe.mini.travelserver.global.api.TourAPIService; import java.util.List; @@ -15,17 +12,8 @@ @RequiredArgsConstructor public class RoomService { - private final RoomRepository roomRepository; private final TourAPIService tourAPIService; - @Transactional(readOnly = true) - public List bringRooms(Long accommodationId) { - return roomRepository.findByAccommodationId(accommodationId) - .stream() - .map(RoomGetResponse::fromEntity) - .toList(); - } - public List bringRoomsFromAPI(Long accommodationId) { List rooms = tourAPIService.bringRooms(accommodationId); return rooms.stream() @@ -33,10 +21,4 @@ public List bringRoomsFromAPI(Long accommodationId) { .toList(); } - @Transactional(readOnly = true) - public RoomGetResponse bringRoom(Long roomId) { - Room room = roomRepository.findById(roomId).orElseThrow(RuntimeException::new); - return RoomGetResponse.fromEntity(room); - } - } From c95751ce31e4d148a3cd21e8382d0492398caf94 Mon Sep 17 00:00:00 2001 From: minjung Date: Tue, 28 Nov 2023 16:42:53 +0900 Subject: [PATCH 05/20] =?UTF-8?q?Fix:=20delete=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C,=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cart/controller/CartController.java | 2 +- .../cart/exception/CartErrorMessage.java | 3 +-- .../cart/exception/CartExceptionHandler.java | 5 ---- .../exception/CartInvalidMemberException.java | 4 --- .../cart/repository/CartRepository.java | 3 ++- .../domain/cart/service/CartService.java | 27 +++++++------------ src/test/http/cart.http | 10 ++++--- 7 files changed, 19 insertions(+), 35 deletions(-) delete mode 100644 src/main/java/ybe/mini/travelserver/domain/cart/exception/CartInvalidMemberException.java diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/controller/CartController.java b/src/main/java/ybe/mini/travelserver/domain/cart/controller/CartController.java index e0399a6..9184401 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/controller/CartController.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/controller/CartController.java @@ -53,7 +53,7 @@ public ResponseDto deleteCart( @AuthenticationPrincipal PrincipalDetails principalDetails, @PathVariable Long cartId) { CartDeleteResponse cartDeleteResponse = - cartService.deleteCart(principalDetails.getMemberId(), cartId); + cartService.deleteCart(cartId); return new ResponseDto<>(HttpStatus.OK.value(), cartDeleteResponse); } } \ No newline at end of file diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartErrorMessage.java b/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartErrorMessage.java index 092e557..51acc37 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartErrorMessage.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartErrorMessage.java @@ -9,8 +9,7 @@ @AllArgsConstructor public enum CartErrorMessage implements ErrorMessage { - CART_INVALID_MEMBER(BAD_REQUEST, "해당 ID가 유효하지 않습니다."), - CART_ALREADY_EXIST(BAD_REQUEST, "해당 정보가 장바구니에 담겨있습니다."), + CART_ALREADY_EXIST(BAD_REQUEST, "해당 정보가 이미 장바구니에 담겨있습니다."), CART_NOT_FOUND(BAD_REQUEST, "해당 ID의 장바구니 정보가 없습니다.") ; diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartExceptionHandler.java b/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartExceptionHandler.java index ce7604d..63dc2a3 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartExceptionHandler.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartExceptionHandler.java @@ -21,11 +21,6 @@ public ProblemDetail handelCartNotFoundException(HttpServletRequest request) { return createProblemDetail(CART_NOT_FOUND, request); } - @ExceptionHandler(CartInvalidMemberException.class) - public ProblemDetail handelCartInvalidMemberException(HttpServletRequest request) { - return createProblemDetail(CART_INVALID_MEMBER, request); - } - @ExceptionHandler(CartAleadyExistException.class) public ProblemDetail handelCartAleadyExistException(HttpServletRequest request) { return createProblemDetail(CART_ALREADY_EXIST, request); diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartInvalidMemberException.java b/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartInvalidMemberException.java deleted file mode 100644 index 86b63d3..0000000 --- a/src/main/java/ybe/mini/travelserver/domain/cart/exception/CartInvalidMemberException.java +++ /dev/null @@ -1,4 +0,0 @@ -package ybe.mini.travelserver.domain.cart.exception; - -public class CartInvalidMemberException extends RuntimeException { -} diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/repository/CartRepository.java b/src/main/java/ybe/mini/travelserver/domain/cart/repository/CartRepository.java index b8ca134..57b945a 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/repository/CartRepository.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/repository/CartRepository.java @@ -4,8 +4,9 @@ import ybe.mini.travelserver.domain.cart.entity.Cart; import java.util.List; +import java.util.Optional; + public interface CartRepository extends JpaRepository { List findALLByMemberId(Long userId); - List deleteAllByMemberId(Long userId); } diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java index c5079fc..98f2885 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java @@ -12,7 +12,6 @@ import ybe.mini.travelserver.domain.cart.dto.response.CartDeleteResponse; import ybe.mini.travelserver.domain.cart.dto.response.CartGetResponse; import ybe.mini.travelserver.domain.cart.entity.Cart; -import ybe.mini.travelserver.domain.cart.exception.CartInvalidMemberException; import ybe.mini.travelserver.domain.cart.exception.CartNotFoundException; import ybe.mini.travelserver.domain.cart.repository.CartRepository; import ybe.mini.travelserver.domain.member.entity.Member; @@ -38,9 +37,9 @@ public class CartService { @Transactional public CartCreateResponse createCart(Long userId, CartCreateRequest cartCreateRequest) { Member member = getMemberById(userId); - createAccommodationById(cartCreateRequest.keyword(), cartCreateRequest.areaCode()); - Room room = createRoomById( - cartCreateRequest.accommodationId(), cartCreateRequest.roomTypeId()); + Accommodation accommodation = + createAccommodationById(cartCreateRequest.keyword(), cartCreateRequest.areaCode()); + Room room = createRoomById(accommodation, cartCreateRequest.roomTypeId()); Cart cart = createCart(cartCreateRequest, room, member); Cart createdCart = cartRepository.save(cart); @@ -57,15 +56,11 @@ public List getMyCarts(Long userId) { } @Transactional - public CartDeleteResponse deleteCart(Long memberId, Long cartId) { - Cart cart = cartRepository.findById(cartId) + public CartDeleteResponse deleteCart(Long cartId) { + cartRepository.findById(cartId) .orElseThrow(CartNotFoundException::new); - if (cart.getMember().getId() == memberId) { - cartRepository.deleteById(cartId); - return new CartDeleteResponse(cartId); - } else { - throw new CartInvalidMemberException(); - } + cartRepository.deleteById(cartId); + return new CartDeleteResponse(cartId); } private Member getMemberById(Long id) { @@ -80,16 +75,12 @@ private Accommodation createAccommodationById(String keyword, AreaCode areaCode) return getOrSaveAccommodation(accommodation); } - private Room createRoomById(Long accommodationId, Long roomId) { - Room room = tourAPIService.bringRoom(accommodationId, roomId); + private Room createRoomById(Accommodation accommodation, Long roomId) { + Room room = tourAPIService.bringRoom(accommodation.getId(), roomId); return getOrSaveRoom(room); } private Cart createCart(CartCreateRequest cartCreateRequest, Room room, Member member) { - // TODO : 성수님 roomId 관련 논의 - roomRepository.findById(room.getId()) - .orElseThrow(CartInvalidMemberException::new); - return Cart.builder() .guestNumber(cartCreateRequest.guestNumber()) .room(room) diff --git a/src/test/http/cart.http b/src/test/http/cart.http index 8ae82ad..4562875 100644 --- a/src/test/http/cart.http +++ b/src/test/http/cart.http @@ -1,15 +1,15 @@ ### 조회 GET http://localhost:8080/carts -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMDY2NjE5LCJleHAiOjE3MDEwNjg0MTksImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJHdpZjd6bWlYUGY3TkNUQ3ZvNlM4ZC5NdG5VMHZNenJRUVBjN1piblpZN2IvN3FQaVo4T1BpIiwibmFtZSI6Im9ramFlb29rIn0.EMCgqXHBobPLQbZ9yL4zFWbf6TwzGQ9PJvxmCw7QnD8 +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2MTc1LCJleHAiOjE3MDExNTc5NzUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.H1zc1zTN0tYJRUs2yttk1kGvJ23iT5IMb2jluECr95k ### 삭제 DELETE http://localhost:8080/carts/4 -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMDY2NzQyLCJleHAiOjE3MDEwNjg1NDIsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJHdpZjd6bWlYUGY3TkNUQ3ZvNlM4ZC5NdG5VMHZNenJRUVBjN1piblpZN2IvN3FQaVo4T1BpIiwibmFtZSI6Im9ramFlb29rIn0.Gwmp4rbynlp2nJNCfTcyJA5AzCVmnD_4LkXS84FvEGg +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2MTc1LCJleHAiOjE3MDExNTc5NzUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.H1zc1zTN0tYJRUs2yttk1kGvJ23iT5IMb2jluECr95k ### 생성 POST http://localhost:8080/carts -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTE2MTk4LCJleHAiOjE3MDExMTc5OTgsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJGRWc3JDenZCWVdWdU5XWm5WN3d3QWVra3E5RUJWZ0t1anpxT28ucmZBU05FZEswZkd5QzVlIiwibmFtZSI6Im9ramFlb29rIn0.PUhHIiJF_XQ1vCcZW1LVXQLLJGkx_HAYKTYinAtH84c +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2MTc1LCJleHAiOjE3MDExNTc5NzUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.H1zc1zTN0tYJRUs2yttk1kGvJ23iT5IMb2jluECr95k Content-Type: application/json { @@ -17,5 +17,7 @@ Content-Type: application/json "accommodationId": 142785, "guestNumber": 1, "checkIn": "2023-11-20", - "checkOut": "2023-11-21" + "checkOut": "2023-11-21", + "keyword": "가락관광호텔", + "areaCode": "SEOUL" } \ No newline at end of file From 7b5a6967ecb9d58435564f147ce2b2e94a85e8db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=ED=98=84?= Date: Tue, 28 Nov 2023 16:43:08 +0900 Subject: [PATCH 06/20] =?UTF-8?q?Test:=20RoomController=EC=99=80=20RoomSer?= =?UTF-8?q?vice=EC=9D=98=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C=20=EB=B0=8F=20=EB=B0=94?= =?UTF-8?q?=EB=80=90=20=EB=A1=9C=EC=A7=81=20=EB=B0=98=EC=98=81=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...> DummyObjectForControllerAndService.java} | 16 +++++- .../domain/room/DummyObjectForRepository.java | 36 ------------ .../domain/room/DummyObjectForService.java | 36 ------------ .../room/controller/RoomControllerTest.java | 56 ++++++++++++++++++ .../room/repository/RoomRepositoryTest.java | 57 ------------------- .../domain/room/service/RoomServiceTest.java | 55 +++++++++++------- 6 files changed, 105 insertions(+), 151 deletions(-) rename src/test/java/ybe/mini/travelserver/domain/room/{DummyObjectForController.java => DummyObjectForControllerAndService.java} (72%) delete mode 100644 src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForRepository.java delete mode 100644 src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForService.java create mode 100644 src/test/java/ybe/mini/travelserver/domain/room/controller/RoomControllerTest.java delete mode 100644 src/test/java/ybe/mini/travelserver/domain/room/repository/RoomRepositoryTest.java diff --git a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForController.java b/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForControllerAndService.java similarity index 72% rename from src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForController.java rename to src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForControllerAndService.java index 799460d..35282ea 100644 --- a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForController.java +++ b/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForControllerAndService.java @@ -4,7 +4,7 @@ import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; import ybe.mini.travelserver.domain.room.entity.Room; -public class DummyObjectForController implements DummyObjectForRoom{ +public class DummyObjectForControllerAndService implements DummyObjectForRoom{ public Room dummyRoom(Accommodation accommodation) { return Room.builder() @@ -19,8 +19,22 @@ public Room dummyRoom(Accommodation accommodation) { .build(); } + public Room dummyRoom1(Accommodation accommodation) { + return Room.builder() + .capacity(4) + .description("객실 설명 2") + .image("이미지 2") + .name("객실 이름 2") + .price(85000) + .roomTypeId(2L) + .stock(20) + .accommodation(accommodation) + .build(); + } + public Accommodation dummyAccommodation() { return Accommodation.builder() + .id(1L) .name("세인트존스 호텔") .location(Location.builder() .address("강원특별자치도 강릉시 창해로 307 ") diff --git a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForRepository.java b/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForRepository.java deleted file mode 100644 index e786008..0000000 --- a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForRepository.java +++ /dev/null @@ -1,36 +0,0 @@ -package ybe.mini.travelserver.domain.room; - -import ybe.mini.travelserver.domain.accommodation.entity.Location; -import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; -import ybe.mini.travelserver.domain.room.entity.Room; - -public class DummyObjectForRepository implements DummyObjectForRoom{ - - public Room dummyRoom(Accommodation accommodation) { - return Room.builder() - .capacity(2) - .description("객실 설명 1") - .image("이미지 1") - .name("객실 이름 1") - .price(100000) - .roomTypeId(1L) - .stock(50) - .accommodation(accommodation) - .build(); - } - - public Accommodation dummyAccommodation() { - return Accommodation.builder() - .name("세인트존스 호텔") - .location(Location.builder() - .address("강원특별자치도 강릉시 창해로 307 ") - .phone("033-660-9000") - .areaCode("32") - .latitude(37.7940780970) - .longitude(128.9186301059) - .build()) - .image("http://tong.visitkorea.or.kr/cms/resource/54/2603354_image2_1.jpg") - .description("푸른 해송숲과 청정 바다가 펼쳐진 강문해변에서의 자연 휴양과...") - .build(); - } -} diff --git a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForService.java b/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForService.java deleted file mode 100644 index a3f1e30..0000000 --- a/src/test/java/ybe/mini/travelserver/domain/room/DummyObjectForService.java +++ /dev/null @@ -1,36 +0,0 @@ -package ybe.mini.travelserver.domain.room; - -import ybe.mini.travelserver.domain.accommodation.entity.Location; -import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; -import ybe.mini.travelserver.domain.room.entity.Room; - -public class DummyObjectForService implements DummyObjectForRoom { - - public Room dummyRoom(Accommodation accommodation) { - return Room.builder() - .capacity(2) - .description("객실 설명 1") - .image("이미지 1") - .name("객실 이름 1") - .price(100000) - .roomTypeId(1L) - .stock(50) - .accommodation(accommodation) - .build(); - } - - public Accommodation dummyAccommodation() { - return Accommodation.builder() - .name("세인트존스 호텔") - .location(Location.builder() - .address("강원특별자치도 강릉시 창해로 307 ") - .phone("033-660-9000") - .areaCode("32") - .latitude(37.7940780970) - .longitude(128.9186301059) - .build()) - .image("http://tong.visitkorea.or.kr/cms/resource/54/2603354_image2_1.jpg") - .description("푸른 해송숲과 청정 바다가 펼쳐진 강문해변에서의 자연 휴양과...") - .build(); - } -} diff --git a/src/test/java/ybe/mini/travelserver/domain/room/controller/RoomControllerTest.java b/src/test/java/ybe/mini/travelserver/domain/room/controller/RoomControllerTest.java new file mode 100644 index 0000000..e342d11 --- /dev/null +++ b/src/test/java/ybe/mini/travelserver/domain/room/controller/RoomControllerTest.java @@ -0,0 +1,56 @@ +package ybe.mini.travelserver.domain.room.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; +import ybe.mini.travelserver.domain.room.DummyObjectForControllerAndService; +import ybe.mini.travelserver.domain.room.dto.RoomGetResponseFromAPI; +import ybe.mini.travelserver.domain.room.service.RoomService; +import ybe.mini.travelserver.global.common.ResponseDto; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; + +@ExtendWith(MockitoExtension.class) +public class RoomControllerTest extends DummyObjectForControllerAndService { + + @Mock + private RoomService roomService; + + @InjectMocks + private RoomController roomController; + + @DisplayName("객실 리스트 조회 - Controller 테스트") + @Test + void getRooms_success() { + // given + Accommodation accommodation = dummyAccommodation(); + List expectedRooms = Arrays.asList( + RoomGetResponseFromAPI.fromEntity(dummyRoom(accommodation)), + RoomGetResponseFromAPI.fromEntity(dummyRoom1(accommodation)) + ); + given(roomService.bringRoomsFromAPI(accommodation.getId())).willReturn(expectedRooms); + + + // when + ResponseDto> responseDto = + roomController.getRooms(accommodation.getId()); + + // then + assertNotNull(responseDto); + assertEquals(HttpStatus.OK.value(), responseDto.status()); + assertEquals(expectedRooms, responseDto.data()); + then(roomService).should().bringRoomsFromAPI(accommodation.getId()); + } + +} diff --git a/src/test/java/ybe/mini/travelserver/domain/room/repository/RoomRepositoryTest.java b/src/test/java/ybe/mini/travelserver/domain/room/repository/RoomRepositoryTest.java deleted file mode 100644 index 41dae38..0000000 --- a/src/test/java/ybe/mini/travelserver/domain/room/repository/RoomRepositoryTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package ybe.mini.travelserver.domain.room.repository; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; -import ybe.mini.travelserver.domain.room.DummyObjectForRepository; -import ybe.mini.travelserver.domain.room.entity.Room; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.BDDMockito.given; -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.times; - -@ExtendWith(MockitoExtension.class) -class RoomRepositoryTest extends DummyObjectForRepository { - - @Mock - RoomRepository roomRepository; - - @DisplayName("객실 단건 조회") - @Test - void findById_success() { - // given - Long roomId = 1L; - Room expectedRoom = dummyRoom(dummyAccommodation()); - - // when - given(roomRepository.findById(roomId)).willReturn(Optional.of(expectedRoom)); - Optional actualRoom = roomRepository.findById(roomId); - - // then - assertTrue(actualRoom.isPresent()); - Room actual = actualRoom.get(); - assertEquals(expectedRoom, actual); - then(roomRepository).should(times(1)).findById(roomId); - } - - @DisplayName("객실 단건 조회 - 존재하지 않는 경우") - @Test - void findById_notFound() { - // given - Long roomId = 2L; - - // when - given(roomRepository.findById(roomId)).willReturn(Optional.empty()); - Optional actualRoom = roomRepository.findById(roomId); - - // then - assertTrue(actualRoom.isEmpty()); - then(roomRepository).should().findById(roomId); - } -} \ No newline at end of file diff --git a/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java b/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java index db451d7..d1ffb04 100644 --- a/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java +++ b/src/test/java/ybe/mini/travelserver/domain/room/service/RoomServiceTest.java @@ -1,43 +1,56 @@ package ybe.mini.travelserver.domain.room.service; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import ybe.mini.travelserver.domain.room.DummyObjectForService; -import ybe.mini.travelserver.domain.room.repository.RoomRepository; +import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; +import ybe.mini.travelserver.domain.room.DummyObjectForControllerAndService; +import ybe.mini.travelserver.domain.room.dto.RoomGetResponseFromAPI; +import ybe.mini.travelserver.domain.room.entity.Room; +import ybe.mini.travelserver.global.api.TourAPIService; +import java.util.Arrays; import java.util.List; -import java.util.Optional; -import static org.mockito.ArgumentMatchers.anyLong; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.then; @ExtendWith(MockitoExtension.class) -class RoomServiceTest extends DummyObjectForService { +class RoomServiceTest extends DummyObjectForControllerAndService { - @InjectMocks - RoomService roomService; @Mock - RoomRepository roomRepository; + private TourAPIService tourAPIService; + + @InjectMocks + private RoomService roomService; - @DisplayName("객실 상세 조회") + @DisplayName("객실 리스트 조회 - Service 테스트") @Test - void bringRoom_success() { + void getRooms_success() { // given -// given(roomRepository.findById(anyLong())) -// .willReturn(Optional.of(dummyRoom(dummyAccommodation()))); -// -// // when -// var actual = roomService.bringRoom(1L); -// -// // then -// var expected = dummyRoomGetResponse(); -// Assertions.assertEquals(expected, actual); -// then(roomRepository).should().findById(anyLong()); + Accommodation accommodation = dummyAccommodation(); + List expectedRooms = Arrays.asList( + dummyRoom(accommodation), dummyRoom1(accommodation) + ); + List responseDto = expectedRooms.stream() + .map(RoomGetResponseFromAPI::fromEntity) + .toList(); + given(tourAPIService.bringRooms(eq(accommodation.getId()))).willReturn(expectedRooms); + + // when + List actualRooms = roomService.bringRoomsFromAPI(accommodation.getId()); + + // then + assertNotNull(actualRooms); + assertEquals(responseDto.size(), actualRooms.size()); + assertEquals(responseDto, actualRooms); + then(tourAPIService).should().bringRooms(eq(accommodation.getId())); + } } \ No newline at end of file From 08619eaf92a869741d82d99ed3b3a2349daa8771 Mon Sep 17 00:00:00 2001 From: tjdtn0219 Date: Tue, 28 Nov 2023 16:52:41 +0900 Subject: [PATCH 07/20] =?UTF-8?q?Fix:=20ReservationRoomDTO=20=EC=8B=9C?= =?UTF-8?q?=EA=B0=84=20=EA=B2=80=EC=A6=9D=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ReservationController.java | 7 ++++--- .../exception/ReservationErrorMessage.java | 1 - .../exception/ReservationExceptionHandler.java | 7 ------- .../controller/ReservationRoomController.java | 8 +++++--- .../dto/ReservationRoomCreateRequest.java | 14 ++++++++------ .../global/exception/dto/DTOErrorMessage.java | 1 + .../global/exception/dto/DTOExceptionHandler.java | 8 ++++++++ src/main/resources/application-dev.yml | 2 +- src/test/http/reservation.http | 6 +++--- 9 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java b/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java index 17004ec..b6d4f7c 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/controller/ReservationController.java @@ -17,6 +17,7 @@ import java.util.List; +import static ybe.mini.travelserver.global.security.Role.HAS_ROLE_USER; import static ybe.mini.travelserver.global.security.Role.ROLE_USER; @Slf4j @@ -27,7 +28,7 @@ public class ReservationController { private final ReservationService reservationService; - @PreAuthorize("hasRole('ROLE_USER')") + @PreAuthorize(HAS_ROLE_USER) @PostMapping public ResponseDto tryReservation ( @RequestBody @Valid ReservationCreateRequest createRequest, @@ -39,7 +40,7 @@ public ResponseDto tryReservation ( ); } - @PreAuthorize("hasRole('ROLE_USER')") + @PreAuthorize(HAS_ROLE_USER) @PostMapping("/from-cart") public ResponseDto tryReservationFromCart ( @RequestBody @Valid ReservationCreateFromCartRequest createRequest, @@ -51,7 +52,7 @@ public ResponseDto tryReservationFromCart ( ); } - @PreAuthorize("hasRole('ROLE_USER')") + @PreAuthorize(HAS_ROLE_USER) @GetMapping public ResponseDto> getMyReservations ( @AuthenticationPrincipal PrincipalDetails principalDetails diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationErrorMessage.java b/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationErrorMessage.java index c6aa6b3..5fb25a2 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationErrorMessage.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationErrorMessage.java @@ -11,7 +11,6 @@ @AllArgsConstructor public enum ReservationErrorMessage implements ErrorMessage { - HTTP_MESSAGE_NOT_READABLE(BAD_REQUEST, "DTO 양식이 맞지 않습니다."), RESERVATION_NOT_FOUND(BAD_REQUEST, "해당 ID의 예약 정보가 없습니다.") ; private final HttpStatus status; diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationExceptionHandler.java b/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationExceptionHandler.java index 7aaf454..c95ad9f 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationExceptionHandler.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/exception/ReservationExceptionHandler.java @@ -2,12 +2,10 @@ import jakarta.servlet.http.HttpServletRequest; import org.springframework.http.ProblemDetail; -import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import ybe.mini.travelserver.global.exception.ProblemDetailCreator; -import static ybe.mini.travelserver.domain.reservation.exception.ReservationErrorMessage.HTTP_MESSAGE_NOT_READABLE; import static ybe.mini.travelserver.domain.reservation.exception.ReservationErrorMessage.RESERVATION_NOT_FOUND; @RestControllerAdvice @@ -17,11 +15,6 @@ protected ReservationExceptionHandler() { super("예약 처리 실패"); } - @ExceptionHandler(HttpMessageNotReadableException.class) - public ProblemDetail handleHttpMessageNotReadableException(HttpServletRequest request) { - return createProblemDetail(HTTP_MESSAGE_NOT_READABLE, request); //todo : Global로 분리할지 논의 - } - @ExceptionHandler(ReservationNotFoundException.class) public ProblemDetail handleReservationNotFoundException(HttpServletRequest request) { return createProblemDetail(RESERVATION_NOT_FOUND, request); diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/controller/ReservationRoomController.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/controller/ReservationRoomController.java index 8433b4a..d90bec6 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/controller/ReservationRoomController.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/controller/ReservationRoomController.java @@ -11,6 +11,8 @@ import java.util.List; +import static ybe.mini.travelserver.global.security.Role.HAS_ROLE_USER; + @Slf4j @RequestMapping("/reservation-rooms") @RestController @@ -19,7 +21,7 @@ public class ReservationRoomController { private final ReservationRoomService reservationRoomService; - @PreAuthorize("hasRole('ROLE_USER')") + @PreAuthorize(HAS_ROLE_USER) @GetMapping("/{reservationId}") public ResponseDto> getReservationRoomsByReserveId( @PathVariable Long reservationId @@ -30,8 +32,8 @@ public ResponseDto> getReservationRoomsByReserv reservationRoomService.getReservationRoomsFromReservation(reservationId) ); } - - @PreAuthorize("hasRole('ROLE_USER')") + + @PreAuthorize(HAS_ROLE_USER) @DeleteMapping public ResponseDto deleteReservationRoom( @RequestParam Long reservationId, diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java index 36a96b3..84b39c2 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java @@ -1,8 +1,11 @@ package ybe.mini.travelserver.domain.reservation_room.dto; -import com.fasterxml.jackson.annotation.JsonFormat; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.FutureOrPresent; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import lombok.Builder; +import org.springframework.format.annotation.DateTimeFormat; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; import java.io.Serializable; @@ -20,14 +23,13 @@ public record ReservationRoomCreateRequest( @NotNull(message = "roomTypeId 양식이 잘못 입력되었습니다.") Long roomTypeId, - @NotNull + @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm") + @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDateTime checkIn, - @NotNull @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm") + @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDateTime checkOut, @NotNull @Min(value = 1, message = "숙박 인원은 최소 1명 이어야 합니다.") diff --git a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java index 1252edd..fd0ae40 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java @@ -11,6 +11,7 @@ @AllArgsConstructor public enum DTOErrorMessage implements ErrorMessage { METHOD_ARGUMENT_NOT_VALID(BAD_REQUEST, "DTO 값이 유효하지 않습니다"), + DATETIME_PARSE(BAD_REQUEST, "날짜 형식이 유효하지 않습니다"), ; private final HttpStatus status; diff --git a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java index a695e5a..4091267 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java @@ -7,8 +7,10 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import ybe.mini.travelserver.global.exception.ProblemDetailCreator; +import java.time.format.DateTimeParseException; import java.util.Objects; +import static ybe.mini.travelserver.global.exception.dto.DTOErrorMessage.DATETIME_PARSE; import static ybe.mini.travelserver.global.exception.dto.DTOErrorMessage.METHOD_ARGUMENT_NOT_VALID; @RestControllerAdvice @@ -26,4 +28,10 @@ public ProblemDetail handleMethodArgumentNotValidException( return createProblemDetail(errorMessage, METHOD_ARGUMENT_NOT_VALID.getStatus().value(), request); } + @ExceptionHandler(DateTimeParseException.class) + public ProblemDetail handleDateTimeParseException( + HttpServletRequest request + ) { + return createProblemDetail(DATETIME_PARSE, request); + } } \ No newline at end of file diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 8d6e62e..f18a0b4 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -21,7 +21,7 @@ spring: jpa: show-sql: true hibernate: - ddl-auto: create + ddl-auto: update properties: hibernate: format_sql: true diff --git a/src/test/http/reservation.http b/src/test/http/reservation.http index 94e3eb7..987051c 100644 --- a/src/test/http/reservation.http +++ b/src/test/http/reservation.http @@ -1,7 +1,7 @@ ### 예약 생성 POST http://localhost:8080/reservations Content-Type: application/json -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTE2MTk4LCJleHAiOjE3MDExMTc5OTgsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJGRWc3JDenZCWVdWdU5XWm5WN3d3QWVra3E5RUJWZ0t1anpxT28ucmZBU05FZEswZkd5QzVlIiwibmFtZSI6Im9ramFlb29rIn0.PUhHIiJF_XQ1vCcZW1LVXQLLJGkx_HAYKTYinAtH84c +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2NTc2LCJleHAiOjE3MDExNTgzNzYsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJFNCbjZSQ3ZQdFQ2WW1vSVM0ZzU1dE8xTFBwRDJkSjJLbDBKcDRXT3k5RmhuNzNxdnNJQS51IiwibmFtZSI6Im9ramFlb29rIn0.HCiMHNhtW45GEFH2tbkihaeiqADBmehLfg2iGlIDuCE { "paymentType": "CARD", @@ -11,8 +11,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0I "accommodationName": "가락관광호텔", "areaCode": "SEOUL", "roomTypeId": 11430, - "checkIn": "2024-01-01 14:00", - "checkOut": "2024-01-02 11:00", + "checkIn": "2024-01-01T00:00", + "checkOut": "2024-01-03T00:00", "guestNumber": 2 } ] From 5e64b9b80a7fa0a88ca3a55bfeb01b56cd85759a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=ED=98=84?= Date: Tue, 28 Nov 2023 17:20:00 +0900 Subject: [PATCH 08/20] =?UTF-8?q?Fix:=20=EB=A9=94=EC=86=8C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accommodation/controller/AccommodationController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationController.java b/src/main/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationController.java index 1a0b7d4..7d6d623 100644 --- a/src/main/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationController.java +++ b/src/main/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationController.java @@ -31,7 +31,7 @@ public ResponseDto> searchAccommodations( } @GetMapping - public ResponseDto searchAccommodations( + public ResponseDto searchAccommodation( @RequestParam String keyword, @RequestParam(value = "area-code") AreaCode areaCode ) { From e9c0f7c378158f55e2b7dbbc1e7c5ab15bc8f6eb Mon Sep 17 00:00:00 2001 From: minjung Date: Tue, 28 Nov 2023 17:27:47 +0900 Subject: [PATCH 09/20] =?UTF-8?q?Fix:=20createRequest=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EC=9D=B8=20=EC=B2=B4=ED=81=AC=EC=95=84=EC=9B=83=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=ED=8F=AC=EB=A7=B7=20=EB=B3=80=EA=B2=BD=20(yy?= =?UTF-8?q?yy-mm-dd)->(yyyymmdd)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/cart/dto/request/CartCreateRequest.java | 4 ++-- src/test/http/cart.http | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java index af2056f..cba171e 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java @@ -19,11 +19,11 @@ public record CartCreateRequest( Long roomTypeId, @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd") LocalDate checkIn, @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd") LocalDate checkOut, @Positive diff --git a/src/test/http/cart.http b/src/test/http/cart.http index 4562875..73e84dd 100644 --- a/src/test/http/cart.http +++ b/src/test/http/cart.http @@ -1,6 +1,6 @@ ### 조회 GET http://localhost:8080/carts -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2MTc1LCJleHAiOjE3MDExNTc5NzUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.H1zc1zTN0tYJRUs2yttk1kGvJ23iT5IMb2jluECr95k +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU5NjI1LCJleHAiOjE3MDExNjE0MjUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.TVvMcujy3_EQDJQcg0CXFVeQpJ5_rF0V83tvcs84dx4 ### 삭제 DELETE http://localhost:8080/carts/4 @@ -9,15 +9,15 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0I ### 생성 POST http://localhost:8080/carts -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU2MTc1LCJleHAiOjE3MDExNTc5NzUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.H1zc1zTN0tYJRUs2yttk1kGvJ23iT5IMb2jluECr95k +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzAxMTU5NjI1LCJleHAiOjE3MDExNjE0MjUsImVtYWlsIjoib2tqYWVvb2s5OEBnbWFpbC5jb20iLCJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJElPdlVoOFJqdHRxMTRaSjhSYVBqUnVoN2FKa1ZDQVdMSHguSTl6UFJCbjl6dkZHOVg1Ykt1IiwibmFtZSI6Im9ramFlb29rIn0.TVvMcujy3_EQDJQcg0CXFVeQpJ5_rF0V83tvcs84dx4 Content-Type: application/json { "roomTypeId": 11430, "accommodationId": 142785, "guestNumber": 1, - "checkIn": "2023-11-20", - "checkOut": "2023-11-21", + "checkIn": "20231120", + "checkOut": "20231123", "keyword": "가락관광호텔", "areaCode": "SEOUL" } \ No newline at end of file From c3bfad77927dfb4e4670833b4af5cc925e5ece10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=ED=98=84?= Date: Tue, 28 Nov 2023 18:05:45 +0900 Subject: [PATCH 10/20] =?UTF-8?q?Test:=20=EC=88=99=EC=86=8C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../accommodation/DummyAccommodation.java | 17 +++- .../AccommodationControllerTest.java | 75 ++++++++++++++++++ .../service/AccommodationServiceTest.java | 79 +++++++++++++++++++ 3 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/test/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationControllerTest.java create mode 100644 src/test/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationServiceTest.java diff --git a/src/test/java/ybe/mini/travelserver/domain/accommodation/DummyAccommodation.java b/src/test/java/ybe/mini/travelserver/domain/accommodation/DummyAccommodation.java index 7d2a76f..7daeda8 100644 --- a/src/test/java/ybe/mini/travelserver/domain/accommodation/DummyAccommodation.java +++ b/src/test/java/ybe/mini/travelserver/domain/accommodation/DummyAccommodation.java @@ -1,6 +1,5 @@ package ybe.mini.travelserver.domain.accommodation; -import ybe.mini.travelserver.domain.accommodation.dto.AccommodationGetResponse; import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; import ybe.mini.travelserver.domain.accommodation.entity.Location; @@ -20,7 +19,19 @@ protected Accommodation dummyAccommodation() { .build(); } - protected AccommodationGetResponse dummyAccommodationGetResponse() { - return AccommodationGetResponse.fromEntity(dummyAccommodation()); + protected Accommodation dummyAccommodation1() { + return Accommodation.builder() + .name("숙소 이름") + .location(Location.builder() + .address("숙소 주소") + .phone("숙소 전화번호") + .areaCode("지역 코드") + .latitude(36.57454563) + .longitude(127.645468423) + .build()) + .image("이미지 URL") + .description("숙소 상세 설명") + .build(); } + } diff --git a/src/test/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationControllerTest.java b/src/test/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationControllerTest.java new file mode 100644 index 0000000..9790934 --- /dev/null +++ b/src/test/java/ybe/mini/travelserver/domain/accommodation/controller/AccommodationControllerTest.java @@ -0,0 +1,75 @@ +package ybe.mini.travelserver.domain.accommodation.controller; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import ybe.mini.travelserver.domain.accommodation.DummyAccommodation; +import ybe.mini.travelserver.domain.accommodation.dto.AccommodationDetailGetResponse; +import ybe.mini.travelserver.domain.accommodation.dto.AccommodationGetResponse; +import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; +import ybe.mini.travelserver.domain.accommodation.service.AccommodationService; +import ybe.mini.travelserver.global.common.ResponseDto; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; + +@ExtendWith(MockitoExtension.class) +class AccommodationControllerTest extends DummyAccommodation { + @Mock + AccommodationService accommodationService; + @InjectMocks + AccommodationController accommodationController; + + + @DisplayName("숙소 리스트 조회") + @Test + void SearchAccommodations_success() { + // given + List expectedAccommodations = Arrays.asList( + AccommodationGetResponse.fromEntity(dummyAccommodation()), + AccommodationGetResponse.fromEntity(dummyAccommodation1()) + ); + given(accommodationService.bringAccommodations(1, 10, "호텔", AreaCode.SEOUL)) + .willReturn(expectedAccommodations); + + // when + ResponseDto> responseDto = + accommodationController.searchAccommodations(1, "호텔", AreaCode.SEOUL); + + // then + assertNotNull(responseDto); + assertEquals(HttpStatus.OK.value(), responseDto.status()); + assertEquals(expectedAccommodations, responseDto.data()); + then(accommodationService).should().bringAccommodations(1, 10, "호텔", AreaCode.SEOUL); + + } + + @DisplayName("숙소 상세 조회") + @Test + void SearchAccommodation_success() { + // given + AccommodationDetailGetResponse expectedAccommodation = + AccommodationDetailGetResponse.fromEntity(dummyAccommodation()); + given(accommodationService.bringAccommodationFromAPI("호텔", AreaCode.SEOUL)) + .willReturn(expectedAccommodation); + + // when + ResponseDto responseDto = + accommodationController.searchAccommodation("호텔", AreaCode.SEOUL); + + // then + assertNotNull(responseDto); + assertEquals(HttpStatus.OK.value(), responseDto.status()); + assertEquals(expectedAccommodation, responseDto.data()); + then(accommodationService).should().bringAccommodationFromAPI("호텔", AreaCode.SEOUL); + } +} diff --git a/src/test/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationServiceTest.java b/src/test/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationServiceTest.java new file mode 100644 index 0000000..4573dcd --- /dev/null +++ b/src/test/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationServiceTest.java @@ -0,0 +1,79 @@ +package ybe.mini.travelserver.domain.accommodation.service; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; +import ybe.mini.travelserver.domain.accommodation.DummyAccommodation; +import ybe.mini.travelserver.domain.accommodation.dto.AccommodationDetailGetResponse; +import ybe.mini.travelserver.domain.accommodation.dto.AccommodationGetResponse; +import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; +import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; +import ybe.mini.travelserver.global.api.TourAPIService; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class AccommodationServiceTest extends DummyAccommodation { + @Mock + TourAPIService tourAPIService; + @InjectMocks + AccommodationService accommodationService; + + @DisplayName("숙소 리스트 조회") + @Test + void SearchAccommodations_success() { + // given + List expectedAccommodations = Arrays.asList( + dummyAccommodation(), dummyAccommodation1() + ); + List responseDto = expectedAccommodations.stream() + .map(AccommodationGetResponse::fromEntity) + .toList(); + given(tourAPIService.bringAccommodations(eq(1), eq(10), eq("호텔"), eq("1"))) + .willReturn(expectedAccommodations); + + // when + List actualAccommodations = + accommodationService.bringAccommodations(1, 10, "호텔", AreaCode.SEOUL); + + // then + assertNotNull(actualAccommodations); + assertEquals(responseDto.size(), actualAccommodations.size()); + assertEquals(responseDto, actualAccommodations); + then(tourAPIService).should().bringAccommodations(eq(1), eq(10), eq("호텔"), eq("1")); + + } + + @DisplayName("숙소 상세 조회") + @Test + void SearchAccommodation_success() { + // given + Accommodation expectedAccommodation = dummyAccommodation(); + AccommodationDetailGetResponse responseDto = + AccommodationDetailGetResponse.fromEntity(expectedAccommodation); + given(tourAPIService.bringAccommodation(eq("호텔"), eq("1"))) + .willReturn(expectedAccommodation); + + // when + AccommodationDetailGetResponse actualAccommodation = + accommodationService.bringAccommodationFromAPI("호텔", AreaCode.SEOUL); + + // then + assertNotNull(actualAccommodation); + assertEquals(responseDto, actualAccommodation); + then(tourAPIService).should().bringAccommodation(eq("호텔"), eq("1")); + } +} From 00805a27ddda9263940ba80ce0f0a35a84fa791f Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:25:05 +0900 Subject: [PATCH 11/20] =?UTF-8?q?Feat:=20TourAPI=20exception=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/api/WrongRequestException.java | 15 +++++++++++++++ .../exception/api/WrongXMLFormatException.java | 9 +++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/ybe/mini/travelserver/global/exception/api/WrongRequestException.java create mode 100644 src/main/java/ybe/mini/travelserver/global/exception/api/WrongXMLFormatException.java diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/WrongRequestException.java b/src/main/java/ybe/mini/travelserver/global/exception/api/WrongRequestException.java new file mode 100644 index 0000000..44632a6 --- /dev/null +++ b/src/main/java/ybe/mini/travelserver/global/exception/api/WrongRequestException.java @@ -0,0 +1,15 @@ +package ybe.mini.travelserver.global.exception.api; + +public class WrongRequestException extends RuntimeException { + + public final String msg; + + public WrongRequestException(String msg) { + this.msg = msg; + } + + @Override + public String getMessage() { + return msg; + } +} diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/WrongXMLFormatException.java b/src/main/java/ybe/mini/travelserver/global/exception/api/WrongXMLFormatException.java new file mode 100644 index 0000000..69ff6e8 --- /dev/null +++ b/src/main/java/ybe/mini/travelserver/global/exception/api/WrongXMLFormatException.java @@ -0,0 +1,9 @@ +package ybe.mini.travelserver.global.exception.api; + +import jakarta.xml.bind.JAXBException; + +public class WrongXMLFormatException extends RuntimeException { + public WrongXMLFormatException(JAXBException e) { + super(e); + } +} From 9c54b4755cc07618accafa8e5d4e9e305ed6ea7d Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:25:44 +0900 Subject: [PATCH 12/20] =?UTF-8?q?Chore:=20TourAPI=20exception=20=EC=95=88?= =?UTF-8?q?=EC=93=B0=EB=8A=94=20=EA=B2=83=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/exception/api/WrongCallBackException.java | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 src/main/java/ybe/mini/travelserver/global/exception/api/WrongCallBackException.java diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/WrongCallBackException.java b/src/main/java/ybe/mini/travelserver/global/exception/api/WrongCallBackException.java deleted file mode 100644 index 51d5512..0000000 --- a/src/main/java/ybe/mini/travelserver/global/exception/api/WrongCallBackException.java +++ /dev/null @@ -1,4 +0,0 @@ -package ybe.mini.travelserver.global.exception.api; - -public class WrongCallBackException extends RuntimeException { -} From d5ea62223fd76b6f84ceaca4a56b026be5013f69 Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:26:29 +0900 Subject: [PATCH 13/20] =?UTF-8?q?Feat:=20TourAPI=20error=20message=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../exception/api/TourAPIErrorMessage.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIErrorMessage.java b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIErrorMessage.java index f7bd0bc..719e7c9 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIErrorMessage.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIErrorMessage.java @@ -3,17 +3,38 @@ import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.http.HttpStatus; +import org.springframework.http.HttpStatusCode; import ybe.mini.travelserver.global.exception.ErrorMessage; -import static org.springframework.http.HttpStatus.BAD_REQUEST; -import static org.springframework.http.HttpStatus.SERVICE_UNAVAILABLE; +import static org.springframework.http.HttpStatus.*; @Getter @AllArgsConstructor public enum TourAPIErrorMessage implements ErrorMessage { - NO_ACCOMMODATIONS_FROM_API(BAD_REQUEST, "API로부터 숙소를 가져오지 못했습니다."), - NO_ROOMS_FROM_API(BAD_REQUEST, "API로부터 객실을 가져오지 못했습니다."), - WRONG_CALLBACK(SERVICE_UNAVAILABLE, "잘못된 콜백입니다."); + // Tour API 숙박, 객실 비즈니스 오류 + NO_ACCOMMODATIONS_FROM_API(NO_CONTENT, "숙소 결과가 반환된 것이 없습니다"), + NO_ROOMS_FROM_API(NO_CONTENT, "객실 결과가 반환된 것이 없습니다"), + + // Tour API Keyword 검색 부분 오류 + INVALID_REQUEST_PARAMETER_ERROR(BAD_REQUEST, "잘못된 요청 파라메터입니다."), + NO_MANDATORY_REQUEST_PARAMETERS_ERROR(BAD_REQUEST, "필수 요청 파라메터가 없습니다."), + TEMPORARILY_DISABLE_THE_SERVICEKEY_ERROR(FORBIDDEN, "일시적으로 사용할 수 없는 서비스 키입니다."), + UNSIGNED_CALL_ERROR(FORBIDDEN, "서명되지 않은 호출입니다."), + NODATA_ERROR(NOT_FOUND, "데이터가 없습니다."), + SERVICETIMEOUT_ERROR(GATEWAY_TIMEOUT, "서비스 연결 실패입니다."), + DB_ERROR(INTERNAL_SERVER_ERROR, "데이터베이스 에러입니다."), + + // Tour API 공통 오류 + APPLICATION_ERROR(INTERNAL_SERVER_ERROR, "Tour API 서버 어플리케이션 에러입니다"), + HTTP_ERROR(INTERNAL_SERVER_ERROR, "Tour API 서버 HTTP 에러입니다"), + NO_OPENAPI_SERVICE_ERROR(INTERNAL_SERVER_ERROR, "해당 Tour API 서비스가 없거나 폐기되었습니다"), + SERVICE_ACCESS_DENIED_ERROR(FORBIDDEN, "Tour API 서비스 접근이 거부되었습니다"), + LIMITED_NUMBER_OF_SERVICE_REQUESTS_EXCEEDS_ERROR(FORBIDDEN, "Tour API 서비스 요청 제한 횟수를 초과하였습니다"), + SERVICE_KEY_IS_NOT_REGISTERED_ERROR(FORBIDDEN, "등록되지 않은 Tour API 서비스 키입니다"), + DEADLINE_HAS_EXPIRED_ERROR(FORBIDDEN, "Tour API 서비스 활용 기간이 만료되었습니다"), + UNREGISTERED_IP_ERROR(FORBIDDEN, "등록되지 않은 Tour API 서비스 IP입니다"), + UNKNOWN_ERROR(INTERNAL_SERVER_ERROR, "Tour API 서버 알 수 없는 에러입니다"); + private final HttpStatus status; private final String message; } From 170f3cca3e98cc5fba161aa418411950df587811 Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:27:40 +0900 Subject: [PATCH 14/20] =?UTF-8?q?Feat:=20TourAPI=20error=20handler=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/TourAPIExceptionHandler.java | 19 +++++++++++-- .../api/TourAPIXMLErrorResponse.java | 27 +++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIXMLErrorResponse.java diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIExceptionHandler.java b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIExceptionHandler.java index edd9883..bcf23e6 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIExceptionHandler.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIExceptionHandler.java @@ -1,11 +1,15 @@ package ybe.mini.travelserver.global.exception.api; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; import org.springframework.http.ProblemDetail; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import ybe.mini.travelserver.global.exception.ProblemDetailCreator; +import static ybe.mini.travelserver.global.exception.api.TourAPIErrorMessage.*; + + @RestControllerAdvice public class TourAPIExceptionHandler extends ProblemDetailCreator { protected TourAPIExceptionHandler() { @@ -14,12 +18,23 @@ protected TourAPIExceptionHandler() { @ExceptionHandler(NoAccommodationsFromAPIException.class) public ProblemDetail handleNotGatheredAccommodationsFromAPIException(HttpServletRequest request) { - return createProblemDetail(TourAPIErrorMessage.NO_ACCOMMODATIONS_FROM_API, request); + return createProblemDetail(NO_ACCOMMODATIONS_FROM_API, request); } @ExceptionHandler(NoRoomsFromAPIException.class) public ProblemDetail handleNotGatheredRoomsFromAPIException(HttpServletRequest request) { - return createProblemDetail(TourAPIErrorMessage.NO_ROOMS_FROM_API, request); + return createProblemDetail(NO_ROOMS_FROM_API, request); } + @ExceptionHandler(WrongXMLFormatException.class) + public ProblemDetail handleWrongXMLFormatException( + WrongXMLFormatException ex, + HttpServletRequest request) { + return createProblemDetail(ex.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR.value(), request); + } + + @ExceptionHandler(WrongRequestException.class) + public ProblemDetail handleWrongCallBackException(WrongRequestException ex, HttpServletRequest request) { + return createProblemDetail(valueOf(ex.getMessage()), request); + } } \ No newline at end of file diff --git a/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIXMLErrorResponse.java b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIXMLErrorResponse.java new file mode 100644 index 0000000..e42bedd --- /dev/null +++ b/src/main/java/ybe/mini/travelserver/global/exception/api/TourAPIXMLErrorResponse.java @@ -0,0 +1,27 @@ +package ybe.mini.travelserver.global.exception.api; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.Getter; + +@Getter +@XmlRootElement(name = "OpenAPI_ServiceResponse") +public class TourAPIXMLErrorResponse { + + @XmlElement(name = "cmmMsgHeader") + private ErrorHeader errorHeader; + + @Getter + public static class ErrorHeader { + + @XmlElement(name = "errMsg") + private String errMsg; + + @XmlElement(name = "returnAuthMsg") + private String returnAuthMsg; + + @XmlElement(name = "returnReasonCode") + private String returnReasonCode; + + } +} \ No newline at end of file From 50f45c97ab86dbdf38383e08ea3b368c6a4a2684 Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:27:59 +0900 Subject: [PATCH 15/20] =?UTF-8?q?Feat:=20TourAPI=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/api/TourAPIService.java | 6 ++-- .../travelserver/global/api/TourAPIUtils.java | 35 +++++++++++++++---- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/global/api/TourAPIService.java b/src/main/java/ybe/mini/travelserver/global/api/TourAPIService.java index 2c77188..966b5cc 100644 --- a/src/main/java/ybe/mini/travelserver/global/api/TourAPIService.java +++ b/src/main/java/ybe/mini/travelserver/global/api/TourAPIService.java @@ -26,7 +26,7 @@ public Accommodation bringAccommodation( var body = accommodationsSimpleSearchResponse.response().body(); - if (body.totalCount() == 0) { + if (body.numOfRows() == 0) { throw new NoAccommodationsFromAPIException(); } @@ -59,7 +59,7 @@ public List bringAccommodations( var body = accommodationsSimpleSearchResponse.response().body(); - if (body.totalCount() == 0) { + if (body.numOfRows() == 0) { throw new NoAccommodationsFromAPIException(); } var items = body.items().item(); @@ -103,7 +103,7 @@ public List bringRooms(long accommodationId) { var body = roomTourAPIResponse.response().body(); - if (body.totalCount() == 0) { + if (body.numOfRows() == 0) { throw new NoRoomsFromAPIException(); } diff --git a/src/main/java/ybe/mini/travelserver/global/api/TourAPIUtils.java b/src/main/java/ybe/mini/travelserver/global/api/TourAPIUtils.java index 882d4e4..6db0658 100644 --- a/src/main/java/ybe/mini/travelserver/global/api/TourAPIUtils.java +++ b/src/main/java/ybe/mini/travelserver/global/api/TourAPIUtils.java @@ -1,5 +1,10 @@ package ybe.mini.travelserver.global.api; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; import lombok.AccessLevel; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -7,16 +12,18 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; -import org.springframework.util.StreamUtils; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.client.HttpMessageConverterExtractor; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.DefaultUriBuilderFactory; import ybe.mini.travelserver.global.api.dto.AccommodationTourAPIResponse; import ybe.mini.travelserver.global.api.dto.RoomTourAPIResponse; -import ybe.mini.travelserver.global.exception.api.WrongCallBackException; +import ybe.mini.travelserver.global.exception.api.TourAPIXMLErrorResponse; +import ybe.mini.travelserver.global.exception.api.WrongRequestException; +import ybe.mini.travelserver.global.exception.api.WrongXMLFormatException; import java.net.URLEncoder; -import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Objects; @@ -31,6 +38,14 @@ public class TourAPIUtils { DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(); factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE); restTemplate.setUriTemplateHandler(factory); + + ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json() + .featuresToEnable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT) + .build(); + + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(objectMapper); + + restTemplate.getMessageConverters().add(0, converter); } private static StringBuilder buildCommonUrl(String endpoint) { @@ -63,9 +78,17 @@ private static T fetchDataFromAPI( clientHttpResponse -> { MediaType contentType = clientHttpResponse.getHeaders().getContentType(); if (contentType != null && contentType.includes(MediaType.TEXT_XML)) { - String body = StreamUtils.copyToString(clientHttpResponse.getBody(), Charset.defaultCharset()); - log.error("공공포텅 오류 XML 반환 : {}", body); - throw new WrongCallBackException(); + try { + JAXBContext jaxbContext = JAXBContext.newInstance(TourAPIXMLErrorResponse.class); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + TourAPIXMLErrorResponse tourAPIXMLErrorResponse = (TourAPIXMLErrorResponse) unmarshaller.unmarshal(clientHttpResponse.getBody()); + log.error("공공포털 오류 XML 반환 : {}", tourAPIXMLErrorResponse); + + String errorMessage = tourAPIXMLErrorResponse.getErrorHeader().getReturnAuthMsg(); + throw new WrongRequestException(errorMessage); + } catch (JAXBException e) { + throw new WrongXMLFormatException(e); + } } return new HttpMessageConverterExtractor<>(responseType, restTemplate.getMessageConverters()) From 4da315df5ec4d79917b91e3a21010f09481226b3 Mon Sep 17 00:00:00 2001 From: okjaeook Date: Tue, 28 Nov 2023 18:28:40 +0900 Subject: [PATCH 16/20] =?UTF-8?q?Chore:=20xml=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index e6afa0c..15e5cf8 100644 --- a/build.gradle +++ b/build.gradle @@ -53,6 +53,8 @@ dependencies { //javers implementation 'org.javers:javers-core:7.2.0' + // xml jaxb + implementation 'jakarta.xml.bind:jakarta.xml.bind-api:+' } From 9d01579ba4c6ba7c9f939fc496551a798e4c0fde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9C=A0=ED=98=84?= Date: Tue, 28 Nov 2023 19:11:58 +0900 Subject: [PATCH 17/20] =?UTF-8?q?Feat:=20=EC=A1=B0=ED=9A=8C=ED=95=A0=20?= =?UTF-8?q?=EA=B0=92=EC=9D=B4=20=EC=97=86=EB=8A=94=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=A1=B0=ED=9A=8C=20=EC=8B=9C=20204=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/accommodation/service/AccommodationService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java b/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java index 89758f8..2b4753f 100644 --- a/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java +++ b/src/main/java/ybe/mini/travelserver/domain/accommodation/service/AccommodationService.java @@ -7,8 +7,8 @@ import ybe.mini.travelserver.domain.accommodation.entity.Accommodation; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; import ybe.mini.travelserver.global.api.TourAPIService; +import ybe.mini.travelserver.global.exception.api.NoAccommodationsFromAPIException; -import java.util.Collections; import java.util.List; @@ -22,7 +22,9 @@ public List bringAccommodations( int pageNo, int numOfRows, String keyword, AreaCode areaCode ) { - if (pageNo <= 0) return Collections.emptyList(); + if (pageNo <= 0) { + throw new NoAccommodationsFromAPIException(); + } String areaCodeString = (areaCode != null) ? String.valueOf(areaCode.getCode()) : null; From 4caeb8798461c282d89535d4ef8004c1dd6b4dde Mon Sep 17 00:00:00 2001 From: minjung Date: Tue, 28 Nov 2023 19:12:09 +0900 Subject: [PATCH 18/20] =?UTF-8?q?Fix:=20cart=20=EC=B2=B4=ED=81=AC=EC=9D=B8?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=EC=95=84=EC=9B=83=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=8F=AC=EB=A7=B7=20=EB=B3=80=EA=B2=BD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20validation=20=EB=B0=8F=20?= =?UTF-8?q?=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cart/dto/request/CartCreateRequest.java | 15 +++++--------- .../domain/cart/service/CartService.java | 11 ++++++++-- .../global/api/TourAPIProperties.java | 5 ++--- .../global/exception/dto/DTOErrorMessage.java | 1 + .../exception/dto/DTOExceptionHandler.java | 11 ++++++++-- ...DateFormatNotCurrentOrFutureException.java | 4 ++++ .../travelserver/global/util/Validation.java | 20 +++++++++++++++++++ 7 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 src/main/java/ybe/mini/travelserver/global/exception/dto/DateFormatNotCurrentOrFutureException.java create mode 100644 src/main/java/ybe/mini/travelserver/global/util/Validation.java diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java index cba171e..a22d3eb 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java @@ -2,10 +2,7 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.constraints.FutureOrPresent; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.*; import lombok.Builder; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; @@ -18,13 +15,11 @@ public record CartCreateRequest( @Positive Long roomTypeId, - @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd") - LocalDate checkIn, + @Pattern(regexp = "\\d{8}", message = "날짜 입력은 8자리 숫자이어야 합니다.") + String checkIn, - @FutureOrPresent - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyyMMdd") - LocalDate checkOut, + @Pattern(regexp = "\\d{8}", message = "날짜 입력은 8자리 숫자이어야 합니다.") + String checkOut, @Positive Integer guestNumber, diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java index 98f2885..8430f88 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/service/CartService.java @@ -21,8 +21,11 @@ import ybe.mini.travelserver.domain.room.repository.RoomRepository; import ybe.mini.travelserver.global.api.TourAPIService; +import java.time.LocalDate; import java.util.List; +import static ybe.mini.travelserver.global.util.Validation.validateDateFormat; + @Slf4j @RequiredArgsConstructor @Service @@ -81,15 +84,19 @@ private Room createRoomById(Accommodation accommodation, Long roomId) { } private Cart createCart(CartCreateRequest cartCreateRequest, Room room, Member member) { + + LocalDate checkIn = validateDateFormat(cartCreateRequest.checkIn()); + LocalDate checkOut = validateDateFormat(cartCreateRequest.checkOut()); return Cart.builder() .guestNumber(cartCreateRequest.guestNumber()) .room(room) .member(member) - .checkOut(cartCreateRequest.checkOut()) - .checkIn(cartCreateRequest.checkIn()) + .checkOut(checkOut) + .checkIn(checkIn) .build(); } + private Room getOrSaveRoom(Room room) { return roomRepository.findByRoomTypeId(room.getRoomTypeId()) .orElseGet(() -> roomRepository.save(room)); diff --git a/src/main/java/ybe/mini/travelserver/global/api/TourAPIProperties.java b/src/main/java/ybe/mini/travelserver/global/api/TourAPIProperties.java index aa35d5b..58cb87f 100644 --- a/src/main/java/ybe/mini/travelserver/global/api/TourAPIProperties.java +++ b/src/main/java/ybe/mini/travelserver/global/api/TourAPIProperties.java @@ -5,9 +5,8 @@ @NoArgsConstructor(access = AccessLevel.PRIVATE) public class TourAPIProperties { - public static final String KEY_DECODED = "1Wkp7yq9dkbxF4oNKeJQQJdUd55hQvujedMr43Rne5vvK7bkirS+1GRzd9rkerYmlitxxeoP8O86VsxM8WTz6A=="; - public static final String KEY_ENCODED = "1Wkp7yq9dkbxF4oNKeJQQJdUd55hQvujedMr43Rne5vvK7bkirS%2B1GRzd9rkerYmlitxxeoP8O86VsxM8WTz6A%3D%3D"; - + public static final String KEY_DECODED = "rKtD0jUO3f83Q/Q7QJ7yxo2GMBF489d4y5NM3H48uUffmUXjeoARqF4wmsICTBt3BVS988w8vG4Nh2UZtMV2/A=="; + public static final String KEY_ENCODED = "rKtD0jUO3f83Q%2FQ7QJ7yxo2GMBF489d4y5NM3H48uUffmUXjeoARqF4wmsICTBt3BVS988w8vG4Nh2UZtMV2%2FA%3D%3D"; public static final String BASE_URL = "https://apis.data.go.kr/B551011/KorService1/"; public static final String SEARCH_KEYWORD = "searchKeyword1"; diff --git a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java index fd0ae40..012f322 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOErrorMessage.java @@ -12,6 +12,7 @@ public enum DTOErrorMessage implements ErrorMessage { METHOD_ARGUMENT_NOT_VALID(BAD_REQUEST, "DTO 값이 유효하지 않습니다"), DATETIME_PARSE(BAD_REQUEST, "날짜 형식이 유효하지 않습니다"), + DATETIME_NOT_CURRENT_OR_FUTURE(BAD_REQUEST, "날짜가 현재 날짜보다 같거나 이후여야합니다.") ; private final HttpStatus status; diff --git a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java index 4091267..3a2ed4d 100644 --- a/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java +++ b/src/main/java/ybe/mini/travelserver/global/exception/dto/DTOExceptionHandler.java @@ -10,8 +10,7 @@ import java.time.format.DateTimeParseException; import java.util.Objects; -import static ybe.mini.travelserver.global.exception.dto.DTOErrorMessage.DATETIME_PARSE; -import static ybe.mini.travelserver.global.exception.dto.DTOErrorMessage.METHOD_ARGUMENT_NOT_VALID; +import static ybe.mini.travelserver.global.exception.dto.DTOErrorMessage.*; @RestControllerAdvice public class DTOExceptionHandler extends ProblemDetailCreator { @@ -34,4 +33,12 @@ public ProblemDetail handleDateTimeParseException( ) { return createProblemDetail(DATETIME_PARSE, request); } + + @ExceptionHandler(DateFormatNotCurrentOrFutureException.class) + public ProblemDetail handleDateFormatNotCurrentOrFutureException( + HttpServletRequest request + ) { + return createProblemDetail(DATETIME_NOT_CURRENT_OR_FUTURE, request); + } + } \ No newline at end of file diff --git a/src/main/java/ybe/mini/travelserver/global/exception/dto/DateFormatNotCurrentOrFutureException.java b/src/main/java/ybe/mini/travelserver/global/exception/dto/DateFormatNotCurrentOrFutureException.java new file mode 100644 index 0000000..3c40c76 --- /dev/null +++ b/src/main/java/ybe/mini/travelserver/global/exception/dto/DateFormatNotCurrentOrFutureException.java @@ -0,0 +1,4 @@ +package ybe.mini.travelserver.global.exception.dto; + +public class DateFormatNotCurrentOrFutureException extends RuntimeException { +} diff --git a/src/main/java/ybe/mini/travelserver/global/util/Validation.java b/src/main/java/ybe/mini/travelserver/global/util/Validation.java new file mode 100644 index 0000000..05f0189 --- /dev/null +++ b/src/main/java/ybe/mini/travelserver/global/util/Validation.java @@ -0,0 +1,20 @@ +package ybe.mini.travelserver.global.util; + +import ybe.mini.travelserver.global.exception.dto.DateFormatNotCurrentOrFutureException; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +public class Validation { + + public static final String datePattern = "yyyyMMdd"; + + public static LocalDate validateDateFormat(String dateString) throws DateTimeParseException { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(datePattern); + LocalDate date = LocalDate.parse(dateString, formatter); + LocalDate nowDate = LocalDate.now(); + if(date.compareTo(nowDate) >= 0) return date; + else throw new DateFormatNotCurrentOrFutureException(); + } +} From 4098ac9c6de98dd665207cc51688b650af106d67 Mon Sep 17 00:00:00 2001 From: minjung Date: Tue, 28 Nov 2023 19:17:15 +0900 Subject: [PATCH 19/20] =?UTF-8?q?Fix:=20reservation=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=8F=AC=EB=A7=B7=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ReservationService.java | 8 +++++++- .../dto/ReservationRoomCreateRequest.java | 18 +++++------------- .../dto/ReservationRoomGetResponse.java | 5 +++-- .../entity/ReservationRoom.java | 11 ++++++----- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java index fefd80d..bf785bf 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation/service/ReservationService.java @@ -22,10 +22,13 @@ import ybe.mini.travelserver.domain.room.entity.Room; import ybe.mini.travelserver.domain.room.repository.RoomRepository; import ybe.mini.travelserver.global.api.TourAPIService; +import ybe.mini.travelserver.global.util.Validation; import java.util.ArrayList; import java.util.List; +import static ybe.mini.travelserver.global.util.Validation.validateDateFormat; + @Slf4j @RequiredArgsConstructor @Service @@ -101,7 +104,10 @@ private ReservationRoom reservationRoomDtoToEntity(ReservationRoomCreateRequest room = getOrSaveRoom(room); return ReservationRoom.createReservationRoom( - room, roomRequest.checkIn(), roomRequest.checkOut(), roomRequest.guestNumber() + room, + validateDateFormat(roomRequest.checkIn()), + validateDateFormat(roomRequest.checkOut()), + roomRequest.guestNumber() ); } diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java index 84b39c2..432fbcc 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomCreateRequest.java @@ -1,9 +1,6 @@ package ybe.mini.travelserver.domain.reservation_room.dto; -import jakarta.validation.constraints.FutureOrPresent; -import jakarta.validation.constraints.Min; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.*; import lombok.Builder; import org.springframework.format.annotation.DateTimeFormat; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; @@ -22,15 +19,10 @@ public record ReservationRoomCreateRequest( AreaCode areaCode, @NotNull(message = "roomTypeId 양식이 잘못 입력되었습니다.") Long roomTypeId, - - - @FutureOrPresent - @DateTimeFormat(pattern = "yyyy-MM-dd") - LocalDateTime checkIn, - - @FutureOrPresent - @DateTimeFormat(pattern = "yyyy-MM-dd") - LocalDateTime checkOut, + @Pattern(regexp = "\\d{8}", message = "날짜 입력은 8자리 숫자이어야 합니다.") + String checkIn, + @Pattern(regexp = "\\d{8}", message = "날짜 입력은 8자리 숫자이어야 합니다.") + String checkOut, @NotNull @Min(value = 1, message = "숙박 인원은 최소 1명 이어야 합니다.") Integer guestNumber diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomGetResponse.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomGetResponse.java index dcd2f56..e44e7e3 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomGetResponse.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/dto/ReservationRoomGetResponse.java @@ -9,15 +9,16 @@ import ybe.mini.travelserver.domain.room.dto.RoomGetResponse; import java.io.Serializable; +import java.time.LocalDate; import java.time.LocalDateTime; @Builder public record ReservationRoomGetResponse( Long id, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm") - LocalDateTime checkIn, + LocalDate checkIn, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm") - LocalDateTime checkOut, + LocalDate checkOut, Integer guestNumber, ReservationRoomStatus status, RoomGetResponse room diff --git a/src/main/java/ybe/mini/travelserver/domain/reservation_room/entity/ReservationRoom.java b/src/main/java/ybe/mini/travelserver/domain/reservation_room/entity/ReservationRoom.java index 2d0f878..a47e03f 100644 --- a/src/main/java/ybe/mini/travelserver/domain/reservation_room/entity/ReservationRoom.java +++ b/src/main/java/ybe/mini/travelserver/domain/reservation_room/entity/ReservationRoom.java @@ -10,6 +10,7 @@ import ybe.mini.travelserver.domain.reservation.entity.Reservation; import ybe.mini.travelserver.domain.room.entity.Room; +import java.time.LocalDate; import java.time.LocalDateTime; import static ybe.mini.travelserver.domain.reservation_room.entity.ReservationRoomStatus.PAYED; @@ -37,12 +38,12 @@ public class ReservationRoom { private Reservation reservation; @Comment("객실 체크인") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") - private LocalDateTime checkIn; + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate checkIn; @Comment("객실 체크아웃") - @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm") - private LocalDateTime checkOut; + @DateTimeFormat(pattern = "yyyy-MM-dd") + private LocalDate checkOut; @Enumerated(EnumType.STRING) @Comment("에약 상태") @@ -56,7 +57,7 @@ public void setReservation(Reservation reservation) { } public static ReservationRoom createReservationRoom( - Room room, LocalDateTime checkIn, LocalDateTime checkOut, Integer guestNumber + Room room, LocalDate checkIn, LocalDate checkOut, Integer guestNumber ) { return ReservationRoom.builder() .room(room) From 4886c2abf395fa8129322012aae3bd4564783d57 Mon Sep 17 00:00:00 2001 From: minjung Date: Tue, 28 Nov 2023 19:23:18 +0900 Subject: [PATCH 20/20] =?UTF-8?q?Fix:=20reservation=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/cart/dto/request/CartCreateRequest.java | 8 ++++---- .../dummy/DummyReservationRoomDTO.java | 13 +++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java index a22d3eb..767722f 100644 --- a/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java +++ b/src/main/java/ybe/mini/travelserver/domain/cart/dto/request/CartCreateRequest.java @@ -1,13 +1,13 @@ package ybe.mini.travelserver.domain.cart.dto.request; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import jakarta.validation.constraints.*; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; import lombok.Builder; import ybe.mini.travelserver.domain.accommodation.entity.AreaCode; -import java.time.LocalDate; - @Builder @JsonIgnoreProperties(ignoreUnknown = true) public record CartCreateRequest( diff --git a/src/test/java/ybe/mini/travelserver/domain/reservation_room/dummy/DummyReservationRoomDTO.java b/src/test/java/ybe/mini/travelserver/domain/reservation_room/dummy/DummyReservationRoomDTO.java index 1d62924..622df1f 100644 --- a/src/test/java/ybe/mini/travelserver/domain/reservation_room/dummy/DummyReservationRoomDTO.java +++ b/src/test/java/ybe/mini/travelserver/domain/reservation_room/dummy/DummyReservationRoomDTO.java @@ -6,6 +6,7 @@ import ybe.mini.travelserver.domain.reservation_room.entity.ReservationRoomStatus; import ybe.mini.travelserver.domain.room.DummyObjectForRoom; +import java.time.LocalDate; import java.time.LocalDateTime; public interface DummyReservationRoomDTO extends DummyObjectForRoom { @@ -15,8 +16,8 @@ default ReservationRoomCreateRequest dummyReservationRoomCreateReq1() { .accommodationId(14253L) .accommodationName("청룡관광호텔") .roomTypeId(5352L) - .checkIn(LocalDateTime.of(2022,1,1,15,0)) - .checkOut(LocalDateTime.of(2022,1,2,11,0)) + .checkIn("20241101") + .checkOut("20241102") .guestNumber(2) .build(); } @@ -26,8 +27,8 @@ default ReservationRoomCreateRequest dummyReservationRoomCreateReq2() { .accommodationId(14253L) .accommodationName("청룡관광호텔") .roomTypeId(5352L) - .checkIn(LocalDateTime.of(2022,1,3,15,0)) - .checkOut(LocalDateTime.of(2022,1,4,11,0)) + .checkIn("20240101") + .checkOut("20241102") .guestNumber(2) .build(); } @@ -35,8 +36,8 @@ default ReservationRoomCreateRequest dummyReservationRoomCreateReq2() { default ReservationRoomGetResponse dummyReservationRoomGetRes() { return ReservationRoomGetResponse.builder() .id(1L) - .checkIn(LocalDateTime.of(2022,1,3,15,0)) - .checkOut(LocalDateTime.of(2022,1,4,11,0)) + .checkIn(LocalDate.of(2024,1,1)) + .checkOut(LocalDate.of(2024,1,2)) .guestNumber(2) .status(ReservationRoomStatus.RESERVED) .room(dummyRoomGetResponse())