728x90
https://soobysu.tistory.com/191
준비물
websocket / Stomp( 채팅방 세션 감지 / 실시간 데이터 전송 )
Redis ( 세션관리 / 메세지 Pub,Sub )
설명
사용자 A / B
A 가 들어온다
A가 메세지를 보낸다 ( 메세지는 안읽음 처리 )
B가 채팅방에 입장한다
B가 채팅을 읽고 읽은 채팅메세지ID를 A에게 전달한다
A는 B에게 받은 변경이된 채팅메세지ID들을 읽음으로 변환한다.
B는 채팅방에 메세지를 보낸다.
메세지를 보낼때 현재 채팅방의 세션을 확인하고 참가자 만큼 숫자를 내린다
A는 updateReadMessageId 를 받아 현재 채팅방에 같은 Id를 가지고 있는 메세지들을 읽음 처리로 바꿔준다.
B가 메세지를 채팅방에 보낸다
ㄴ> 현재 채팅방의 세션에 2명이 접속중인것을 확인하고 메세지를 읽음 상태로 채팅방에 뿌려준다.
A가 나간다
B가 메세지를 보낸다
ㄴ> 현재 채팅방세션에 1명이 접속중이니 안읽음으로 메세지를 채팅방에 뿌려준다.
채팅방 입장 -> DB 에서 메세지 조회
( 안읽음 메세지들은 읽음처리 함
-> 변경된 메세지 id 들을 상대방에게 웹소켓으로 전송 )
접속중 -> 웹소켓으로 메세지 실시간 받기
채팅방 입장
fun selectHistory(chatRoomId: String, authObject: AuthObject, pageable: Pageable): List<MessageResponse> {
chatRoomRepository.findById(chatRoomId).orElseThrow {
throw NotFoundException("채팅방을 찾을 수 없습니다.")
}
val pageableMessage = repository.findAllByChatRoomId(chatRoomId, pageable)
val messageContent = pageableMessage.content
if (messageContent.isEmpty()) return emptyList()
if (pageable.pageNumber == 0) {
val updateReadMessage = messageContent.filter {
it.senderId != authObject.userId
it.readCount > 0
}.onEach { it.readCount = 0 }
repository.saveAll(updateReadMessage)
val updateReadCountMessage = updateReadMessage.map { UpdateReadCountResponseDto.of(it) }
val updateMessages = SendResponse(updateReadMessage = updateReadCountMessage)
redisProvider.convertAndSend("$CHAT_ROOM_PREFIX${chatRoomId}", updateMessages)
}
return messageContent.map { MessageResponse.of(it) }
}
채팅방 입장시 메세지를 모두 읽음 표시로 변경 후 저장하고,
변경된 메세지들은 다시 상대방에게 읽었다는 updateMessages 로 보내준고,
모든 메세지들을 내 채팅방에 뿌려준다.
메세지 보내기
fun sendMessage(authObject: AuthObject, req: SendMessageRequestDto): Response {
val customer = customerService.findModelById(authObject.userId!!)
val sessionKey = "${CHAT_SESSION_PREFIX}${req.chatRoomId}"
val chatRoom = chatRoomRepository.findById(req.chatRoomId).orElseThrow {
throw NotFoundException("채팅방을 찾을 수 없습니다.")
}
val receiverId = chatRoom.getOtherCustomerId(authObject.userId)
val message = ChatMessage.personalMessageOf(customer, req)
try {
val currentUser = redisProvider.countCurrentSession(sessionKey)
message.readCount = if (currentUser > 1) 0 else 1
val newMessage = MessageResponse.of(saveModel(message))
val sendResponse = SendResponse(newMessage)
redisProvider.convertAndSend("$CHAT_ROOM_PREFIX${req.chatRoomId}", sendResponse)
return Response( .. )
} catch (e: Exception) {
throw InvalidRequestException("메시지 전송에 실패하였습니다.")
}
}
메세지를 보낼때는 현재 채팅방의 인원을 체크하여 채팅방 인원수 만큼 빼고,
채팅방에 메세지를 보낸다.
728x90
'개-발 > Java + Spring + Kotlin' 카테고리의 다른 글
[Spring] ServletRequest 캐싱 (ContentCachingRequestWrapper) (0) | 2024.12.02 |
---|---|
[spring] Cache 조회 성능을 최적화 Redis + Kotlin (0) | 2024.11.14 |
[WebSoket] Spring + SocketJs 사용하기 ( 테스트 Html코드 공유 ) (0) | 2024.11.02 |
[Spring Batch] 반복 오류 제어 (0) | 2024.09.01 |
[Java] 정규표현식 regex 패키지 (0) | 2024.07.29 |