1. 程式人生 > >SpringBoot學習筆記(11):使用WebSocket構建交互式Web應用程序

SpringBoot學習筆記(11):使用WebSocket構建交互式Web應用程序

-- 文件 基於 ping pan lan tin eas return

SpringBoot學習筆記(11):使用WebSocket構建交互式Web應用程序

快速開始

  本指南將引導您完成創建“hello world”應用程序的過程,該應用程序在瀏覽器和服務器之間來回發送消息。 WebSocket是一個非常薄,輕量級的TCP層。它使得非常適合使用“子協議”來嵌入消息。在本指南中,我們將深入研究並使用Spring的STOMP消息來創建交互式Web應用程序。

  我們將建立一個服務用來接收一個攜有用戶名稱的消息,然後作為回應,推送一個問候語到客戶訂閱的隊列中。

  本節內容的思維導圖大致如下:

  技術分享圖片

參考教程

https://spring.io/guides/gs/messaging-stomp-websocket/

STOMP消息

  STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,簡單(流)文本定向消息協議,它提供了一個可互操作的連接格式,允許STOMP客戶端與任意STOMP消息代理(Broker)進行交互。STOMP協議由於設計簡單,易於開發客戶端,因此在多種語言和多種平臺上得到廣泛地應用。

  STOMP協議的前身是TTMP協議(一個簡單的基於文本的協議),專為消息中間件設計。

  STOMP是一個非常簡單和容易實現的協議,其設計靈感源自於HTTP的簡單性。盡管STOMP協議在服務器端的實現可能有一定的難度,但客戶端的實現卻很容易。例如,可以使用Telnet登錄到任何的STOMP代理,並與STOMP代理進行交互。

  STOMP協議與2012年10月22日發布了最新的STOMP 1.2規範。
  要查看STOMP 1.2規範,見: https://stomp.github.io/stomp-specification-1.2.html

基於Maven構建應用

  首先,設置一個基本的構建腳本。在使用Spring構建應用程序時,您可以使用任何您喜歡的構建系統,但此處包含了使用Maven所需的代碼。

  如果您不熟悉Maven,請參閱使用Maven構建Java項目。

 <!--添加WebSocket依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>webjars-locator-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>sockjs-client</artifactId>
            <version>1.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>stomp-websocket</artifactId>
            <version>2.3.3</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>bootstrap</artifactId>
            <version>3.3.7</version>
        </dependency>
        <dependency>
            <groupId>org.webjars</groupId>
            <artifactId>jquery</artifactId>
            <version>3.1.0</version>
        </dependency>

創建一個資源表示類

  現在您已經設置了項目和構建系統,您可以創建STOMP消息服務。通過考慮服務交互來開始這個過程。

  該服務將接受一個包含在STOMP消息中name的消息,該消息的主體是JSON對象。如果給出的名稱是“Fred”,那麽消息可能如下所示:

{
    "name": "Fred"
}

  要對帶有name的消息建模,可以使用name屬性和相應的getName()方法創建一個普通的Java對象:

public class HelloMessage {
    private String name;

