Skip to content

Commit 9fca162

Browse files
committed
[FIX] 예약 조회 시 이미지 테이블에서 관련 이미지도 함께 조회되도록 로직 수정
1 parent 1913bc3 commit 9fca162

File tree

6 files changed

+120
-70
lines changed

6 files changed

+120
-70
lines changed

src/main/java/com/sumte/guesthouse/dto/GuesthouseDetailDTO.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ public class GuesthouseDetailDTO {
2323
private AdType advertisement;
2424
private List<String> optionServices;
2525
private List<String> targetAudience;
26-
private List<RoomResponseDTO.GetRoomResponse> rooms;
26+
private List<RoomResponseDTO.GetPreviewRoomByGuesthouseResponse> rooms;
2727
private List<String> imageUrls; // 모든 이미지 URL 리스트
2828
}

src/main/java/com/sumte/guesthouse/repository/GuesthouseRepositoryCustom.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import org.springframework.data.domain.Page;
44
import org.springframework.data.domain.Pageable;
55

6+
import com.sumte.guesthouse.dto.GuesthousePreviewDTO;
67
import com.sumte.guesthouse.dto.GuesthouseSearchRequestDTO;
7-
import com.sumte.guesthouse.entity.Guesthouse;
88

99
public interface GuesthouseRepositoryCustom {
10-
Page<Guesthouse> searchFiltered(GuesthouseSearchRequestDTO dto, Pageable pageable);
10+
Page<GuesthousePreviewDTO> searchFiltered(GuesthouseSearchRequestDTO dto, Pageable pageable);
1111
}

src/main/java/com/sumte/guesthouse/service/GuesthouseQueryServiceImpl.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ public GuesthouseDetailDTO getHouseById(Long guesthouseId) {
9191
));
9292

