springboot2.0+websocket統合【群発メッセージ+シングルペア】(二)


第2編では,主にsocketjs,stompモードを用いたwebsocketを簡単に実現する.第1篇の住所:springboot 2.0+websocket統合【群発メッセージ+シングルペア】参考:http://tech.lede.com/2017/03/08/qa/websocket+spring/https://blog.csdn.net/mr_zhuqiang/article/details/46618197
前回のプロジェクトを続行します.次のコードの一部が読めない場合は、前の記事で流れを見たり、文末にプロジェクトのgitアドレスを貼ったりしてください.
1.まず配置から、WebStompConfig
コードの中の注釈は基本的に各行の意味をはっきり説明することができて、ここで完全なコードを詳しく言わないでください
package com.example.websocketdemo1.stomp;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/**
 * EnableWebSocketMessageBroker     :            WebSocket,          STOMP   ;
 * registerStompEndpoints()   :        ,         。  “/chat”       STOMP   。                       ,       ,                 ,      ,        :url=’/127.0.0.1:8080/chat’   STOMP server     ,        url;
 * configureMessageBroker()   :             ,                      。
 *
 * @author linyun
 * @date 2018/9/13   5:15
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebStompConfig implements WebSocketMessageBrokerConfigurer {

    @Autowired
    private WebSocketHandleInterceptor interceptor;

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

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //                 ,                    
        registry.enableSimpleBroker("/message", "/notice");
        //             ,                 
        registry.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        //                 
        registration.interceptors(interceptor);
    }
}

2.ユーザー情報登録、WebSocketHandleInterceptor
前編では,ユーザ情報をセッションに直接格納し,握手をすることでWebSocketSessionにユーザ情報を格納する.今回stompを使うモードでも一対一のメッセージが存在するので、相手が誰なのかを知る必要があるので、ユーザー情報も登録しておきます.
完全なコード
package com.example.websocketdemo1.stomp;

import com.sun.security.auth.UserPrincipal;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.security.Principal;

/**
 * @author linyun
 * @date 2018/9/13   5:57
 */
@Component
public class WebSocketHandleInterceptor implements ChannelInterceptor {

    /**
     *   user websocket conn 
     * @param message
     * @param channel
     * @return
     */
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        if (StompCommand.CONNECT.equals(accessor.getCommand())) {
            String username = accessor.getFirstNativeHeader("username");
            if (StringUtils.isEmpty(username)) {
                return null;
            }
            //   user
            Principal principal = new UserPrincipal(username);
            accessor.setUser(principal);
        }
        return message;
    }
}

ここのusername情報に注意
String username = accessor.getFirstNativeHeader("username");

usernameはページに渡され、具体的な渡し方は後ろのページで、具体的なパラメータ名は自由にカスタマイズできます.もう1つのユーザ情報を取得する方法:
Object raw = message.getHeaders().get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
if (raw instanceof Map) {
    System.out.println(raw);
    //   raw  ,         ,   username。
}

3.メッセージを処理するクラス、GreetingControl
メッセージの受信と送信に使用します.まずメッセージのmodelを来て、メッセージを包装して、lombokプラグインを使って、getsetを省きました.コード:
package com.example.websocketdemo1.stomp;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author linyun
 * @date 2018/9/13   5:44
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Message {
    private String to;
    private Long date;
    private String from;
    private String content;
}

コントロールの完全なコード
package com.example.websocketdemo1.stomp;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.handler.annotation.*;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.security.Principal;
import java.util.Map;

/**
 * @author linyun
 * @date 2018/9/13   5:42
 */
@Slf4j
@Controller
public class GreetingController {

    @Autowired
    private SimpMessagingTemplate simpMessagingTemplate;


    /**
     *     
     * @return
     */
    @RequestMapping("/chat4")
    public String chat4() {
        return "chat4";
    }