    public HelloMessage(String name){
        this.name=name;
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

  在接收到消息並提取名稱後,服務將通過創建問候語並在客戶端訂閱的單獨隊列上發布該問候語來處理它。問候語也將是一個JSON對象,可能看起來像這樣:

public class GreetingMessage {
    private String context;

    public GreetingMessage(String context) {
        this.context = context;
    }

    public String getContext() {
        return context;
    }

    public void setContext(String context) {
        this.context = context;
    }
}

  Spring將使用Jackson JSON庫自動封送以上類型為JSON的實例。接下來,您將創建一個控制器來接收問候消息並發送問候消息。

創建一個消息處理控制器

import com.mrsaber.filebar.domain.GreetingMessage;
import com.mrsaber.filebar.domain.HelloMessage;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;

@Controller
public class GreetController {

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public GreetingMessage greeting(HelloMessage message) throws Exception
    {
        Thread.sleep(1000);
        return new GreetingMessage("Hello,"+message.getName());
    }
}

這個控制器看起來是簡潔又簡單的,但是已經做了大量的工作。讓我們來分解一下這個操作。

  1.   @MessageMapping註解確保如果將消息發送到目標“/ hello”,則調用greeting()方法
  2.   消息的原數據綁定到HelloMessage對象,該對象將傳遞給greeting()。
  3.   在內部,該方法的實現通過使線程休眠1秒來模擬處理延遲。這是為了演示客戶端發送消息後,只要需要異步處理消息,服務器就可以使用。客戶可以繼續進行它需要做的任何工作而無需等待響應。
  4.   在1秒延遲之後,greeting()方法創建一個Greeting對象並返回它。返回值將廣播給@SendTo註解中指定的“/ topic / greetings”的所有訂閱者

配置Spring以進行STOMP消息傳遞

  現在已經創建了服務的基本組件,您可以配置Spring以啟用WebSocket和STOMP消息傳遞。

  創建一個名為WebSocketConfig的Java類,如下所示:

  技術分享圖片

創建瀏覽器客戶端

HTML部分

<!DOCTYPE html>
<html>
<head>
    <title>Hello WebSocket</title>
    <link href="webs/bootstrap.min.css" rel="stylesheet">
    <script src="webs/jquery.min.js"></script>
    <script src="webs/sockjs.min.js"></script>
    <script src="webs/stomp.min.js"></script>
    <script src="webs/app.js"></script>
</head>
<body>
<noscript><h2 style="color: #ff0000">Seems your browser doesn‘t support Javascript! Websocket relies on Javascript being
    enabled. Please enable
    Javascript and reload this page!</h2></noscript>
<div id="main-content" class="container">
    <div class="row">
        <div class="col-md-6">
            <form class="form-inline">
                <div class="form-group">
                    <label for="connect">WebSocket connection:</label>
                    <button id="connect" class="btn btn-default" type="submit">Connect</button>
                    <button id="disconnect" class="btn btn-default" type="submit" disabled="disabled">Disconnect
                    </button>
                </div>
            </form>
        </div>
        <div class="col-md-6">
            <form class="form-inline">
                <div class="form-group">
                    <label for="name">What is your name?</label>
                    <input type="text" id="name" class="form-control" placeholder="Your name here...">
                </div>
                <button id="send" class="btn btn-default" type="submit">Send</button>
            </form>
        </div>
    </div>
    <div class="row">
        <div class="col-md-12">
            <table id="conversation" class="table table-striped">
                <thead>
                <tr>
                    <th>Greetings</th>
                </tr>
                </thead>
                <tbody id="greetings">
                </tbody>
            </table>
        </div>
    </div>
</div>
</body>
</html>

JavaScript部分

我們編寫了一個app.js文件用來存放我們的業務邏輯。

var stompClient = null;

function setConnected(connected) {
    $("#connect").prop("disabled", connected);
    $("#disconnect").prop("disabled", !connected);
    if (connected) {
        $("#conversation").show();
    }
    else {
        $("#conversation").hide();
    }
    $("#greetings").html("");
}

function connect() {
    var socket = new SockJS(‘localhost:8080/gs-guide-websocket‘);
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        setConnected(true);
        console.log(‘Connected: ‘ + frame);
        stompClient.subscribe(‘/topic/greetings‘, function (greeting) {
            showGreeting(JSON.parse(greeting.body).context);
        });
    });
}

function disconnect() {
    if (stompClient !== null) {
        stompClient.disconnect();
    }
    setConnected(false);
    console.log("Disconnected");
}

function sendName() {
    stompClient.send("/app/hello", {}, JSON.stringify({‘name‘: $("#name").val()}));
}

function showGreeting(message) {
    $("#greetings").append("<tr><td>" + message + "</td></tr>");
}

$(function () {
    $("form").on(‘submit‘, function (e) {
        e.preventDefault();
    });
    $( "#connect" ).click(function() { connect(); });
    $( "#disconnect" ).click(function() { disconnect(); });
    $( "#send" ).click(function() { sendName(); });
});  

測試程序

技術分享圖片

SpringBoot學習筆記(11):使用WebSocket構建交互式Web應用程序