SpringBootおよびWebSocketsとのチャット





. « Spring Framework» . , , : « Spring», .









ビルスケーラブルなサーバに送信され、イベントを使用して通知のようなFacebookの-とRedisの、私たちは、サーバからクライアントにメッセージを送信するサーバ送信されたイベントを使用していました。また、サーバーとクライアント間の双方向通信テクノロジーであるWebSocketについても言及しました。



この記事では、WebSocketの一般的な使用例の1つを見ていきます。プライベートメッセージングアプリケーションを作成します。



以下のビデオは、私たちがやろうとしていることを示しています。





WebSocketsとSTOMPの概要



WebSocketは、サーバーとクライアント間の双方向通信用のプロトコルです。

WebSocketは、HTTPとは異なり、アプリケーション層プロトコルはトランスポート層プロトコル(TCP)です。最初の接続にはHTTPが使用されますが、接続はWebSocketで使用されるTCP接続に「アップグレード」されます。



WebSocketは、メッセージ形式を定義しない低レベルのプロトコルです。したがって、WebSocket RFCは、メッセージの構造と標準を記述するサブプロトコルを定義します。STOMP over WebSockets(STOMP over WebSockets)を使用します。



プロトコルSTOMP(シンプル/テキスト指向のメッセージプロトコルのストリーミング)は、サーバーとクライアント間のメッセージ交換のルールを定義します。



STOMPはHTTPに似ており、次のコマンドを使用してTCP上で実行されます。



  • 接続する
  • 申し込む
  • 購読解除
  • 送信
  • ベギン
  • コミット
  • ACK


STOMPコマンドの仕様と完全なリストはここにあります



建築







  • 認証サービスは、ユーザーを認証し、管理を担当。ここでは車輪を作り直さずJWTの認証サービスとSpringBootを使用したソーシャル認証を使用します。
  • チャットサービスがある、のWebSocketを設定STOMPメッセージを処理し、ユーザーメッセージを格納し、処理するための責任を負います。
  • チャットクライアントが接続して、チャットを購読するSTOMPクライアントを使用していますReactJSアプリケーションです。また、ここにユーザーインターフェイスがあります。


メッセージモデル



最初に考えるのはメッセージモデルです。ChatMessageは次のようになります。



public class ChatMessage {
   @Id
   private String id;
   private String chatId;
   private String senderId;
   private String recipientId;
   private String senderName;
   private String recipientName;
   private String content;
   private Date timestamp;
   private MessageStatus status;
}


クラスはChatMessage非常に単純で、送信者と受信者を識別するために必要なフィールドがあります。



また、メッセージがクライアントに配信されたかどうかを示すステータスフィールドもあります。



public enum MessageStatus {
    RECEIVED, DELIVERED
}


サーバーがチャットからメッセージを受信すると、メッセージを受信者に直接送信するのではなく、新しいメッセージが受信されたことをクライアントに通知する通知(ChatNotification)を送信します。その後、クライアント自身が新しいメッセージを受信できます。クライアントがメッセージを受信するとすぐに、メッセージはDELIVEREDとしてマークされます。



通知は次のようになります。



public class ChatNotification {
    private String id;
    private String senderId;
    private String senderName;
}


通知には、以下に示すように、クライアントが新しいメッセージまたは新しいメッセージの数に関する情報を表示できるように、新しいメッセージのIDと送信者に関する情報が含まれています。











SpringでのWebSocketとSTOMPの構成



最初のステップは、STOMPエンドポイントとメッセージブローカーを構成することです。



これを行うには、注釈を使用してWebSocketConfigクラスを作成@Configuration@EnableWebSocketMessageBrokerます。



@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker( "/user");
        config.setApplicationDestinationPrefixes("/app");
        config.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry
                .addEndpoint("/ws")
                .setAllowedOrigins("*")
                .withSockJS();
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
        resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setObjectMapper(new ObjectMapper());
        converter.setContentTypeResolver(resolver);
        messageConverters.add(converter);
        return false;
    }
}


最初の方法は、メッセージ/userを送受信するために、単一のプレフィックス付きアドレス持つ単純なメモリ内メッセージブローカーを構成します。プレフィックス付きアドレス/appは、注釈付きの方法@MessageMapping処理されるメッセージ用です。これについては、次のセクションで説明します。