9393
// 4-c) RoomResponseDTO 리스트 생성
94-
List<RoomResponseDTO.GetRoomResponse> roomDtos = rooms.stream()
95-
.map(room -> RoomResponseDTO.GetRoomResponse.builder()
94+
List<RoomResponseDTO.GetPreviewRoomByGuesthouseResponse> roomDtos = rooms.stream()
95+
.map(room -> RoomResponseDTO.GetPreviewRoomByGuesthouseResponse.builder()
9696
.id(room.getId())
9797
.name(room.getName())
9898
.content(room.getContents())
@@ -190,15 +190,15 @@ public Slice<GuesthouseResponseDTO.HomeSummary> getGuesthousesForHome(Pageable p
190190
@Transactional
191191
public Page<GuesthousePreviewDTO> getFilteredGuesthouse(GuesthouseSearchRequestDTO dto, Pageable pageable) {
192192
// 1) 필터링된 게스트하우스 페이징 조회
193-
Page<Guesthouse> page = guesthouseRepositoryCustom.searchFiltered(dto, pageable);
194-
List<Guesthouse> ghList = page.getContent();
193+
Page<GuesthousePreviewDTO> page = guesthouseRepositoryCustom.searchFiltered(dto, pageable);
194+
List<GuesthousePreviewDTO> ghList = page.getContent();
195195
if (ghList.isEmpty()) {
196196
return new PageImpl<>(List.of(), pageable, 0);
197197
}
198198

199199
// 2) 조회된 게스트하우스 ID들
200200
List<Long> ghIds = ghList.stream()
201-
.map(Guesthouse::getId)
201+
.map(GuesthousePreviewDTO::getId)
202202
.toList();
203203

204204
// 3) 이미지 일괄 조회 (N+1 방지)
Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
package com.sumte.reservation.converter;
22

3-
import com.sumte.guesthouse.entity.Guesthouse;
3+
import java.time.temporal.ChronoUnit;
4+
45
import org.springframework.stereotype.Component;
56

7+
import com.sumte.guesthouse.entity.Guesthouse;
68
import com.sumte.reservation.dto.ReservationRequestDTO;
79
import com.sumte.reservation.dto.ReservationResponseDTO;
810
import com.sumte.reservation.entity.Reservation;
911
import com.sumte.reservation.entity.ReservationStatus;
1012
import com.sumte.room.entity.Room;
1113
import com.sumte.user.entity.User;
1214

13-
import java.time.temporal.ChronoUnit;
14-
1515
@Component
1616
public class ReservationConverter {
1717

@@ -33,45 +33,48 @@ public ReservationResponseDTO.CreateReservationDTO toCreateResponse(Reservation
3333
.build();
3434
}
3535

36-
public ReservationResponseDTO.MyReservationDTO toMyReservationDTO(Reservation reservation, boolean canWriteReview, boolean reviewWritten) {
36+
public ReservationResponseDTO.MyReservationDTO toMyReservationDTO(Reservation reservation, String firstRoomImageUrl,
37+
boolean canWriteReview,
38+
boolean reviewWritten) {
3739
Room room = reservation.getRoom();
3840
Guesthouse guestHouse = room.getGuesthouse();
39-
int nightCount = (int) ChronoUnit.DAYS.between(reservation.getStartDate(), reservation.getEndDate());
41+
int nightCount = (int)ChronoUnit.DAYS.between(reservation.getStartDate(), reservation.getEndDate());
4042

4143
return ReservationResponseDTO.MyReservationDTO.builder()
42-
.id(reservation.getId())
43-
.guestHouseName(guestHouse.getName())
44-
.roomName(room.getName())
45-
.imageUrl(room.getImageUrl())
46-
.startDate(reservation.getStartDate())
47-
.endDate(reservation.getEndDate())
48-
.adultCount(reservation.getAdultCount())
49-
.childCount(reservation.getChildCount())
50-
.nightCount(nightCount)
51-
.status(reservation.getReservationStatus())
52-
.canWriteReview(canWriteReview)
53-
.reviewWritten(reviewWritten)
54-
.build();
44+
.id(reservation.getId())
45+
.guestHouseName(guestHouse.getName())
46+
.roomName(room.getName())
47+
.imageUrl(firstRoomImageUrl)
48+
.startDate(reservation.getStartDate())
49+
.endDate(reservation.getEndDate())
50+
.adultCount(reservation.getAdultCount())
51+
.childCount(reservation.getChildCount())
52+
.nightCount(nightCount)
53+
.status(reservation.getReservationStatus())
54+
.canWriteReview(canWriteReview)
55+
.reviewWritten(reviewWritten)
56+
.build();
5557
}
5658

57-
public ReservationResponseDTO.ReservationDetailDTO toReservationDetailDTO(Reservation reservation) {
59+
public ReservationResponseDTO.ReservationDetailDTO toReservationDetailDTO(Reservation reservation,
60+
String firstRoomImageUrl) {
5861
Room room = reservation.getRoom();
5962
Guesthouse guestHouse = room.getGuesthouse();
60-
int nightCount = (int) ChronoUnit.DAYS.between(reservation.getStartDate(), reservation.getEndDate());
63+
int nightCount = (int)ChronoUnit.DAYS.between(reservation.getStartDate(), reservation.getEndDate());
6164

6265
return ReservationResponseDTO.ReservationDetailDTO.builder()
63-
.reservationId(reservation.getId())
64-
.guestHouseName(guestHouse.getName())
65-
.roomName(room.getName())
66-
.imageUrl(room.getImageUrl())
67-
.adultCount(reservation.getAdultCount())
68-
.childCount(reservation.getChildCount())
69-
.startDate(reservation.getStartDate())
70-
.endDate(reservation.getEndDate())
71-
.status(reservation.getReservationStatus().name())
72-
.totalPrice(room.getPrice())
73-
.nightCount(nightCount)
74-
.reservedAt(reservation.getCreatedAt())
75-
.build();
66+
.reservationId(reservation.getId())
67+
.guestHouseName(guestHouse.getName())
68+
.roomName(room.getName())
69+
.imageUrl(firstRoomImageUrl)
70+
.adultCount(reservation.getAdultCount())
71+
.childCount(reservation.getChildCount())
72+
.startDate(reservation.getStartDate())
73+
.endDate(reservation.getEndDate())
74+
.status(reservation.getReservationStatus().name())
75+
.totalPrice(room.getPrice())
76+
.nightCount(nightCount)
77+
.reservedAt(reservation.getCreatedAt())
78+
.build();
7679
}
7780
}

src/main/java/com/sumte/reservation/service/ReservationServiceImpl.java

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
11
package com.sumte.reservation.service;
22

3+
import java.time.LocalDate;
4+
import java.time.LocalTime;
5+
import java.util.List;
6+
import java.util.Optional;
7+
8+
import org.springframework.data.domain.Page;
9+
import org.springframework.data.domain.Pageable;
10+
import org.springframework.stereotype.Service;
11+
import org.springframework.transaction.annotation.Transactional;
12+
313
import com.sumte.apiPayload.code.error.CommonErrorCode;
414
import com.sumte.apiPayload.code.error.ReservationErrorCode;
515
import com.sumte.apiPayload.exception.SumteException;
16+
import com.sumte.image.entity.Image;
17+
import com.sumte.image.entity.OwnerType;
18+
import com.sumte.image.repository.ImageRepository;
619
import com.sumte.payment.entity.Payment;
720
import com.sumte.payment.entity.PaymentStatus;
821
import com.sumte.payment.repository.PaymentRepository;
9-
import com.sumte.reservation.entity.ReservationStatus;
10-
import com.sumte.review.repository.ReviewRepository;
11-
import org.springframework.data.domain.Page;
12-
import org.springframework.data.domain.Pageable;
13-
import org.springframework.stereotype.Service;
14-
1522
import com.sumte.reservation.converter.ReservationConverter;
1623
import com.sumte.reservation.dto.ReservationRequestDTO;
1724
import com.sumte.reservation.dto.ReservationResponseDTO;
1825
import com.sumte.reservation.entity.Reservation;
26+
import com.sumte.reservation.entity.ReservationStatus;
1927
import com.sumte.reservation.repository.ReservationRepository;
28+
import com.sumte.review.repository.ReviewRepository;
2029
import com.sumte.room.entity.Room;
2130
import com.sumte.room.repository.RoomRepository;
2231
import com.sumte.user.entity.User;
2332
import com.sumte.user.repository.UserRepository;
2433

2534
import lombok.RequiredArgsConstructor;
26-
import org.springframework.transaction.annotation.Transactional;
27-
28-
import java.time.LocalDate;
29-
import java.time.LocalTime;
30-
import java.util.List;
31-
import java.util.Optional;
3235

3336
@Service
3437
@RequiredArgsConstructor
@@ -40,17 +43,20 @@ public class ReservationServiceImpl implements ReservationService {
4043
private final UserRepository userRepository;
4144
private final PaymentRepository paymentRepository;
4245
private final ReviewRepository reviewRepository;
46+
private final ImageRepository imageRepository;
4347

4448
@Override
4549
@Transactional
46-
public ReservationResponseDTO.CreateReservationDTO createReservation(ReservationRequestDTO.CreateReservationDTO request, Long userId) {
50+
public ReservationResponseDTO.CreateReservationDTO createReservation(
51+
ReservationRequestDTO.CreateReservationDTO request, Long userId) {
4752
User user = userRepository.findById(userId)
48-
.orElseThrow(() -> new SumteException(CommonErrorCode.USER_NOT_FOUND));
53+
.orElseThrow(() -> new SumteException(CommonErrorCode.USER_NOT_FOUND));
4954
Room room = roomRepository.findById(request.getRoomId())
50-
.orElseThrow(() -> new SumteException(ReservationErrorCode.ROOM_NOT_FOUND));
55+
.orElseThrow(() -> new SumteException(ReservationErrorCode.ROOM_NOT_FOUND));
5156

5257
// 닐짜 유효성 검사
53-
if (request.getStartDate().isAfter(request.getEndDate()) || request.getStartDate().isEqual(request.getEndDate())) {
58+
if (request.getStartDate().isAfter(request.getEndDate()) || request.getStartDate()
59+
.isEqual(request.getEndDate())) {
5460
throw new SumteException(ReservationErrorCode.RESERVATION_DATE_INVALID);
5561
}
5662
// 정원 초과 검사
@@ -59,12 +65,13 @@ public ReservationResponseDTO.CreateReservationDTO createReservation(Reservation
5965
throw new SumteException(ReservationErrorCode.ROOM_CAPACITY_EXCEEDED);
6066
}
6167
// 중복 예약 검사
62-
boolean isOverlapping = reservationRepository.existsOverlappingReservation(room, request.getStartDate(), request.getEndDate());
63-
if(isOverlapping) {
68+
boolean isOverlapping = reservationRepository.existsOverlappingReservation(room, request.getStartDate(),
69+
request.getEndDate());
70+
if (isOverlapping) {
6471
throw new SumteException(ReservationErrorCode.ALREADY_RESERVED);
6572
}
6673

67-
Reservation reservation = reservationConverter.toEntity(request,user,room);
74+
Reservation reservation = reservationConverter.toEntity(request, user, room);
6875
reservationRepository.save(reservation);
6976
return reservationConverter.toCreateResponse(reservation);
7077
}
@@ -73,37 +80,60 @@ public ReservationResponseDTO.CreateReservationDTO createReservation(Reservation
7380
@Transactional(readOnly = true)
7481
public Page<ReservationResponseDTO.MyReservationDTO> getMyReservations(Long userId, Pageable pageable) {
7582
User user = userRepository.findById(userId)
76-
.orElseThrow(() -> new SumteException(CommonErrorCode.USER_NOT_FOUND));
83+
.orElseThrow(() -> new SumteException(CommonErrorCode.USER_NOT_FOUND));
7784

7885
Page<Reservation> reservations = reservationRepository.findAllByUser(user, pageable);
7986
return reservations.map(reservation -> {
8087
boolean isComplete = reservation.getReservationStatus().equals(ReservationStatus.COMPLETED);
8188

82-
boolean reviewWritten = reviewRepository.existsByUserIdAndRoomGuesthouseId(user.getId(), reservation.getRoom().getGuesthouse().getId());
89+
boolean reviewWritten = reviewRepository.existsByUserIdAndRoomGuesthouseId(user.getId(),
90+
reservation.getRoom().getGuesthouse().getId());
8391
boolean canWriteReview = isComplete && !reviewWritten;
8492

85-
return reservationConverter.toMyReservationDTO(reservation,canWriteReview,reviewWritten);
93+
// 첫 번째 방 이미지 URL 조회
94+
String firstImageUrl = imageRepository
95+
.findByOwnerTypeAndOwnerIdOrderBySortOrderAsc(
96+
OwnerType.ROOM,
97+
reservation.getRoom().getId()
98+
)
99+
.stream()
100+
.map(Image::getUrl)
101+
.findFirst()
102+
.orElse(null);
103+
104+
return reservationConverter.toMyReservationDTO(reservation, firstImageUrl, canWriteReview, reviewWritten);
86105
});
87106
}
88107

89108
@Override
90109
@Transactional(readOnly = true)
91110
public ReservationResponseDTO.ReservationDetailDTO getReservationDetail(Long reservationId, Long userId) {
92111
Reservation reservation = reservationRepository.findById(reservationId)
93-
.orElseThrow(() -> new SumteException(ReservationErrorCode.RESERVATION_NOT_FOUND));
112+
.orElseThrow(() -> new SumteException(ReservationErrorCode.RESERVATION_NOT_FOUND));
94113

95114
if (!reservation.getUser().getId().equals(userId)) {
96115
throw new SumteException(CommonErrorCode.FORBIDDEN);
97116
}
98117

99-
return reservationConverter.toReservationDetailDTO(reservation);
118+
// 첫 번째 방 이미지 URL 조회
119+
String firstImageUrl = imageRepository
120+
.findByOwnerTypeAndOwnerIdOrderBySortOrderAsc(
121+
OwnerType.ROOM,
122+
reservation.getRoom().getId()
123+
)
124+
.stream()
125+
.map(Image::getUrl)
126+
.findFirst()
127+
.orElse(null);
128+
129+
return reservationConverter.toReservationDetailDTO(reservation, firstImageUrl);
100130
}
101131

102132
@Override
103133
@Transactional
104134
public void cancelReservation(Long reservationId, Long userId) {
105135
Reservation reservation = reservationRepository.findById(reservationId)
106-
.orElseThrow(() -> new SumteException(ReservationErrorCode.RESERVATION_NOT_FOUND));
136+
.orElseThrow(() -> new SumteException(ReservationErrorCode.RESERVATION_NOT_FOUND));
107137

108138
// 사용자 본인 확인
109139
if (!reservation.getUser().getId().equals(userId)) {
@@ -129,14 +159,15 @@ public void updateCompletedReservations() {
129159

130160
boolean isAfterCheckout = endDate.isBefore(today) || (endDate.isEqual(today) && checkoutTime.isBefore(now));
131161

132-
if (!isAfterCheckout) continue;
162+
if (!isAfterCheckout)
163+
continue;
133164

134165
Optional<Payment> paymentOpt = paymentRepository.findByReservation(reservation);
135166

136167
boolean isPaid = paymentOpt
137-
.map(Payment::getPaymentStatus)
138-
.filter(status -> status == PaymentStatus.PAID)
139-
.isPresent();
168+
.map(Payment::getPaymentStatus)
169+
.filter(status -> status == PaymentStatus.PAID)
170+
.isPresent();
140171

141172
if (isPaid) {
142173
reservation.complete();

src/main/java/com/sumte/room/dto/RoomResponseDTO.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,22 @@ public static class GetRoomResponse {
5050
List<String> imageUrls;
5151
}
5252

53+
@Builder
54+
@Getter
55+
@NoArgsConstructor
56+
@AllArgsConstructor
57+
public static class GetPreviewRoomByGuesthouseResponse {
58+
Long id;
59+
String name;
60+
Long price;
61+
Long standardCount;
62+
Long totalCount;
63+
String content;
64+
LocalTime checkin;
65+
LocalTime checkout;
66+
String imageUrl;
67+
}
68+
5369
@NoArgsConstructor
5470
@Getter
5571
@AllArgsConstructor

0 commit comments

Comments
 (0)