ㅁ 문제 발생
- user1과 user2가 채팅방 1에 접속해서 서로 메세지를 보냈다. 지금은 정상적으로 메세지가 잘 보인다.
- 문제는 user1이 다른 채팅방을 갔다가 다시 이전에 있던 채팅방으로 돌아와서 메세지를 보내면,
계속 채팅방 1에 접속해있던 user2는 그 메세지가 보이지만 user1은 자기 메세지도 상대가 보낸 메세지도 화면에 보이지 않는다.
ㅁ 원인
- 맨 처음에는 채팅방 1에 연결되어 있는 세션이 2개다.
- user1이 다른 방에 갔다가 다시 채팅방 1로 돌아와서 메세지를 보낸 경우, 현재 채팅방 1에 연결되어 있는 세션이 1개다.
user2의 세션은 남아있지만 user1의 세션은 제거되고 다시 추가가 되지 않고 있다.
ㅁ 해결
@RequiredArgsConstructor
@Component // serlvet-context.xml에 빈 등록 구문 대체
@Slf4j // 로그 출력을 위한 롬복 어노테이션
public class ChatEchoHandler extends TextWebSocketHandler {
// 각 채팅방의 세션 리스트를 관리하는 맵 (roomNo, userId)
private Map<String, Map<String, WebSocketSession>> chatRooms = new ConcurrentHashMap<>();
// 각 채팅방에 사용자가 참여하고 있는지 여부를 flag로 저장하는 맵 (roomNo, userId)
private Map<String, Map<String, Boolean>> userStatusMap = new ConcurrentHashMap<>();
private final ChatService chatService;
/**
* 웹소켓에 클라이언트가 연결되었을 때 처리할 내용 정의
* @param session - 현재 웹소켓과 연결된 클라이언트 객체 (채팅방에 접속된 클라이언트)
*/
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
String roomNo = session.getUri().getQuery().split("roomNo=")[1];
String userId = ((UserDto) session.getAttributes().get("loginUser")).getUserId();
// log.debug("session Attributes 목록: {}", session.getAttributes()); // {sessionId=xxxx, loginUser=MemberDto객체}
session.getAttributes().put("roomNo", roomNo); // roomNo 저장
session.getAttributes().put("userId", userId); // userId 저장
log.debug("{} --> User {} has entered room {}", "ChatEchoHandler의 afterConnectionEstablished 실행됨", userId, roomNo);
// 현재 roomNo를 key값으로 가지는 List<WebSocketSession>이 없으면 생성한다.
if ( !chatRooms.containsKey(roomNo) ) {
chatRooms.put(roomNo, new ConcurrentHashMap<>() );
}
// 현재 roomNo를 key값으로 가지는 Map<String, Boolean>이 없으면 생성한다.
if ( !userStatusMap.containsKey(roomNo) ) {
userStatusMap.put(roomNo, new ConcurrentHashMap<>() );
}
// 사용자가 현재 roomNo 채팅방에 없었거나 퇴장상태인 경우에는 입장처리한다.
if ( !userStatusMap.get(roomNo).containsKey(userId) || userStatusMap.get(roomNo).get(userId) == false ) {
userStatusMap.get(roomNo).put(userId, true); // 이 userId를 현재 roomNo에 입장처리. (Map에 이미 있는 키로 put을 호출하면 기존 키에 매핑된 값이 새로운 값으로 덮어쓰기 됨)
log.debug("{} 유저가 {} 채팅방 번호에 입장처리됨.", userId, roomNo);
chatRooms.get(roomNo).put(userId, session); // 현재 roomNo를 key로 List<WebSocketSession>에 현재 클라이언트 session을 추가한다.
// 입장 메시지 생성 및 전송
String msg = "entry|" + userId + " 님이 " + roomNo + " 채팅방에 입장하였습니다.";
log.debug("입장 메세지 : {}\n", msg);
for (WebSocketSession sss : chatRooms.get(roomNo).values() ) {
sss.sendMessage(new TextMessage(msg));
}
// .values()는 Java의 Map 인터페이스에서 제공하는 메서드로 Map에 저장된 값들(value)만을 Collection 형태로 반환합니다. 즉, 키(key)에 상관없이 Map에 저장된 값들을 한꺼번에 처리하고 싶을 때 사용됩니다.
// Map<K, V>에서 .values()를 호출하면 V 타입의 모든 값(value)이 포함된 Collection<V> 객체를 반환합니다. 반환된 Collection은 Iterable 인터페이스를 구현하고 있으므로, for-each 루프에서 사용할 수 있습니다.
}
// 클라이언트의 session이 현재 roomNo의 List<WebSocketSession>에 없다면 추가한다.
if( chatRooms.get(roomNo).get(userId) == null ) {
chatRooms.get(roomNo).put(userId, session);
}
}
- chatRooms.get(roomNo).get(userId)가 null이면 추가한다.
- 나갔다 다시 와도 잘 된다.
- user001의 세션이 잘 들어갔다.
'프로젝트 > 파이널프로젝트-대학 행정 그룹웨어' 카테고리의 다른 글
coolsms로 예약 신청 결과 문자로 전송하기 (0) | 2024.11.30 |
---|---|
[문제] 예약 내역에서 비품이 안 보임 (0) | 2024.11.27 |
[문제] 1대1 채팅방 상대의 사번이 보이지 않고 내 사번이 보임 (0) | 2024.11.14 |
파이널 프로젝트 받아오기 (0) | 2024.11.08 |
Spring Boot 프로젝트에 Swagger 적용하기 (1) | 2024.11.07 |