Springboot]Websocket+stompによるチャット


📚 Websocket+Stompチャットの実装
✍🏻 Websocket
通常、サーバに情報を要求するとhttp/http通信が行われる.これは,クライアントがサーバに要求すると,サーバが対応する情報に応答する構造である.
しかしチャットする時、もし誰かが会話を送信するならば、私はサーバーに要求を送信しないで、サーバーも私に自分で情報を提供するべきで、この時Webソケットを使います
  • は、私が望んでいる情報(sub)を購読し、購読したトピックにメッセージを発行し、そのトピックを購読しているすべてのユーザーにメッセージを送信する方法がWebソケットです.
  • http/http通信とは、同じユーザがサーバにリソースまたは情報を複数回要求する場合、毎回要求情報を送信する必要があり、ソケット通信は1回の接続で接続を維持することができ、何の設定もなく情報を送信および受信することができる.
    ✍🏻 Stomp
    📌 What is stomp?

  • stompは、tcpやwebsocketなどの双方向ネットワークプロトコルに基づいて動作する(信頼性プロトコル)

  • STOMPは、テキスト向けのプロトコルまたはメッセージ負荷にテキストまたはバイナリデータを含めることができる.

  • stompは、メッセージのソースとメッセージのソースを分離するメッセージ伝達方法を提供する.

  • stompはhttpでモデリングされたFrameベースのプロトコルで、Frameはいくつかのテキスト行で指定された構造です.
    COMMAND
    header1: value1
    header2: value2
    (空白)
    Body

  • COMMAND:SEND、SUBSCRIBE指示

  • ヘッダーのdestinationを使用してメッセージをこのヘッダーに送信または購読できます.
  • 📌 Flow
  • チャットルームの作成:pub/sub実装のためのツール
  • の作成
  • チャットルームに入ります.トピック(/pub/chat/enter)->トピックを購読するユーザーにテンプレートを提供します.convertAndSend("/sub/chat/room/"+ message.getRoomId(), message); 入力情報
  • を送信する.
  • チャットルームを通じてメッセージを送信:
    メッセージを対応するTopic(/pub/chat/message)に送信
    このツールは、購読したユーザーにメッセージを送信します(/sub/chat/room/{roomid})
    ユーザーはstompです.subscribe(/sub/chat/room/+roomId,コールバック関数)によって購読されたチャットルームから受信されたメッセージ
  • (/app ==/pub,/topic ==/sub)
  • Spring-MessageモジュールはSpringフレームワークに統合されたメッセージアプリケーション
  • をサポートします.
  • 単純AnnotationMethod:@MessageMappingなどクライアントのSENDを受信して処理する.
  • Broker Channel:サーバ内部で使用されるチャネルであるため、単純なAnnotationMethodは単純なBrokerの存在を直接理解せずにメッセージを伝えることができる.
  • ✍🏻 Important Code
    📌 Websocket Config
    @EnableWebSocketMessageBroker
    @Configuration
    public class StompWebSocketConfig implements WebSocketMessageBrokerConfigurer {
    
       @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {
            registry.addEndpoint("/stomp/chat")
                   // 도메인허용 .setAllowedOrigins("http://api.tildp.shop","http://www.tildp.shop","http://localhost:8080")
                    .withSockJS();
        }
    
        /*어플리케이션 내부에서 사용할 path를 지정할 수 있음*/
        @Override
        public void configureMessageBroker(MessageBrokerRegistry registry) {
            registry.setApplicationDestinationPrefixes("/pub");
            registry.enableSimpleBroker("/sub");
        }
    }
    
  • setApplicationDestinationPrefixesは、クライアントによってSEND要求を処理する./pubの
  • に送信
  • enableSimpleBrokerは、このパスを使用してSimpleBrokerを登録します.SimpleBrokerは、このパスを購読しているクライアントにメッセージを送信します.
  • 📌 StompChatHandler
    チャットルームに入る部分コード
    @MessageMapping処理により、Webソケットへのメッセージ発行を行います.クライアントが「/pub/chat/enter」の発行を要求すると、コントローラはメールを受信し、アドレスを購読しているユーザーにメッセージを送信します.
    =>メッセージがパブリッシュされると、「/sub/chat/room/[roomId]」にメッセージが送信されます.
    =>クライアントはアドレスを購読しており、メッセージが受信されると画面に出力されます.
    =>既存のハンドルChatHandlerの代わりに制御スライダをスケーリングする必要がなくなりました
    @MessageMapping(value = "/chat/enter")
        public void enter(ChatMessageDTO message) {
            String id = message.getRoomId();
            Long room_id = Long.valueOf(id);
    
            // chat user 정보 저장 (채팅유저 , 채팅방)
            ChatRoom chatRoom = chatRoomRepository.findByRoomId(room_id).orElseThrow(
                    () -> new NullPointerException("해당 채팅방이 존재하지 않습니다."));
            User user = userRepository.findByUsername(message.getWriter()).orElseThrow(
                    () -> new NullPointerException("해당 사용자가 존재하지 않습니다."));
    
    
            if (!(chatUserRepository.findByChatRoomAndUser(chatRoom, user).isPresent())) { //채팅방 처음입장
                ChatUser chatUser = new ChatUser(user, chatRoom);
                chatUserRepository.save(chatUser);
                int count  =chatUserRepository.countByChatRoom(chatRoom);
    
                chatRoom.setCount(count);
                chatRoomRepository.save(chatRoom);
    
                message.setMessage("채팅방에 참여하였습니다.");
                template.convertAndSend("/sub/chat/room/" + message.getRoomId(), message);
            }
            else
            {
                message.setMessage("채팅방에 재입장하였습니다.");
                template.convertAndSend("/sub/chat/room/" + message.getRoomId(), message);
            }
        }
    
  • チャットルームの人数を実現するために、chatUserというエンティティ
  • も作成しました.
  • チャットルームは、チャットルームに入ったユーザの情報を含み、ユーザは部屋を購読するたびにChatUserを生成する.
  • ですが、チャットルームに入るたびに繰り返されるので、リポジトリに存在を特定してから生成する必要があります.
  • チャットルームの人数を実現
    https://velog.io/@dltndudvlzm/%EB%82%B4%EC%9D%BC%EB%B0%B0%EC%9B%80%EC%BA%A0%ED%94%84-211215-TIL
    これは私が今日整理した文章です.参照><