Skip to content

Commit 6b9fb2b

Browse files
authored
refactor: 멘토 및 채팅 관련 API 응답 수정 (#537)
* refactor: 멘토의 멘토링 조회 응답에서 mentoringId가 아니라 roomId를 포함하도록 * refactor: 파트너가 멘토인 경우 partnerId는 mentorId로 - AS IS: 멘토/멘티 모두 partnerId가 siteUserId - TO BE: 멘티: siteUserId, 멘토: mentorId * refactor: 응답의 senderId가 mentorId/siteUserId가 되도록 * refactor: senderId에 해당하는 chatParticipant가 없을 경우 예외 처리하는 로직 추가 * refactor: 메서드명에 맞게 시그니처 변경 * refactor: getChatMessages 메서드에서 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all) * refactor: 헬퍼 메서드로 메서드 복잡성을 분산한다 * refactor: getChatPartner 메서드의 응답으로 siteUserId를 넘겨주도록 - AS IS: mentorId(mentor) / siteUserId(mentee) - TO BE: siteUserId(all)
1 parent 8de1c80 commit 6b9fb2b

File tree

8 files changed

+78
-31
lines changed

8 files changed

+78
-31
lines changed

src/main/java/com/example/solidconnection/chat/domain/ChatMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class ChatMessage extends BaseEntity {
2828
@Column(nullable = false, length = 500)
2929
private String content;
3030

31-
private long senderId;
31+
private long senderId; // chat_participant의 id
3232

3333
@ManyToOne(fetch = FetchType.LAZY)
3434
private ChatRoom chatRoom;

src/main/java/com/example/solidconnection/chat/dto/ChatMessageResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
public record ChatMessageResponse(
77
long id,
88
String content,
9-
long senderId,
9+
long senderId, // siteUserId
1010
ZonedDateTime createdAt,
1111
List<ChatAttachmentResponse> attachments
1212
) {

src/main/java/com/example/solidconnection/chat/dto/ChatParticipantResponse.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package com.example.solidconnection.chat.dto;
22

33
public record ChatParticipantResponse(
4-
long partnerId,
4+
long partnerId, // siteUserId
55
String nickname,
66
String profileUrl
77
) {

src/main/java/com/example/solidconnection/chat/service/ChatService.java

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.example.solidconnection.chat.dto.ChatMessageSendRequest;
1616
import com.example.solidconnection.chat.dto.ChatMessageSendResponse;
1717
import com.example.solidconnection.chat.dto.ChatParticipantResponse;
18+
import com.example.solidconnection.chat.dto.ChatRoomData;
1819
import com.example.solidconnection.chat.dto.ChatRoomListResponse;
1920
import com.example.solidconnection.chat.dto.ChatRoomResponse;
2021
import com.example.solidconnection.chat.repository.ChatMessageRepository;
@@ -23,11 +24,15 @@
2324
import com.example.solidconnection.chat.repository.ChatRoomRepository;
2425
import com.example.solidconnection.common.dto.SliceResponse;
2526
import com.example.solidconnection.common.exception.CustomException;
26-
import com.example.solidconnection.chat.dto.ChatRoomData;
27+
import com.example.solidconnection.mentor.repository.MentorRepository;
2728
import com.example.solidconnection.siteuser.domain.SiteUser;
2829
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
2930
import java.util.Collections;
3031
import java.util.List;
32+
import java.util.Map;
33+
import java.util.Set;
34+
import java.util.function.Function;
35+
import java.util.stream.Collectors;
3136
import org.springframework.context.annotation.Lazy;
3237
import org.springframework.data.domain.Pageable;
3338
import org.springframework.data.domain.Slice;
@@ -43,6 +48,7 @@ public class ChatService {
4348
private final ChatParticipantRepository chatParticipantRepository;
4449
private final ChatReadStatusRepository chatReadStatusRepository;
4550
private final SiteUserRepository siteUserRepository;
51+
private final MentorRepository mentorRepository;
4652

4753
private final SimpMessageSendingOperations simpMessageSendingOperations;
4854

@@ -51,12 +57,14 @@ public ChatService(ChatRoomRepository chatRoomRepository,
5157
ChatParticipantRepository chatParticipantRepository,
5258
ChatReadStatusRepository chatReadStatusRepository,
5359
SiteUserRepository siteUserRepository,
60+
MentorRepository mentorRepository,
5461
@Lazy SimpMessageSendingOperations simpMessageSendingOperations) {
5562
this.chatRoomRepository = chatRoomRepository;
5663
this.chatMessageRepository = chatMessageRepository;
5764
this.chatParticipantRepository = chatParticipantRepository;
5865
this.chatReadStatusRepository = chatReadStatusRepository;
5966
this.siteUserRepository = siteUserRepository;
67+
this.mentorRepository = mentorRepository;
6068
this.simpMessageSendingOperations = simpMessageSendingOperations;
6169
}
6270

@@ -114,20 +122,46 @@ public SliceResponse<ChatMessageResponse> getChatMessages(long siteUserId, long
114122

115123
Slice<ChatMessage> chatMessages = chatMessageRepository.findByRoomIdWithPaging(roomId, pageable);
116124

117-
List<ChatMessageResponse> content = chatMessages.getContent().stream()
118-
.map(this::toChatMessageResponse)
119-
.toList();
125+
Map<Long, ChatParticipant> participantIdToParticipant = buildParticipantIdToParticipantMap(chatMessages);
126+
List<ChatMessageResponse> content = buildChatMessageResponses(chatMessages, participantIdToParticipant);
120127

121128
return SliceResponse.of(content, chatMessages);
122129
}
123130

131+
// senderId(chatParticipantId)로 chatParticipant 맵 생성
132+
private Map<Long, ChatParticipant> buildParticipantIdToParticipantMap(Slice<ChatMessage> chatMessages) {
133+
Set<Long> participantIds = chatMessages.getContent().stream()
134+
.map(ChatMessage::getSenderId)
135+
.collect(Collectors.toSet());
136+
137+
return chatParticipantRepository.findAllById(participantIds).stream()
138+
.collect(Collectors.toMap(ChatParticipant::getId, Function.identity()));
139+
}
140+
141+
private List<ChatMessageResponse> buildChatMessageResponses(
142+
Slice<ChatMessage> chatMessages,
143+
Map<Long, ChatParticipant> participantIdToParticipant
144+
) {
145+
return chatMessages.getContent().stream()
146+
.map(message -> {
147+
ChatParticipant senderParticipant = participantIdToParticipant.get(message.getSenderId());
148+
if (senderParticipant == null) {
149+
throw new CustomException(CHAT_PARTICIPANT_NOT_FOUND);
150+
}
151+
long externalSenderId = senderParticipant.getSiteUserId();
152+
return toChatMessageResponse(message, externalSenderId);
153+
})
154+
.toList();
155+
}
156+
124157
@Transactional(readOnly = true)
125158
public ChatParticipantResponse getChatPartner(long siteUserId, Long roomId) {
126159
ChatRoom chatRoom = chatRoomRepository.findById(roomId)
127160
.orElseThrow(() -> new CustomException(INVALID_CHAT_ROOM_STATE));
128161
ChatParticipant partnerParticipant = findPartner(chatRoom, siteUserId);
129162
SiteUser siteUser = siteUserRepository.findById(partnerParticipant.getSiteUserId())
130163
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));
164+
131165
return ChatParticipantResponse.of(siteUser.getId(), siteUser.getNickname(), siteUser.getProfileImageUrl());
132166
}
133167

@@ -148,7 +182,7 @@ public void validateChatRoomParticipant(long siteUserId, long roomId) {
148182
}
149183
}
150184

151-
private ChatMessageResponse toChatMessageResponse(ChatMessage message) {
185+
private ChatMessageResponse toChatMessageResponse(ChatMessage message, long externalSenderId) {
152186
List<ChatAttachmentResponse> attachments = message.getChatAttachments().stream()
153187
.map(attachment -> ChatAttachmentResponse.of(
154188
attachment.getId(),
@@ -162,7 +196,7 @@ private ChatMessageResponse toChatMessageResponse(ChatMessage message) {
162196
return ChatMessageResponse.of(
163197
message.getId(),
164198
message.getContent(),
165-
message.getSenderId(),
199+
externalSenderId,
166200
message.getCreatedAt(),
167201
attachments
168202
);

src/main/java/com/example/solidconnection/mentor/dto/MentoringForMentorResponse.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,17 @@
66
import java.time.ZonedDateTime;
77

88
public record MentoringForMentorResponse(
9-
long mentoringId,
9+
Long roomId,
1010
String profileImageUrl,
1111
String nickname,
1212
boolean isChecked,
1313
VerifyStatus verifyStatus,
1414
ZonedDateTime createdAt
1515
) {
1616

17-
public static MentoringForMentorResponse of(Mentoring mentoring, SiteUser partner) {
17+
public static MentoringForMentorResponse of(Mentoring mentoring, SiteUser partner, Long roomId) {
1818
return new MentoringForMentorResponse(
19-
mentoring.getId(),
19+
roomId,
2020
partner.getProfileImageUrl(),
2121
partner.getNickname(),
2222
mentoring.getCheckedAtByMentor() != null,

src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import com.example.solidconnection.location.region.domain.Region;
44
import com.example.solidconnection.mentor.domain.Mentor;
5+
import java.util.List;
56
import java.util.Optional;
7+
import java.util.Set;
68
import org.springframework.data.domain.Pageable;
79
import org.springframework.data.domain.Slice;
810
import org.springframework.data.jpa.repository.JpaRepository;
@@ -23,4 +25,6 @@ public interface MentorRepository extends JpaRepository<Mentor, Long> {
2325
WHERE u.region = :region
2426
""")
2527
Slice<Mentor> findAllByRegion(@Param("region") Region region, Pageable pageable);
28+
29+
List<Mentor> findAllBySiteUserIdIn(Set<Long> siteUserIds);
2630
}

src/main/java/com/example/solidconnection/mentor/service/MentoringQueryService.java

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -121,17 +121,6 @@ public SliceResponse<MentoringForMenteeResponse> getMentoringsForMentee(
121121
return SliceResponse.of(content, mentoringSlice);
122122
}
123123

124-
// N+1 을 해결하면서 멘토링의 채팅방 정보 조회
125-
private Map<Long, Long> mapMentoringIdToChatRoomIdWithBatchQuery(List<Mentoring> mentorings) {
126-
List<Long> mentoringIds = mentorings.stream()
127-
.map(Mentoring::getId)
128-
.distinct()
129-
.toList();
130-
List<ChatRoom> chatRooms = chatRoomRepository.findAllByMentoringIdIn(mentoringIds);
131-
return chatRooms.stream()
132-
.collect(Collectors.toMap(ChatRoom::getMentoringId, ChatRoom::getId));
133-
}
134-
135124
@Transactional(readOnly = true)
136125
public SliceResponse<MentoringForMentorResponse> getMentoringsForMentor(long siteUserId, Pageable pageable) {
137126
Mentor mentor = mentorRepository.findBySiteUserId(siteUserId)
@@ -143,9 +132,15 @@ public SliceResponse<MentoringForMentorResponse> getMentoringsForMentor(long sit
143132
Mentoring::getMenteeId
144133
);
145134

135+
Map<Long, Long> mentoringIdToChatRoomId = mapMentoringIdToChatRoomIdWithBatchQuery(mentoringSlice.getContent());
136+
146137
List<MentoringForMentorResponse> content = new ArrayList<>();
147138
for (Mentoring mentoring : mentoringSlice) {
148-
content.add(MentoringForMentorResponse.of(mentoring, mentoringToPartnerUser.get(mentoring)));
139+
content.add(MentoringForMentorResponse.of(
140+
mentoring,
141+
mentoringToPartnerUser.get(mentoring),
142+
mentoringIdToChatRoomId.get(mentoring.getId())
143+
));
149144
}
150145

151146
return SliceResponse.of(content, mentoringSlice);
@@ -168,4 +163,15 @@ private Map<Mentoring, SiteUser> mapMentoringToPartnerUserWithBatchQuery(
168163
mentoring -> partnerIdToPartnerUsermap.get(getPartnerId.apply(mentoring))
169164
));
170165
}
166+
167+
// N+1 을 해결하면서 멘토링의 채팅방 정보 조회
168+
private Map<Long, Long> mapMentoringIdToChatRoomIdWithBatchQuery(List<Mentoring> mentorings) {
169+
List<Long> mentoringIds = mentorings.stream()
170+
.map(Mentoring::getId)
171+
.distinct()
172+
.toList();
173+
List<ChatRoom> chatRooms = chatRoomRepository.findAllByMentoringIdIn(mentoringIds);
174+
return chatRooms.stream()
175+
.collect(Collectors.toMap(ChatRoom::getMentoringId, ChatRoom::getId));
176+
}
171177
}

src/test/java/com/example/solidconnection/mentor/service/MentoringQueryServiceTest.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,18 @@ class 멘토의_멘토링_목록_조회_테스트 {
9797
Mentoring mentoring2 = mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser2.getId());
9898
Mentoring mentoring3 = mentoringFixture.거절된_멘토링(mentor1.getId(), menteeUser3.getId());
9999

100+
ChatRoom chatRoom2 = chatRoomFixture.멘토링_채팅방(mentoring2.getId());
101+
100102
// when
101103
SliceResponse<MentoringForMentorResponse> response = mentoringQueryService.getMentoringsForMentor(mentorUser1.getId(), pageable);
102104

103105
// then
104-
assertThat(response.content()).extracting(MentoringForMentorResponse::mentoringId)
106+
assertThat(response.content())
107+
.extracting(MentoringForMentorResponse::verifyStatus, MentoringForMentorResponse::roomId)
105108
.containsExactlyInAnyOrder(
106-
mentoring1.getId(),
107-
mentoring2.getId(),
108-
mentoring3.getId()
109+
tuple(VerifyStatus.PENDING, null),
110+
tuple(VerifyStatus.APPROVED, chatRoom2.getId()),
111+
tuple(VerifyStatus.REJECTED, null)
109112
);
110113
}
111114

@@ -137,10 +140,10 @@ class 멘토의_멘토링_목록_조회_테스트 {
137140

138141
// then
139142
assertThat(response.content())
140-
.extracting(MentoringForMentorResponse::mentoringId, MentoringForMentorResponse::isChecked)
143+
.extracting(MentoringForMentorResponse::nickname, MentoringForMentorResponse::isChecked)
141144
.containsExactlyInAnyOrder(
142-
tuple(mentoring1.getId(), false),
143-
tuple(mentoring2.getId(), true)
145+
tuple(menteeUser1.getNickname(), false),
146+
tuple(menteeUser2.getNickname(), true)
144147
);
145148
}
146149

0 commit comments

Comments
 (0)