반응형

이전 단계에서 모든 처리를 마치고 이제 메시지만 전송해주면된다. 

그런데 메시지를 전송할때 수신자가 현재 웹소켓에 연결되어있지않을때에 대한 처리를 해주어야했다.

 

getOnlineSession

private List<WebSocketSession> getOnlineSession(List<UserEntity> userEntities) {
    return userEntities.stream()
            .map(receiver -> userSessionMap.get(receiver.getEmail()))
            .filter(Objects::nonNull)
            .toList();
}

 

 

getOfflineUsers

private List<UserEntity> getOfflineUsers(List<UserEntity> userEntities) {
    List<UserEntity> offlineReceivers = userEntities.stream()
            .filter(receiver -> userSessionMap.get(receiver.getEmail()) == null)
            .toList();
    return offlineReceivers;
}

 

위 메서드를 이용해서 온라인인 유저는 세션으로 받아오고, 오프라인인 유저도 찾았다.

private void sendMessageAndkeep(List<UserEntity> userEntities, ChatMessageDto chatMessageDto, UserEntity sender) {
    //연결중인 세션만 찾아서 문자를전송
    getOnlineSession(userEntities).forEach(
            receiverSession -> sendMessage(receiverSession, chatMessageDto.getMessage()));

    //연결중이지않은 유저는 해당 기록을 저장.
    saveOfflineChat(userEntities, chatMessageDto, sender);
}

 

연결되어있는세션은  바로 chatMessegeDto에있는 message를 전송해주고 

연결중이지않은 유저는 유저정보와 메시지를 저장해준다.

 

saveOfflineChat

private void saveOfflineChat(List<UserEntity> userEntities, ChatMessageDto chatMessageDto, UserEntity sender) {
    List<UserEntity> offlineReceivers = getOfflineUsers(userEntities);

    offlineReceivers.forEach(offlineUser -> {
        OfflineChatHistoryEntity offlineChat = OfflineChatHistoryEntity.builder()
                .senderId(sender.getId())
                .receiverId(offlineUser.getId())
                .content(chatMessageDto.getMessage())
                .createdAt(LocalDateTime.now())
                .build();
        offlineChatHistoryRepository.save(offlineChat);
    });
}

 

이렇게 전송되지못한메시지는 저장해두었다가 이후에 해당유저가 웹소켓에 연결될때 다시 전송해준다.

웹소켓에 연결될때 실행되는 afterConnectionEstablished 메서드에 해당 기능을 추가해준다.

@Override
@Transactional
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    //유저의 이메일을 얻어온다.
    String userId = getUserId(session);

    UserEntity userEntity = userRepository.findByEmail(userId)
            .orElseThrow(() -> new ApiException(ErrorCode.BAD_REQUEST, "없는 유저입니다."));


    // 오프라인 유저 리스트에 해당 유저가 있는지 확인
    if (offlineChatHistoryRepository.existsByReceiverId(userEntity.getId())) {
        // chatRepository에서 해당 유저의 오프라인 메시지 정보 조회
        List<OfflineChatHistoryEntity> offlineMessages = offlineChatHistoryRepository.findByReceiverId(
                userEntity.getId());

        // 조회한 메시지 정보를 새로 연결된 세션을 통해 전송
        for (OfflineChatHistoryEntity message : offlineMessages) {
            sendMessage(session, message.getContent());
        }

        // 오프라인 유저 리스트에서 해당 유저 제거
        offlineChatHistoryRepository.deleteAllByReceiverId(userEntity.getId());
    }

    //유저의 이메일과 세션을 매핑해서 서버에서 관리.
    userSessionMap.put(userId, session);
    log.info("{} 환영합니다", userId);
}

 

이렇게 해주면 웹소켓에 연결될때 받지못한 메시지를 받을수있다.

반응형

'공부 임시 저장소' 카테고리의 다른 글

스프링 부트 - spring-security-jwt  (0) 2024.06.25
스프링부트 - aws s3파일저장  (0) 2024.06.25
스프링부트 - 파일 저장  (0) 2024.06.24
사이드 프로젝트) 채팅앱  (0) 2024.06.24
스프링 웹소켓  (1) 2024.06.03

+ Recent posts