-
Notifications
You must be signed in to change notification settings - Fork 0
✨Feat: 단체채팅(JOIN, LEAVE는 아직 X) #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.be.sportizebe.domain.chat.dto; | ||
|
|
||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Getter | ||
| @NoArgsConstructor | ||
| public class ChatPresenceRequest { | ||
| private Long roomId; | ||
| private Long userId; | ||
| private String nickname; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| package com.be.sportizebe.domain.chat.websocket; | ||
|
|
||
| import java.util.concurrent.ConcurrentHashMap; | ||
| import java.util.concurrent.ConcurrentMap; | ||
|
|
||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class ChatSessionRegistry { | ||
|
|
||
| public record Presence(Long roomId, Long userId, String nickname) {} | ||
|
|
||
| private final ConcurrentMap<String, Presence> store = new ConcurrentHashMap<>(); | ||
|
|
||
| public void put(String sessionId, Long roomId, Long userId, String nickname) { | ||
| store.put(sessionId, new Presence(roomId, userId, nickname)); | ||
| } | ||
|
|
||
| public Presence remove(String sessionId) { | ||
| return store.remove(sessionId); | ||
| } | ||
|
|
||
| public Presence get(String sessionId) { | ||
| return store.get(sessionId); | ||
| } | ||
| } | ||
|
Comment on lines
+8
to
+26
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 비정상 연결 해제 시 세션 정리 필요 사용자가 🛠️ 제안하는 수정 - WebSocket 이벤트 리스너 추가별도의 이벤트 리스너 클래스를 생성하거나 기존 설정에 추가: `@Component`
`@RequiredArgsConstructor`
public class WebSocketEventListener {
private final ChatSessionRegistry registry;
private final ChatMessageService chatMessageService;
private final ChatRoomService chatRoomService;
private final SimpMessagingTemplate messagingTemplate;
`@EventListener`
public void handleSessionDisconnect(SessionDisconnectEvent event) {
String sessionId = event.getSessionId();
ChatSessionRegistry.Presence presence = registry.remove(sessionId);
if (presence != null) {
// 자동 퇴장 메시지 브로드캐스트
ChatRoom room = chatRoomService.getOrThrow(presence.roomId());
String content = presence.nickname() + " 님이 퇴장했습니다.";
ChatMessage msg = chatMessageService.saveJoinLeave(
room, ChatMessage.Type.LEAVE,
presence.userId(), presence.nickname(), content
);
messagingTemplate.convertAndSend(
"/topic/chat/rooms/" + presence.roomId(),
ChatMessageResponse.from(msg)
);
}
}
}🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| package com.be.sportizebe.domain.chat.websocket; | ||
|
|
||
| import com.be.sportizebe.domain.chat.dto.ChatPresenceRequest; | ||
| import com.be.sportizebe.domain.chat.dto.response.ChatMessageResponse; | ||
| import com.be.sportizebe.domain.chat.dto.request.ChatSendRequest; | ||
| import com.be.sportizebe.domain.chat.entity.ChatMessage; | ||
|
|
@@ -8,6 +8,7 @@ | |
| import com.be.sportizebe.domain.chat.service.ChatRoomService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.messaging.handler.annotation.MessageMapping; | ||
| import org.springframework.messaging.simp.SimpMessageHeaderAccessor; | ||
| import org.springframework.messaging.simp.SimpMessagingTemplate; | ||
| import org.springframework.stereotype.Controller; | ||
|
|
||
|
|
@@ -17,6 +18,7 @@ public class ChatStompController { | |
| private final ChatMessageService chatMessageService; | ||
| private final ChatRoomService chatRoomService; // ✅ 추가 | ||
| private final SimpMessagingTemplate messagingTemplate; | ||
| private final ChatSessionRegistry registry; | ||
|
|
||
| @MessageMapping("/chat.send") | ||
| public void send(ChatSendRequest req){ | ||
|
|
@@ -33,4 +35,43 @@ public void send(ChatSendRequest req){ | |
| ChatMessageResponse.from(saved) | ||
| ); | ||
| } | ||
|
|
||
| @MessageMapping("/chat.join") | ||
| public void join(ChatPresenceRequest req, SimpMessageHeaderAccessor headerAccessor) { | ||
| String sessionId = headerAccessor.getSessionId(); | ||
|
|
||
| ChatRoom room = chatRoomService.getOrThrow(req.getRoomId()); | ||
|
|
||
| // 1) 세션에 “이 탭이 어느 방에 있는지” 저장 | ||
| registry.put(sessionId, req.getRoomId(), req.getUserId(), req.getNickname()); | ||
|
|
||
| // 2) 시스템 메시지 생성 + (옵션) DB 저장 | ||
| String content = req.getNickname() + " 님이 입장했습니다."; | ||
| ChatMessage msg = chatMessageService.saveJoinLeave( | ||
| room, | ||
| ChatMessage.Type.JOIN, | ||
| req.getUserId(), | ||
| req.getNickname(), | ||
| content | ||
| ); | ||
| // 3) 브로드캐스트 | ||
| messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), msg); | ||
|
Comment on lines
+57
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
🐛 제안하는 수정 // 3) 브로드캐스트
- messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), msg);
+ messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), ChatMessageResponse.from(msg));🤖 Prompt for AI Agents |
||
| } | ||
| @MessageMapping("/chat.leave") | ||
| public void leave(ChatPresenceRequest req, SimpMessageHeaderAccessor headerAccessor) { | ||
| String sessionId = headerAccessor.getSessionId(); | ||
|
|
||
| ChatRoom room = chatRoomService.getOrThrow(req.getRoomId()); | ||
| registry.remove(sessionId); // 명시적으로 나가면 제거 | ||
|
|
||
| String content = req.getNickname() + " 님이 퇴장했습니다."; | ||
| ChatMessage msg = chatMessageService.saveJoinLeave( | ||
| room, | ||
| ChatMessage.Type.LEAVE, | ||
| req.getUserId(), | ||
| req.getNickname(), | ||
| content | ||
| ); | ||
| messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), msg); | ||
|
Comment on lines
+74
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 동일한 엔티티 직접 브로드캐스트 문제
🐛 제안하는 수정- messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), msg);
+ messagingTemplate.convertAndSend("/topic/chat/rooms/" + req.getRoomId(), ChatMessageResponse.from(msg));🤖 Prompt for AI Agents |
||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: Sportize/be
Length of output: 660
🏁 Script executed:
Repository: Sportize/be
Length of output: 1095
saveSystem메서드는 사용되지 않는 데드 코드입니다. 제거 또는 용도 명확히 필요합니다.이 메서드는 코드베이스 전체에서 호출되지 않습니다. 또한 메서드 이름과 주석에서 "시스템 메시지 전용"이라고 명시하지만,
type파라미터는JOIN/LEAVE/SYSTEM을 모두 받을 수 있어 목적이 불명확합니다.saveJoinLeave메서드가JOIN/LEAVE유형을 처리하므로,saveSystem은 향후 순수SYSTEM타입 전용으로 예약된 것인지, 아니면 불필요한 코드인지 확인하여 제거하거나 명확히 하세요.🤖 Prompt for AI Agents