SpringBoot 整合 WebSocket

SpringBoot 整合 WebSocket(topic廣播)

1、什麼是WebSocket

  WebSocket爲遊覽器和服務器提供了雙工異步通信的功能,即遊覽器可以向服務器發送消息,服務器也可以向遊覽器發送消息。WebSocket需遊覽器的支持,如IE10、Chrome 13+、Firefox 6+,這對我們現在的遊覽器來說都不是問題。

  WebSocket是通過一個socket來實現雙工異步通訊能力的。但是直接使用WebSocket(或SockJS:WebSocket協議的模擬,增加了當遊覽器不支持WebSocket的時候的兼容支持)協議開發程序顯得特別繁瑣, 我們會使用它的子協議STOMP,它是一個更高級別的協議,STOMP協議使用一個基於幀的格式來定義消息,與HTTP的request和reponse類似(具有類似於@RequestMapping的@MassageMapping)

2、什麼是STOMP

  STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息協議,是一種爲MOM(Message Oriented Middleware,面向消息的中間件)設計的簡單文本協議。
它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互,類似於OpenWire(一種二進制協議)。由於其設計簡單,很容易開發客戶端,因此在多種語言和多種平臺上得到廣泛應用。其中最流行的STOMP消息代理是Apache ActiveMQ。

  STOMP協議工作於TCP協議之上,使用了下列命令:
      1)、SEND 發送
      2)、SUBSCRIBE 訂閱
      3)、UNSUBSCRIBE 退訂
      4)、BEGIN 開始
      5)、COMMIT 提交
      6)、ABORT 取消
      7)、ACK 確認
      8)、DISCONNECT 斷開

3、爲什麼需要WebSocket

  答案很簡單,因爲 HTTP 協議有一個缺陷:通信只能由客戶端發起。
舉例來說,我們想了解今天的天氣,只能是客戶端向服務器發出請求,服務器返回查詢結果。HTTP 協議做不到服務器主動向客戶端推送信息。如果想持續從服務的獲取消息,則只能使用輪詢或建立長連接的方法來實現,但是這樣或浪費很多不必要的資源。
而webSocket則解決了這個問題,通信可由雙方發起,只需要建立一次連接,服務的端就可以持續從服務端獲得消息。主要用來做消息通知,消息推送等模塊

4、SpringBoot使用 STOMP 消息步驟

  1)、添加pom文件依賴

  2)、java方式配置websocket stomp

  3)、消息實體類

  4)、書寫控制層

  5)、書寫頁面

5、Pom 依賴

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

6、java方式配置websocket stomp

package com.example.demo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    /**
     * 配置鏈接端點
     * @param registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry){
        registry.addEndpoint("/endpointWisely").withSockJS();
    }

    /**
     * 配置消息代理
     * @param registry
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry){
        registry.enableSimpleBroker("/topic");
    }
}

7、消息實體類

package com.example.demo.PoJo;

/**
 * 消息接受
 */
public class WiselyMessage {

    private String name;

    public String getName(){
        return name;
    }
}

 

package com.example.demo.PoJo;

/**
 * 消息返回
 */
public class WiselyResponse {

    private String responseMessage;

    public WiselyResponse(String responseMessage){
        this.responseMessage = responseMessage;
    }

    public String getResponseMessage(){
        return responseMessage;
    }

}

8、書寫控制層

package com.example.demo.controller;

import com.example.demo.PoJo.WiselyMessage;
import com.example.demo.PoJo.WiselyResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;

import java.security.Principal;

@Controller
public class WsController {

    /**
     * MessageMapping 類似於 RequestMapping
     * SendTo 訂閱地址 類似於 訂閱一個URL (我的理解就是 調用了這個方法 在返回的時候會給訂閱該url的地址發送數據)
     * @param message
     * @return
     * @throws Exception
     */
    @MessageMapping("/welcome")
    @SendTo("/topic/getResponse")
    public WiselyResponse say(WiselyMessage message) throws Exception {
        Thread.sleep(3000);
        return new WiselyResponse("Welcome," + message.getName() + "!");
    }
}

9、書寫頁面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>Spring Boot+WebSocket+廣播式</title>

</head>
<body onload="disconnect()">
<noscript><h2 style="color: #ff0000">貌似你的瀏覽器不支持websocket</h2></noscript>
<div>
    <div>
        <button id="connect" onclick="connect();">連接</button>
        <button id="disconnect" disabled="disabled" onclick="disconnect();">斷開連接</button>
    </div>
    <div id="conversationDiv">
        <label>輸入你的名字</label><input type="text" id="name" />
        <button id="sendName" onclick="sendName();">發送</button>
        <p id="response"></p>
    </div>
</div>
<script th:src="@{sockjs.min.js}"></script>
<script th:src="@{stomp.min.js}"></script>
<script th:src="@{jquery.js}"></script>
<script type="text/javascript">
    var stompClient = null;

    function setConnected(connected) {
        document.getElementById('connect').disabled = connected;
        document.getElementById('disconnect').disabled = !connected;
        document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
        $('#response').html();
    }
    
    function connect() {
        var socket = new SockJS('/endpointWisely'); //1
        stompClient = Stomp.over(socket);
        stompClient.connect({}, function(frame) {
            setConnected(true);
            console.log('Connected: ' + frame);
            stompClient.subscribe('/topic/getResponse', function(respnose){ //2
                showResponse(JSON.parse(respnose.body).responseMessage);
            });
        });
    }
    
    
    function disconnect() {
        if (stompClient != null) {
            stompClient.disconnect();
        }
        setConnected(false);
        console.log("Disconnected");
    }

    function sendName() {
        var name = $('#name').val();
           //3
        stompClient.send("/welcome", {}, JSON.stringify({ 'name': name }));
    }

    function showResponse(message) {
          var response = $("#response");
          response.html(message);
    }
</script>
</body>
</html>

10、客戶端發送和接收消息圖解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章