    /**
     *     2
     * @return
     */
    @RequestMapping("/chat5")
    public String chat5() {
        return "chat5";
    }

    /**
     *     
     * @param message
     * @param messageHeaders
     * @param destination
     * @param headers
     * @param id
     * @param body
     */
    @MessageMapping("/hello/{id}")
    public void hello(Message message,
                      MessageHeaders messageHeaders,
                      @Header("destination") String destination,
                      @Headers Map<String, Object> headers,
                      @DestinationVariable long id,
                      @Payload String body) {
        log.info("message:{}", message);
        log.info("messageHeaders:{}", messageHeaders);
        log.info("destination:{}", destination);
        log.info("headers:{}", headers);
        log.info("id:{}", id);
        log.info("body:{}", body);
    }


    /***        ***/

    /**
     *       。
     * @param message
     */
    @MessageMapping("/hello")
    public void hello(@Payload com.example.websocketdemo1.stomp.Message message) {
        System.out.println(message);
        com.example.websocketdemo1.stomp.Message returnMessage = new com.example.websocketdemo1.stomp.Message();
        returnMessage.setContent("  ," + message.getContent());
        simpMessagingTemplate.convertAndSend("/message/public", returnMessage);
    }

    /**
     *            
     * @param message
     * @return
     */
    @MessageMapping("/hello1")
    @SendTo("/message/public")
    public com.example.websocketdemo1.stomp.Message hello1(@Payload com.example.websocketdemo1.stomp.Message message) {
        System.out.println(message);
        com.example.websocketdemo1.stomp.Message returnMessage = new com.example.websocketdemo1.stomp.Message();
        returnMessage.setContent("  2," + message.getContent());
        return returnMessage;
    }

    /***        ***/

    /**
     *        。              。
     * @param message
     * @param principal
     */
    @MessageMapping("/hello2")
    public void hello2(@Payload com.example.websocketdemo1.stomp.Message message, Principal principal) {
        System.out.println(message);
        System.out.println(principal);
        com.example.websocketdemo1.stomp.Message returnMessage = new com.example.websocketdemo1.stomp.Message();
        returnMessage.setContent("  3," + message.getContent());
        simpMessagingTemplate.convertAndSendToUser(message.getTo(), "/notice/msg", returnMessage);
    }

}

コードのいくつかの方法の最初の方法を少し説明します./hello/{id}は、主にメッセージを送信する要求でそれらのパラメータを取得できることをテストし、これらのパラメータを自分のビジネスに合理的に利用するために使用されます.
    @MessageMapping("/hello/{id}")
    public void hello(Message message,
                      MessageHeaders messageHeaders,
                      @Header("destination") String destination,
                      @Headers Map<String, Object> headers,
                      @DestinationVariable long id,
                      @Payload String body) {
        log.info("message:{}", message);
        log.info("messageHeaders:{}", messageHeaders);
        log.info("destination:{}", destination);
        log.info("headers:{}", headers);
        log.info("id:{}", id);
        log.info("body:{}", body);
    }

4.結合ページテスト
ユーザー情報を設定する2ページを新規作成
http://127.0.0.1:8080/chat4
username='tom';
http://127.0.0.1:8080/chat5
username='jerry';

主にstompを導入する.jsとsocketjsの2つのjs.ページの完全なコード:

<html lang="en">
<head>
    <title>  websockettitle>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/css/bootstrap.min.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-toast-plugin/1.3.2/jquery.toast.min.css">
head>
<body>
<div class="container">
    <button type="button" class="btn btn-primary" onclick="connect()">  button>
    <button type="button" class="btn btn-primary" onclick="disconnect()">  button>

