spring springboot2 結合 websocket+sockJs+stomp 實現個人訂閱和廣播模式


一  名詞解釋

  1.WebSocket

WebSocket 是發送和接收消息的底層API,WebSocket 協議提供了通過一個套接字實現全雙工通信的功能。也能夠實現 web 瀏覽器和 server 間的異步通信,全雙工意味着 server 與瀏覽器間可以發送和接收消息。需要注意的是必須考慮瀏覽器是否支持

  2.SockJs

為了應對許多瀏覽器不支持WebSocket協議的問題,設計了備選SockJs。

SockJS 是 WebSocket 技術的一種模擬。SockJS 會 盡可能對應 WebSocket API,但如果 WebSocket 技術不可用的話,就會選擇另外的通信方式協議。

  3.STOMP

SockJS 為 WebSocket 提供了 備選方案。但無論哪種場景,對於實際應用來說,這種通信形式層級過低。下面看一下如何 在 WebSocket 之上使用 STOMP協議,來為瀏覽器 和 server 間的 通信增加適當的消息語義。(STOMP—— Simple Text Oriented Message Protocol——面向消息的簡單文本協議)

  4.三者之間的關系

WebSocket 是底層協議,SockJS 是WebSocket 的備選方案,也是 底層協議,而 STOMP 是基於 WebSocket(SockJS) 的上層協議

二 springboot的config

<!--  websocket-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

  1.基礎配置

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic", "/queue", "/user"); //表示在topic和queue這兩個域上服務端可以向客戶端發消息
        registry.setApplicationDestinationPrefixes("/app");//客戶端向服務器端發送時的主題上面需要加"/app"作為前綴
        registry.setUserDestinationPrefix("/user");//指定用戶發送一對一的主題,前綴是"/user"
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/stomp/endpoint").withSockJS();
    }
}

第一步就是添加注解 此注解 這個配置類不僅配置了 WebSocket,還配置了基於代理的 STOMP 消息

第二步 配置一個消息代理..一個是允許服務器向客戶端發送的域 一個是客戶端想服務器發送的前綴,最后一個是指定一對第一發送的前綴

第三步 就是配置了節點,並且使用sockjs的方式

  2.監聽連接與斷開

  用到了redis管理session

    @Access(name = "監聽websocket連接成功")
    @EventListener
    public void onConnectEvent(SessionConnectEvent event) {
        //獲取Session連接信息
        StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
        //獲取SessionId
        String sessionId = sha.getSessionId();
        //存儲redis
        Map<String, String> map = new HashMap<String, String>();
        map.put(sessionId, agentNo);
        redisTemplate.opsForHash().putAll("webSocket", map);
    }

    @Access(name = "監聽websocket斷開連接")
    @EventListener
    public void onDisconnectEvent(SessionDisconnectEvent event) {
        //獲取Session連接信息
        StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage());
        //獲取SessionId
        String sessionId = sha.getSessionId();
        //redis刪除此sessionId
        redisTemplate.opsForHash().delete("webSocket", sessionId);
    }
}

  三.實現前端代碼

   1.引入js 

<!-- websocket   ****代表自己的項目路徑  這個寫自己的  -->
<script src="/***/sockjs-client/sockjs.min.js"></script>
<script src="/***/stomp-websocket/stomp.min.js"></script>
<!-- 參考 -->
<!-- 
https://cdn.bootcdn.net/ajax/libs/sockjs-client/1.4.0/sockjs.min.js
https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.min.js
-->

  2.連接和訂閱消息

  使用了agentNo 區分訂閱廣播消息與個人消息

var stompClient = null;
var socket = null;
function connect() {
    //從sesionStorage獲取坐席工號  下面連接頭需要  這個按照自己需求修改
    agentNo = sessionStorage.getItem("agentNo");
    //建立連接對象(還未發起連接)  地址更換成自己的  連接服務器注冊端點endPoint時,寫訪問服務器的全路徑URL:
    socket = new SockJS('地址');
    //獲取 STOMP 子協議的客戶端對象
    stompClient = Stomp.over(socket);
    //建立連接,並且連接頭上定義了坐席工號
    stompClient.connect({
        userName: agentNo    // <---這是頭 在后面的監聽  連接成功的類可以獲取到  業務代碼需要 按需刪除
    }, function (frame) {
        console.log('Connected: ' + frame);
        //訂閱廣播消息
        stompClient.subscribe('/topic/greetings', function (greeting) {
            var data = JSON.parse(greeting.body).data;
            //實現自己的需求
        });
        //訂閱個人消息   
        stompClient.subscribe('/user/' + agentNo + '/message', function (greeting) {
            var data = JSON.parse(greeting.body);
            //實現自己的需求
        });
    });
}

  2.發送消息

function send(data) {
    var param = {
        id: data,
        release: true
    }
    stompClient.send("/app/release", {}, JSON.stringify(param));  
 // <----- app 就是在config中定義的客戶端往服務器發送的前綴,param是信息.必須用實體發送后台必須用實體接收
//release是后面controller中定義的 相當於RequestMapping中寫的地址一樣
}

  四.實現后端代碼

    1.發送廣播

    @Access(name = "發布公告")
    @MessageMapping("/release")
    @SendTo("/topic/greetings")
    public WebResult release(@RequestBody Announcement announcement) {
       //執行業務代碼邏輯
    }

  2.發送個人消息

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

     public void demo() {
     // messagingTemplate.convertAndSend(url,"");  //方法1
    //方法2  相當於/user/' + agentNo + '/message'    對應前端訂閱的地址
    messagingTemplate.convertAndSendToUser(ledgerQuery.getAgentNo(), "/message", "");
}

  

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM