
채팅 안읽음 처리
- 채팅방 별 사용자가 읽지 않은 개수를 목록에 출력
- 전송한 사용자는 메시지에 대해 읽음 처리가 바로 가능해야 함
- 그룹 채팅방은 속한 사용자가 보낸 메시지 개수를 전부 확인 해야 함
채팅 안읽음 개수
- 사용자가 페이지에 진입과 동시에 채팅방 목록에 해당 안읽음 개수를 검색
<select id="getUnreadCounts" parameterType="java.lang.Long" resultType="java.util.Map">
SELECT COUNT(cm.chat_message_no) AS unread_count, cm.chat_room_no
FROM fl_chat_message cm
LEFT JOIN fl_chat_read_status cr ON cm.chat_message_no = cr.chat_message_no AND cr.member_no = #{memberNo}
JOIN fl_chat_member ctm ON cm.chat_room_no = ctm.chat_room_no
WHERE cr.chat_read_no IS NULL
AND cm.chat_room_no IS NOT NULL
AND ctm.member_no = #{memberNo}
AND cm.chat_message_create_date >= ctm.chat_member_join_date AND cm.chat_sender_no NOT IN (0)
GROUP BY cm.chat_room_no;
</select>
- 위의 쿼리문을 통해 현재 사용자의 번호를 가지고 채팅방 별 안읽은 개수를 모두 체크하여 서비스쪽으로 값을 넘김
- Group By를 통해 같은 채팅방 번호끼리 개수를 확인 가능
실시간 반영
- 페이지 진입 후, 실시간으로 보낸 메시지 개수 또한 증가 시켜야 함
- 같은 방 사용자가 메시지를 전송과 동시에 실시간으로 같은 방 사용자들에게 안읽음 개수를 증가시켜 일괄 목록에 표현하도록 구현
채팅 읽음 처리 디비
//채팅 읽음 디비
CREATE TABLE fl_chat_read_status (
chat_read_no INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT COMMENT '읽음 상태 번호',
chat_message_no INT UNSIGNED NOT NULL COMMENT '메시지 번호',
member_no INT UNSIGNED NOT NULL COMMENT '사원 번호',
chat_read_date DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '읽은 시간',
CONSTRAINT chat_read_message_no_fk
FOREIGN KEY (chat_message_no)
REFERENCES fl_chat_message(chat_message_no)
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT chat_read_emp_no_fk
FOREIGN KEY (member_no)
REFERENCES fl_member(member_no)
ON DELETE CASCADE
ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT '읽음 상태';
//발신자 채팅 읽음 트리거
DELIMITER //
CREATE TRIGGER after_chat_message_insert
AFTER INSERT ON fl_chat_message
FOR EACH ROW
BEGIN
IF NEW.chat_sender_no <> 0 THEN
INSERT INTO fl_chat_read_status (chat_message_no, member_no, chat_read_date)
VALUES (NEW.chat_message_no, NEW.chat_sender_no, CURRENT_TIMESTAMP);
END IF;
END;
//
DELIMITER ;
- 메시지 전송과 동시에 해당 사용자의 번호와 메시지 번호를 가지고 읽음 테이블에 값을 입력
- 이를 통해 발신자는 읽음 처리가 동시에 가능
채팅방 진입 시 읽음 처리
- 채팅방 진입 시, 읽지 않은 메시지를 일괄 읽음 처리하고 개수를 차감
- 채팅방 번호와 현재 사용자 번호, 메시지 번호를 지니고 채팅 읽음 테이블에 값을 INSERT하여 읽음 처리 진행
// 읽음 처리(js)
function markAllMessagesAsRead(chatRoomNo) {
const message = {
type: 'markAsRead',
chatRoomNo: chatRoomNo,
currentMember: currentMember
};
socket.send(JSON.stringify(message));
}
----------------------------------------------------------------------------------------------
//채팅 읽음 처리(socket)
private void handleChatRead(Map<String, Object> jsonMap, WebSocketSession session ,String type) throws Exception {
Long currentMemberNo = Long.parseLong((String) jsonMap.get("currentMember"));
Long roomNo = ((Number) jsonMap.get("chatRoomNo")).longValue();
List<Long> messageNo = chatMessageService.markMessagesAsReadForChatRoom(currentMemberNo, roomNo);
if (!messageNo.isEmpty()) {
for (Long i : messageNo) {
ChatReadDto chatReadDto = new ChatReadDto();
chatReadDto.setMember_no(currentMemberNo);
chatReadDto.setChat_message_no(i);
chatMessageService.insertReadStatus(chatReadDto);
}
}
Map<String, Object> response = new HashMap<>();
response.put("type", "updateUnreadCount");
response.put("chatRoomNo", roomNo);
response.put("unreadCount", 0);
session.sendMessage(new TextMessage(new ObjectMapper().writeValueAsString(response)));
}
- 해당 채팅방 목록을 클릭과 동시에 실시간으로 웹소켓으로 해당 정보를 가지고 감
- 웹소켓 핸들러에서 읽음 처리 메소드로 이동
- 해당 메소드에서 안읽음 메시지를 모두 조회
- 조회한 메시지 번호와 사용자 번호를 가지고 읽음 처리 디비에 값 INSERT
채팅방 이용 시, 개수 증가 제한
- 현재 채팅방을 이용하고 , 실시간 소통 중이라면 바로바로 확인 처리를 구성
- 보냄과 동시에 사용자에게 해당 정보가 도착하고 그 채팅방 번호와 사용자가 이용 중인 채팅방 번호가 동일하면 디비에 읽음 처리 진행
- 전역 변수로 채팅방 번호를 가지고 있다가 동작이 변화하면 이를 판단하여 진행
트러블 슈팅
- 발신자의 읽음 처리를 고민하지 않고, 디비를 설계했음
- 보낸 사용자도 읽음 개수가 실시간 반영된다는 점을 깨닫고 동시에 읽음 처리를 서비스에서 진행할까 고민
- 하지만 구조상 너무 비효율적인 작업이라 생각함
- 디비에 트리거를 추가해서 바로 읽음 처리될 수 있도록 구성해야 겠다고 생각
- 위처럼 추가 후, 발신자는 개수 증가를 제한
깨달은 점
- 실시간 반영과 디비 반영을 동시에 진행해야 하므로 어떤 순서로 구성해야 합리적일지 고민을 많이 함
- 어느 부분에선 실시간 반영을 먼저하고 디비에 값을 넣으면 값 반영에 대해 오류가 발생하는 경우가 생김
- 구성하는 부분과 설계순서에 대해 많이 고민할 필요가 있음