Skip to content

Commit 9b3f612

Browse files
Soundbar91soundbar91
andauthored
refactor: chat 도메인 리팩토링 (#89)
* refactor: 채팅방 생성 유효성 검증 로직 ChatRoom으로 이동 * refactor: 동아리 회장 변수 네이밍 수정 * feat: chat_room 테이블에 마지막으로 보낸 메시지 관련 컬럼 추가 * refactor: 채팅방 참여 인원 검증 메소드 네이밍 수정 * feat: 채팅 메시지를 보냈을 때, chat_room 테이블에 있는 채팅 메시지 관련 컬럼 업데이트 로직 추가 * refactor: ChatMessage 변수 인라인 * refactor: ChatMessage 변수 네이밍 수정 * refactor: getLastMessage 메소드 삭제 및 관련 메소드 내부 로직 수정 * refactor: 채팅방 참여자 유효성 검증 로직을 ChatRoom으로 이동 * refactor: 채팅방 리스트를 조회할 때, LEFT JOIN으로 가져오는 메시지 로직 삭제 및 개선 * refactor: 읽지 않는 메시지 개수 조회 메소드 네이밍 수정 * refactor: 읽지 않는 메시지 리스트 조회 메소드 네이밍 수정 * fix: 채팅방 정렬 기준을 마지막으로 보낸 메시지 시각으로 수정 * refactor: POST /chats/rooms 요청 DTO 네이밍 수정 * fix: ChatRoom의 OneToMany로 관리되는 ChatMessage 삭제 * chore: ChatRoom 클래스 내부 메소드 순서 수정 * fix: ChatRoom getter 메소드 삭제 * fix: ChatMessage isSentBy 반환형 수정 * chore: 코드 개행 * chore: ChatRoomService 클래스 네이밍 수정 * chore: ChatMessage save 메소드 순서 수정 * chore: 코드 개행 * refactor: 채팅방 정렬 기준 추가 --------- Co-authored-by: soundbar91 <soundbar91@jinhakapply.com>
1 parent 6513ea0 commit 9b3f612

File tree

11 files changed

+130
-78
lines changed

11 files changed

+130
-78
lines changed

src/main/java/gg/agit/konect/domain/chat/controller/ChatApi.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import gg.agit.konect.domain.chat.dto.ChatMessagesResponse;
1414
import gg.agit.konect.domain.chat.dto.ChatRoomResponse;
1515
import gg.agit.konect.domain.chat.dto.ChatRoomsResponse;
16-
import gg.agit.konect.domain.chat.dto.CreateChatRoomRequest;
16+
import gg.agit.konect.domain.chat.dto.ChatRoomCreateRequest;
1717
import gg.agit.konect.global.auth.annotation.UserId;
1818
import io.swagger.v3.oas.annotations.Operation;
1919
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -38,7 +38,7 @@ public interface ChatApi {
3838
""")
3939
@PostMapping("/rooms")
4040
ResponseEntity<ChatRoomResponse> createOrGetChatRoom(
41-
@Valid @RequestBody CreateChatRoomRequest request,
41+
@Valid @RequestBody ChatRoomCreateRequest request,
4242
@UserId Integer userId
4343
);
4444

@@ -52,7 +52,9 @@ ResponseEntity<ChatRoomResponse> createOrGetChatRoom(
5252
- 최근 메시지가 있는 순서대로 정렬됩니다.
5353
""")
5454
@GetMapping("/rooms")
55-
ResponseEntity<ChatRoomsResponse> getChatRooms(@UserId Integer userId);
55+
ResponseEntity<ChatRoomsResponse> getChatRooms(
56+
@UserId Integer userId
57+
);
5658

5759
@Operation(summary = "문의하기 메시지 리스트를 조회한다.", description = """
5860
## 설명

src/main/java/gg/agit/konect/domain/chat/controller/ChatController.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
import gg.agit.konect.domain.chat.dto.ChatMessagesResponse;
1515
import gg.agit.konect.domain.chat.dto.ChatRoomResponse;
1616
import gg.agit.konect.domain.chat.dto.ChatRoomsResponse;
17-
import gg.agit.konect.domain.chat.dto.CreateChatRoomRequest;
18-
import gg.agit.konect.domain.chat.service.ChatRoomService;
17+
import gg.agit.konect.domain.chat.dto.ChatRoomCreateRequest;
18+
import gg.agit.konect.domain.chat.service.ChatService;
1919
import gg.agit.konect.global.auth.annotation.UserId;
2020
import jakarta.validation.Valid;
2121
import lombok.RequiredArgsConstructor;
@@ -25,20 +25,22 @@
2525
@RequestMapping("/chats")
2626
public class ChatController implements ChatApi {
2727

28-
private final ChatRoomService chatRoomService;
28+
private final ChatService chatService;
2929

3030
@PostMapping("/rooms")
3131
public ResponseEntity<ChatRoomResponse> createOrGetChatRoom(
32-
@Valid @RequestBody CreateChatRoomRequest request,
32+
@Valid @RequestBody ChatRoomCreateRequest request,
3333
@UserId Integer userId
3434
) {
35-
ChatRoomResponse response = chatRoomService.createOrGetChatRoom(userId, request);
35+
ChatRoomResponse response = chatService.createOrGetChatRoom(userId, request);
3636
return ResponseEntity.ok(response);
3737
}
3838

3939
@GetMapping("/rooms")
40-
public ResponseEntity<ChatRoomsResponse> getChatRooms(@UserId Integer userId) {
41-
ChatRoomsResponse response = chatRoomService.getChatRooms(userId);
40+
public ResponseEntity<ChatRoomsResponse> getChatRooms(
41+
@UserId Integer userId
42+
) {
43+
ChatRoomsResponse response = chatService.getChatRooms(userId);
4244
return ResponseEntity.ok(response);
4345
}
4446

@@ -49,7 +51,7 @@ public ResponseEntity<ChatMessagesResponse> getChatRoomMessages(
4951
@PathVariable(value = "chatRoomId") Integer chatRoomId,
5052
@UserId Integer userId
5153
) {
52-
ChatMessagesResponse response = chatRoomService.getChatRoomMessages(userId, chatRoomId, page, limit);
54+
ChatMessagesResponse response = chatService.getChatRoomMessages(userId, chatRoomId, page, limit);
5355
return ResponseEntity.ok(response);
5456
}
5557

@@ -59,7 +61,7 @@ public ResponseEntity<ChatMessageResponse> sendMessage(
5961
@Valid @RequestBody ChatMessageSendRequest request,
6062
@UserId Integer userId
6163
) {
62-
ChatMessageResponse response = chatRoomService.sendMessage(userId, chatRoomId, request);
64+
ChatMessageResponse response = chatService.sendMessage(userId, chatRoomId, request);
6365
return ResponseEntity.ok(response);
6466
}
6567
}

src/main/java/gg/agit/konect/domain/chat/dto/CreateChatRoomRequest.java renamed to src/main/java/gg/agit/konect/domain/chat/dto/ChatRoomCreateRequest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import io.swagger.v3.oas.annotations.media.Schema;
66
import jakarta.validation.constraints.NotNull;
77

8-
public record CreateChatRoomRequest(
8+
public record ChatRoomCreateRequest(
99
@NotNull(message = "동아리 ID는 필수입니다.")
1010
@Schema(description = "동아리 ID", example = "1", requiredMode = REQUIRED)
1111
Integer clubId

src/main/java/gg/agit/konect/domain/chat/dto/ChatRoomsResponse.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.time.LocalDateTime;
77
import java.util.List;
8+
import java.util.Map;
89

910
import com.fasterxml.jackson.annotation.JsonFormat;
1011

@@ -36,23 +37,27 @@ public record InnerChatRoomResponse(
3637
@Schema(description = "읽지 않은 메시지 개수", example = "12", requiredMode = REQUIRED)
3738
Integer unreadCount
3839
) {
39-
public static InnerChatRoomResponse from(ChatRoom chatRoom, User currentUser) {
40+
public static InnerChatRoomResponse from(
41+
ChatRoom chatRoom, User currentUser, Map<Integer, Integer> unreadCountMap
42+
) {
4043
User chatPartner = chatRoom.getChatPartner(currentUser);
4144

4245
return new InnerChatRoomResponse(
4346
chatRoom.getId(),
4447
chatPartner.getName(),
4548
chatPartner.getImageUrl(),
4649
chatRoom.getLastMessageContent(),
47-
chatRoom.getLastMessageTime(),
48-
chatRoom.getUnreadCount(currentUser.getId())
50+
chatRoom.getLastMessageSentAt(),
51+
unreadCountMap.getOrDefault(chatRoom.getId(), 0)
4952
);
5053
}
5154
}
5255

53-
public static ChatRoomsResponse from(List<ChatRoom> chatRooms, User currentUser) {
56+
public static ChatRoomsResponse from(
57+
List<ChatRoom> chatRooms, User currentUser, Map<Integer, Integer> unreadCountMap
58+
) {
5459
return new ChatRoomsResponse(chatRooms.stream()
55-
.map(chatRoom -> InnerChatRoomResponse.from(chatRoom, currentUser))
60+
.map(chatRoom -> InnerChatRoomResponse.from(chatRoom, currentUser, unreadCountMap))
5661
.toList());
5762
}
5863
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package gg.agit.konect.domain.chat.dto;
2+
3+
public record UnreadMessageCount(
4+
Integer chatRoomId,
5+
Long unreadCount
6+
) {
7+
8+
}

src/main/java/gg/agit/konect/domain/chat/model/ChatMessage.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static ChatMessage of(ChatRoom chatRoom, User sender, User receiver, Stri
7676
.build();
7777
}
7878

79-
public Boolean isSentBy(Integer userId) {
79+
public boolean isSentBy(Integer userId) {
8080
return sender.getId().equals(userId);
8181
}
8282

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,22 @@
11
package gg.agit.konect.domain.chat.model;
22

3+
import static gg.agit.konect.global.code.ApiResponseCode.CANNOT_CREATE_CHAT_ROOM_WITH_SELF;
4+
import static gg.agit.konect.global.code.ApiResponseCode.FORBIDDEN_CHAT_ROOM_ACCESS;
35
import static jakarta.persistence.FetchType.LAZY;
46
import static jakarta.persistence.GenerationType.IDENTITY;
57
import static lombok.AccessLevel.PROTECTED;
68

79
import java.time.LocalDateTime;
8-
import java.util.ArrayList;
9-
import java.util.Comparator;
10-
import java.util.List;
1110

1211
import gg.agit.konect.domain.user.model.User;
12+
import gg.agit.konect.global.exception.CustomException;
1313
import gg.agit.konect.global.model.BaseEntity;
1414
import jakarta.persistence.Column;
1515
import jakarta.persistence.Entity;
1616
import jakarta.persistence.GeneratedValue;
1717
import jakarta.persistence.Id;
1818
import jakarta.persistence.JoinColumn;
1919
import jakarta.persistence.ManyToOne;
20-
import jakarta.persistence.OneToMany;
2120
import jakarta.persistence.Table;
2221
import lombok.Builder;
2322
import lombok.Getter;
@@ -34,6 +33,12 @@ public class ChatRoom extends BaseEntity {
3433
@Column(name = "id", nullable = false, updatable = false, unique = true)
3534
private Integer id;
3635

36+
@Column(name = "last_message_content", columnDefinition = "TEXT")
37+
private String lastMessageContent;
38+
39+
@Column(name = "last_message_sent_at")
40+
private LocalDateTime lastMessageSentAt;
41+
3742
@ManyToOne(fetch = LAZY)
3843
@JoinColumn(name = "sender_id")
3944
private User sender;
@@ -42,9 +47,6 @@ public class ChatRoom extends BaseEntity {
4247
@JoinColumn(name = "receiver_id")
4348
private User receiver;
4449

45-
@OneToMany(mappedBy = "chatRoom", fetch = LAZY)
46-
private List<ChatMessage> chatMessages = new ArrayList<>();
47-
4850
@Builder
4951
private ChatRoom(Integer id, User sender, User receiver) {
5052
this.id = id;
@@ -53,40 +55,35 @@ private ChatRoom(Integer id, User sender, User receiver) {
5355
}
5456

5557
public static ChatRoom of(User sender, User receiver) {
58+
validateIsNotSameParticipant(sender, receiver);
5659
return ChatRoom.builder()
5760
.sender(sender)
5861
.receiver(receiver)
5962
.build();
6063
}
6164

62-
public User getChatPartner(User currentUser) {
63-
return sender.getId().equals(currentUser.getId()) ? receiver : sender;
65+
public static void validateIsNotSameParticipant(User sender, User receiver) {
66+
if (sender.getId().equals(receiver.getId())) {
67+
throw CustomException.of(CANNOT_CREATE_CHAT_ROOM_WITH_SELF);
68+
}
6469
}
6570

66-
public boolean isParticipant(Integer userId) {
67-
return sender.getId().equals(userId) || receiver.getId().equals(userId);
71+
public void validateIsParticipant(Integer userId) {
72+
if (!isParticipant(userId)) {
73+
throw CustomException.of(FORBIDDEN_CHAT_ROOM_ACCESS);
74+
}
6875
}
6976

70-
public ChatMessage getLastMessage() {
71-
return chatMessages.stream()
72-
.max(Comparator.comparing(BaseEntity::getCreatedAt))
73-
.orElse(null);
74-
}
75-
76-
public String getLastMessageContent() {
77-
ChatMessage lastMessage = getLastMessage();
78-
return lastMessage != null ? lastMessage.getContent() : null;
77+
public boolean isParticipant(Integer userId) {
78+
return sender.getId().equals(userId) || receiver.getId().equals(userId);
7979
}
8080

81-
public LocalDateTime getLastMessageTime() {
82-
ChatMessage lastMessage = getLastMessage();
83-
return lastMessage != null ? lastMessage.getCreatedAt() : null;
81+
public User getChatPartner(User currentUser) {
82+
return sender.getId().equals(currentUser.getId()) ? receiver : sender;
8483
}
8584

86-
public Integer getUnreadCount(Integer userId) {
87-
return (int)chatMessages.stream()
88-
.filter(message -> message.getReceiver().getId().equals(userId))
89-
.filter(message -> !message.getIsRead())
90-
.count();
85+
public void updateLastMessage(String lastMessageContent, LocalDateTime lastMessageSentAt) {
86+
this.lastMessageContent = lastMessageContent;
87+
this.lastMessageSentAt = lastMessageSentAt;
9188
}
9289
}

src/main/java/gg/agit/konect/domain/chat/repository/ChatMessageRepository.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,29 @@
99
import org.springframework.data.repository.Repository;
1010
import org.springframework.data.repository.query.Param;
1111

12+
import gg.agit.konect.domain.chat.dto.UnreadMessageCount;
1213
import gg.agit.konect.domain.chat.model.ChatMessage;
1314

1415
public interface ChatMessageRepository extends Repository<ChatMessage, Integer> {
1516

1617
ChatMessage save(ChatMessage chatMessage);
1718

19+
@Query("""
20+
SELECT new gg.agit.konect.domain.chat.dto.UnreadMessageCount(
21+
cm.chatRoom.id,
22+
COUNT(cm)
23+
)
24+
FROM ChatMessage cm
25+
WHERE cm.chatRoom.id IN :chatRoomIds
26+
AND cm.receiver.id = :receiverId
27+
AND cm.isRead = false
28+
GROUP BY cm.chatRoom.id
29+
""")
30+
List<UnreadMessageCount> countUnreadMessagesByChatRoomIdsAndUserId(
31+
@Param("chatRoomIds") List<Integer> chatRoomIds,
32+
@Param("receiverId") Integer receiverId
33+
);
34+
1835
@Query("""
1936
SELECT cm
2037
FROM ChatMessage cm
@@ -31,7 +48,7 @@ public interface ChatMessageRepository extends Repository<ChatMessage, Integer>
3148
AND cm.receiver.id = :receiverId
3249
AND cm.isRead = false
3350
""")
34-
List<ChatMessage> findUnreadMessages(
51+
List<ChatMessage> findUnreadMessagesByChatRoomIdAndUserId(
3552
@Param("chatRoomId") Integer chatRoomId,
3653
@Param("receiverId") Integer receiverId
3754
);

src/main/java/gg/agit/konect/domain/chat/repository/ChatRoomRepository.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,8 @@ public interface ChatRoomRepository extends Repository<ChatRoom, Integer> {
1919
FROM ChatRoom cr
2020
JOIN FETCH cr.sender
2121
JOIN FETCH cr.receiver
22-
LEFT JOIN FETCH cr.chatMessages
2322
WHERE cr.sender.id = :userId OR cr.receiver.id = :userId
24-
ORDER BY cr.updatedAt DESC
23+
ORDER BY cr.lastMessageSentAt DESC NULLS LAST, cr.id
2524
""")
2625
List<ChatRoom> findByUserId(@Param("userId") Integer userId);
2726

0 commit comments

Comments
 (0)