div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js" type="text/javascript">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.2/js/bootstrap.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-toast-plugin/1.3.2/jquery.toast.min.js">script>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js">script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js">script>
<script language=javascript>

    var username = 'tom';
    var sendMessage = null;
    var disConnect = null;

    function connect() {
        var socket = new SockJS("http://127.0.0.1:8080/chat");
        var client = Stomp.over(socket);
        client.connect({
            username: username
        }, function (succ) {
            console.log('client connect success:', succ);

            client.subscribe("/message/public", function (res) {
                console.log('    ---/message/public:',res);
            });

            client.subscribe("/user/notice/msg", function (res) {
                console.log('    :',res)
            });
        }, function (error) {
            console.log('client connect error:', error);
        });
        sendMessage = function (destination, headers, body) {
            client.send(destination, headers, body)
        };
        disConnect = function () {
            client.disconnect();
            console.log('client connect break')
        }
    }

    function disconnect() {
        disConnect();
    }

    //      
    function send(roomId, ct) {
        var messageModel = {};
        messageModel.type = 1;
        messageModel.content = ct;
        messageModel.from = username;
        sendMessage("/app/hello/" + roomId, {}, JSON.stringify(messageModel));
    }

    /**
     *         ,     /sub/public         。
     */
    function send1() {
        var messageModel = {};
        messageModel.type = 1;
        messageModel.content = '  ,' + new Date().getTime();
        messageModel.from = username;
        sendMessage("/app/hello", {}, JSON.stringify(messageModel));
    }
    function send2() {
        var messageModel = {};
        messageModel.type = 1;
        messageModel.content = 'hello1,' + new Date().getTime();
        messageModel.from = username;
        sendMessage("/app/hello1", {}, JSON.stringify(messageModel));
    }
    /**        ,    to **/
    function send3() {
        var messageModel = {};
        messageModel.to = 'jerry';
        messageModel.type = 1;
        messageModel.content = 'hello1,' + new Date().getTime();
        messageModel.from = username;
        sendMessage("/app/hello2", {}, JSON.stringify(messageModel));
    }
    }
script>
body>
html>

リンクボタンをクリックして、主にいくつかの操作をしました.
1.websocketへのリンク
2.購読/message/public3.購読/user/notice/msg5.ランニングテスト
ページに入ると、コンソールを開き、コマンドを直接入力します.都合が悪いと思ったら、ページにボタンをいくつか追加して、美観点=)
  • send(‘123456’,‘hello’);

  • このメソッドは、/app/hello/123456にメッセージを送信し、パラメータmessageModelを持参します.バックグラウンド@MessageMapping("/hello/{id}")で受信したメッセージをモニタします.
  • send1();

  • /app/helloにメッセージを送信し、バックグラウンドで受信するとsimpMessagingTemplate.convertAndSend("/message/public", returnMessage);/message/publicを購読したすべてのユーザーにメッセージをブロードキャストします.テストのために、いくつかのブラウザを開いたほうがいいです.コンソールの印刷情報を見てみましょう.
  • send3();

  • @Message Mapping("/hello 2")にメッセージを送信します.メッセージメッセージメッセージModelにto=jerryが追加されていることに注意してください.バックグラウンドでパラメータを受信後、simpMessagingTemplateを使用します.convertAndSendToUser(message.getTo(), “/notice/msg”, returnMessage); メッセージをjerryに送信し、単一ペアのメッセージプッシュを実現する.
    6.まとめてみる
  • stomp下位実装はすべてブロードキャストであり、単一ペアの単一は表面が特殊に見えるだけで、本質は実際には生成された唯一のブロードキャストアドレスでもある.テストも簡単で、2ページを開いてtomにログインし、1つはjerryにログインします.jerryでtomにメッセージを送信します.2つのtomはいずれもメッセージを受け取る.
  • ページにサブスクリプションアドレスが登録され、バックグラウンドでは登録されたアドレスでブロードキャストが送信されます.だから/messageと/noticeの後のパラメータは実は勝手に書くことができます.

  • 完全なプロジェクトgit:https://gitlab.com/tulongx/websocketdemo1
    以上です.springboot2.0+websocket集成【群发消息+单对单】(二)_第1张图片