SpringBoot 整合 WebSocket(topic廣播)javascript
一、什麼是WebSockethtml
WebSocket爲遊覽器和服務器提供了雙工異步通訊的功能,即遊覽器能夠向服務器發送消息,服務器也能夠向遊覽器發送消息。WebSocket需遊覽器的支持,如IE十、Chrome 13+、Firefox 6+,這對咱們如今的遊覽器來講都不是問題。java
WebSocket是經過一個socket來實現雙工異步通信能力的。可是直接使用WebSocket(或SockJS:WebSocket協議的模擬,增長了當遊覽器不支持WebSocket的時候的兼容支持)協議開發程序顯得特別繁瑣, 咱們會使用它的子協議STOMP,它是一個更高級別的協議,STOMP協議使用一個基於幀的格式來定義消息,與HTTP的request和reponse相似(具備相似於@RequestMapping的@MassageMapping)jquery
二、什麼是STOMPweb
STOMP,Streaming Text Orientated Message Protocol,是流文本定向消息協議,是一種爲MOM(Message Oriented Middleware,面向消息的中間件)設計的簡單文本協議。
它提供了一個可互操做的鏈接格式,容許STOMP客戶端與任意STOMP消息代理(Broker)進行交互,相似於OpenWire(一種二進制協議)。因爲其設計簡單,很容易開發客戶端,所以在多種語言和多種平臺上獲得普遍應用。其中最流行的STOMP消息代理是Apache ActiveMQ。spring
STOMP協議工做於TCP協議之上,使用了下列命令:
1)、SEND 發送
2)、SUBSCRIBE 訂閱
3)、UNSUBSCRIBE 退訂
4)、BEGIN 開始
5)、COMMIT 提交
6)、ABORT 取消
7)、ACK 確認
8)、DISCONNECT 斷開
瀏覽器
三、爲何須要WebSocket服務器
答案很簡單,由於 HTTP 協議有一個缺陷:通訊只能由客戶端發起。
舉例來講,咱們想了解今天的天氣,只能是客戶端向服務器發出請求,服務器返回查詢結果。HTTP 協議作不到服務器主動向客戶端推送信息。若是想持續從服務的獲取消息,則只能使用輪詢或創建長鏈接的方法來實現,可是這樣或浪費不少沒必要要的資源。而webSocket則解決了這個問題,通訊可由雙方發起,只須要創建一次鏈接,服務的端就能夠持續從服務端得到消息。主要用來作消息通知,消息推送等模塊
websocket
四、SpringBoot使用 STOMP 消息步驟app
1)、添加pom文件依賴
2)、java方式配置websocket stomp
3)、消息實體類
4)、書寫控制層
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>
六、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"); } }
七、消息實體類
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; } }
八、書寫控制層
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() + "!"); } }
九、書寫頁面
<!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>
十、客戶端發送和接收消息圖解