2番目の方法は、STOMPエンドポイントを登録します/wsこのエンドポイントは、クライアントがSTOMPサーバーに接続するために使用されます。これには、WebSocketが使用できない場合に使用されるフォールバックSockJSも含まれます。



最後のメソッドは、SpringがメッセージをJSONとの間で変換するために使用するJSONコンバーターを構成します。



メッセージを処理するためのコントローラー



このセクションでは、リクエストを処理するコントローラー作成します。ユーザーからメッセージを受信し、受信者に送信します。



@Controller
public class ChatController {

    @Autowired private SimpMessagingTemplate messagingTemplate;
    @Autowired private ChatMessageService chatMessageService;
    @Autowired private ChatRoomService chatRoomService;

    @MessageMapping("/chat")
    public void processMessage(@Payload ChatMessage chatMessage) {
        var chatId = chatRoomService
                .getChatId(chatMessage.getSenderId(), chatMessage.getRecipientId(), true);
        chatMessage.setChatId(chatId.get());

        ChatMessage saved = chatMessageService.save(chatMessage);
        
        messagingTemplate.convertAndSendToUser(
                chatMessage.getRecipientId(),"/queue/messages",
                new ChatNotification(
                        saved.getId(),
                        saved.getSenderId(),
                        saved.getSenderName()));
    }
}


注釈@MessageMappingを使用して、メッセージがに送信される/app/chatときにメソッドが呼び出されるように構成しますprocessMessage以前に構成されたアプリケーションプレフィックスがマッピングに追加されることに注意してください/app



このメソッドは、メッセージをMongoDBに格納してconvertAndSendToUserから、メソッド呼び出して通知をターゲットに送信します。プレフィックスアドレス



convertAndSendToUser追加する方法最終的なアドレスは次のようになります。/userrecipientId/queue/messages



/user/{recipientId}/queue/messages


このアドレスのすべてのサブスクライバー(この場合は1つ)がメッセージを受信します。



chatIdの生成



2人のユーザー間の会話ごとに、チャットルームを作成し、それを識別するための一意のチャットルームを生成しchatIdます。ChatRoom



クラスは次のようになります。



public class ChatRoom {
    private String id;
    private String chatId;
    private String senderId;
    private String recipientId;
}


chatIdは連結と同じsenderId_recipientIdです。会話ごとに、同じ2つのエンティティを保持しchatIdます。1つは送信者と受信者の間、もう1つは受信者と送信者の間で、両方のユーザーが同じを受信するようにしchatIdます。



JavaScriptクライアント



このセクションでは、WebSocket / STOMPサーバーとの間でメッセージを送受信するJavaScriptクライアントを作成します。



SockJSとStomp.jsを使用して、STOMP overWebSocketを使用してサーバーと通信します。



const connect = () => {
    const Stomp = require("stompjs");
    var SockJS = require("sockjs-client");
    SockJS = new SockJS("http://localhost:8080/ws");
    stompClient = Stomp.over(SockJS);
    stompClient.connect({}, onConnected, onError);
  };


このメソッドは、サーバーが接続を待機しているconnect()への接続を確立し、接続が成功したときに呼び出され、サーバーへの接続中にエラーが発生した場合に呼び出される/wsコールバック関数も定義します。onConnectedonError



const onConnected = () => {
    console.log("connected");

    stompClient.subscribe(
      "/user/" + currentUser.id + "/queue/messages",
      onMessageReceived
    );
  };


このメソッドonConnected()は特定のアドレスにサブスクライブし、そこで送信されたすべてのメッセージを受信します。



const sendMessage = (msg) => {
    if (msg.trim() !== "") {
      const message = {
        senderId: currentUser.id,
        recipientId: activeContact.id,
        senderName: currentUser.name,
        recipientName: activeContact.name,
        content: msg,
        timestamp: new Date(),
      };
        
      stompClient.send("/app/chat", {}, JSON.stringify(message));
    }
  };


メソッドの最後に、コントローラーで指定されsendMessage()たアドレスにメッセージが送信/app/chatされます。



結論



この記事では、SpringBootとSTOMPoverWebSocketを使用してチャットを作成するためのすべての重要なポイントについて説明しました。



また、SockJsおよびStomp.jsライブラリを使用してJavaScriptクライアントを構築しました



サンプルのソースコードはここにあります






コースの詳細をご覧ください。











All Articles