通過WebSocket和STOMP實現瀏覽器和伺服器的訊息通訊
非同步訊息
非同步訊息有兩個重要的概念,訊息代理(broker)和目的地(destination)。訊息代理:當一個應用傳送訊息時,需要制定傳送的目的地,然後將訊息交給訊息代理(類似郵局),訊息代理會確保訊息傳送到指定的目的地。
目的地:不同的訊息系統有不同的訊息路由模式,但是有兩種通用的目的地:佇列(queue)和主題(topic),分別對應兩種訊息模型:點對點模型和釋出/訂閱模型
點對點模型:
佇列可以有多個接收者,但是訊息只能被一個接收者取走。
釋出-訂閱訊息模型:
主題裡的訊息可以傳送給多個訂閱者。
WebSockt實現瀏覽器和服務端通訊
WebSocket協議提供了通過套接字實現全雙工、非同步通訊的功能。首先,瀏覽器的JavaScript客戶端建立一個socket並連線到服務端,接下來,客戶端和服務端之間可以通過這個通道傳送和接收訊息,服務端可以通過這個連結傳送更新到客戶端。
通過Spring的WebSocketAPI實現
客戶端程式碼:
<html> <head> <title>Home</title> <script th:src="@{/webjars/sockjs-client/0.3.4/sockjs.min.js}"></script> <script th:src="@{/webjars/jquery/2.0.3/jquery.min.js}"></script> </head> <body> <button id="stop">Stop</button> <script th:inline="javascript"> var sock = new SockJS([[@{/marco}]]);//SockJS是對WebSocket技術的一種模擬,在瀏覽器不支援WebSocket通訊時, 提供其他的通訊方式。 sock.onopen = function() { console.log('Opening'); sayMarco(); } sock.onmessage = function(e) { console.log('Received message: ', e.data); $('#output').append('Received "' + e.data + '"<br/>'); setTimeout(function(){sayMarco()}, 2000); } sock.onclose = function() { console.log('Closing'); } function sayMarco() { console.log('Sending Marco!'); $('#output').append('Sending "Marco!"<br/>'); sock.send("Marco!"); } $('#stop').click(function() {sock.close()}); </script> <div id="output"></div> </body> </html>
上面程式碼中,sock建立的引數是/marco,這是一個路徑,代表該客服端sock連線到服務端的路徑是當前路徑加上這個相對路徑。而這個/marco其實對應的就是服務端的handler訊息處理器。
服務端程式碼:
public class MarcoHandler extends AbstractWebSocketHandler { private static final Logger logger = LoggerFactory.getLogger(MarcoHandler.class); //處理文字訊息 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { logger.info("Received message: " + message.getPayload()); Thread.sleep(2000); session.sendMessage(new TextMessage("Polo!")); } }
@Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(marcoHandler(), "/marco").withSockJS(); } @Bean public MarcoHandler marcoHandler() { return new MarcoHandler(); } }
上面兩端程式碼中,@Configuration註解的是WebSocket的配置類。這個類指定了/marco對應的處理類,並且通過@Bean向Spring容器中注入了這個處理類。第一段程式碼則是MacroHandler類的實現,它繼承了AbstractWebSock抽象類,實現了處理訊息的方法。
總的來說,上述程式碼客戶端首先和一個服務端名為“/macro”的應用建立了連線。通過這條連線,客戶端給服務端傳送一條訊息“Macro”。服務端的handler會接收到這條訊息,並通過這條通道(WebSocketSession)傳送“polo”給客戶端。客戶端處理訊息的方法onmessage()又會在接收到訊息後呼叫sayMarco()。如此迴圈傳送訊息。這個傳送訊息的過程非同步的,也就是說客戶端給服務端傳送訊息後,不會等待服務端處理完成。所以說WebSocket建立的是一個非同步的全雙工的通訊通道。
通過Sping的STOMP協議實現訊息機制
直接使用WebSocket(或者SockJS)類似於用TCP套接字編寫Web應用。正如HTTP為TCP添加了請求相應模型,定義了傳送內容的語義一樣,STOMP協議定義在WEBSOCKET協議之上,為其定義了訊息的語義。
STOMP的訊息格式和HTTP請求或相應的結構類似:
SEND是命令,表示傳送內容,接下來是兩條頭資訊,destination是傳送訊息的目的地,content-length是負載大小。 接下來一個空行,下面是負載內容,這裡是一個JSON字串。
前端程式碼:
<html>
<head>
<title>Home</title>
<script th:src="@{/webjars/sockjs-client/0.3.4/sockjs.min.js}"></script>
<script th:src="@{/webjars/stomp-websocket/2.3.0/stomp.min.js}"></script>
<script th:src="@{/webjars/jquery/2.0.3/jquery.min.js}"></script>
</head>
<body>
<button id="stop">Stop</button>
<script th:inline="javascript">
var sock = new SockJS([[@{/marcopolo}]]);
var stomp = Stomp.over(sock);
stomp.connect('guest', 'guest', function(frame) {
console.log('***** Connected *****');
stomp.subscribe("/topic/marco", handlePolo);
sayMarco();
});
function handleOneTime(message) {
console.log('Received: ', message);
}
function handlePolo(message) {
console.log('Received: ', message);
$('#output').append("<b>Received: " +
JSON.parse(message.body).message + "</b><br/>")
if (JSON.parse(message.body).message === 'Polo!') {
setTimeout(function(){sayMarco()}, 2000);
}
}
function handleErrors(message) {
console.log('RECEIVED ERROR: ', message);
$('#output').append("<b>GOT AN ERROR!!!: " +
JSON.parse(message.body).message + "</b><br/>")
}
function sayMarco() {
console.log('Sending Marco!');
stomp.send("/app/marco", {},
JSON.stringify({ 'message': 'Marco!' }));
$('#output').append("<b>Send: Marco!</b><br/>")
}
$('#stop').click(function() {sock.close()});
</script>
<div id="output"></div>
</body>
</html>
var sock = new SockJS([[@{/marcopolo}]]);var stomp = Stomp.over(sock);
建立了到/marcopolo的WebSocket的連線之後,呼叫stomp.min.js庫的Stomp物件的over()函式,在sock之上建立stomp客戶端,實際是封裝了SockJS。接下來建立stomp連線,訂閱一個目的地/topic/macro,並把接收道德訊息交給 handlepolo函式去處理。
服務端程式碼:
配置類:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketStompConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/marcopolo").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// registry.enableStompBrokerRelay("/queue", "/topic");
registry.enableSimpleBroker("/queue", "/topic");
registry.setApplicationDestinationPrefixes("/app");
}
controller:
@Controller
public class MarcoController {
private static final Logger logger = LoggerFactory
.getLogger(MarcoController.class);
@MessageMapping("/marco")
public Shout handleShout(Shout incoming) {
logger.info("Received message: " + incoming.getMessage());
try { Thread.sleep(2000); } catch (InterruptedException e) {}
Shout outgoing = new Shout();
outgoing.setMessage("Polo!");
return outgoing;
}
}
可以看到,與前端對應,配置類中註冊了endpoint:/marcopolo, 此外,在配置訊息代理的函式中,啟用了簡單代理,簡單代理會接收目的地字首為/topic和/queue的訊息,而目的地字首為/app的訊息不會交給代理,而是直接路由到帶有@MessageMapping註解的控制器方法中。這個方法的返回值會經過訊息代理髮送到目的地:
傳送訊息到客戶端
Spring提供了兩種方式傳送訊息到客戶端
- 作為處理訊息的附帶結果
- 使用訊息模板SimpleMessagingTemplate
上面的服務端程式碼就是講訊息作為附帶結果返回,返回的目的地是處理方法目的地預設是/macro加上一個/topic字首,也正是前端subscribe()訂閱的目的地。另外還可以通過@sendTo註解來過載目的地,相應的前端要訂閱這個過載的目的地才能收到訊息。
SimpleMessagingTemplate可以在應用的任意地方傳送訊息,不用以接收一條訊息為前提,同時可以發給指定的使用者,基於SpringSecurity。
@Service
public class SpittleFeedServiceImpl implements SpittleFeedService {
private SimpMessagingTemplate messaging;
private Pattern pattern = Pattern.compile("\\@(\\S+)");
@Autowired
public SpittleFeedServiceImpl(SimpMessagingTemplate messaging) {
this.messaging = messaging;
}
public void broadcastSpittle(Spittle spittle) {
messaging.convertAndSend("/topic/spittlefeed", spittle);
Matcher matcher = pattern.matcher(spittle.getMessage());
if (matcher.find()) {
String username = matcher.group(1);
messaging.convertAndSendToUser(username, "/queue/notifications",
new Notification("You just got mentioned!"));
}
}
}
相關推薦
通過WebSocket和STOMP實現瀏覽器和伺服器的訊息通訊
非同步訊息非同步訊息有兩個重要的概念,訊息代理(broker)和目的地(destination)。訊息代理:當一個應用傳送訊息時,需要制定傳送的目的地,然後將訊息交給訊息代理(類似郵局),訊息代理會確保訊息傳送到指定的目的地。目的地:不同的訊息系統有不同的訊息路由模式,但是有
Spring boot:WebSocket+SockJS+Stomp實現廣播和點對點訊息傳送
筆記 廣播式 STS工具新建spring boot專案 使用Thymeleaf和Websocket依賴 pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave
第18章-使用WebSocket和STOMP實現消息功能
control rom rup mpm 空間 except 線路 如何 cto Spring 4.0為WebSocket通信提供了支持,包括: 發送和接收消息的低層級API; 發送和接收消息的高級API; 用來發送消息的模板; 支持SockJS,用來解決瀏覽器端、服務器
Spring 學習——基於Spring WebSocket 和STOMP實現簡單的聊天功能
本篇主要講解如何使用Spring websocket 和STOMP搭建一個簡單的聊天功能專案,裡面使用到的技術,如websocket和STOMP等會簡單介紹,不會太深,如果對相關介紹不是很瞭解的,請自行查閱相關知識。 本篇的專案主要是一個學習Spring we
Java後臺框架篇--spring websocket 和stomp實現訊息功能
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>Home</title> <spring:
第18章 使用WebSocket和 STOMP實現訊息功能
概述: 瀏覽器和伺服器之間傳送訊息在SpringMVC控制器中處理訊息為目標使用者傳送訊息為了解決應用為web應用之間的通訊 Spring4.0 為 WebSocket通訊提供了支援 包括: 傳送和接收訊息的低層級API;傳送和接收訊息的高階API;用來發送訊息的模板
SocketLog-微信除錯、API除錯和AJAX的除錯的工具,能將日誌通過WebSocket輸出到Chrome瀏覽器的console中
說明 SocketLog適合Ajax除錯和API除錯, 舉一個常見的場景,用SocketLog來做微信除錯, 我們在做微信API開發的時候,如果API有bug,微信只提示“改公眾賬號暫時無法提供服務,請稍候再試” ,我們根本不知道API出來什麼問題。 有了Sock
使用spring websocket 和stomp實現訊息功能
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> <html> <head> <title>Home</title> <spring:
spring 使用WebSocket 和 STOMP 實現訊息功能
1)本文旨在 介紹如何 利用 WebSocket 和 STOMP 實現訊息功能; 2)要知道, WebSocket 是傳送和接收訊息的 底層API,而SockJS 是在 WebSocket 之上的 API;最後 STOMP(面向訊息的簡單文字協議)是基於 SockJS 的高
libevent和libcurl實現http和https伺服器 cJSON使用
前言 libevent和libcurl都是功能強大的開源庫;libevent主要實現伺服器,包含了select、epoll等高併發的實現;libcurl實現了curl命令的API封裝,主要作為客戶端。這兩個開源庫的安裝可以參考我的這篇部落格:https://www.cnblogs.com/liudw
Android通過Runtime.getRuntime().exec實現Ping和Traceroute命令時readLine阻塞問題解決
在PC上呼叫cmd,進行一些常用的命令操作,在Android上的是通過Runtime.getRuntime().exec來執行底層Linux下的程式或指令碼(bat)。 首先連線上真機,電腦開啟CMD,輸入adb-shell,確保你要進行的指令碼語言是可以執行的。(比如
Spring Websocket+SockJS+STOMP實現即時通訊(零)—— 要點
Spring Websocket+SockJS+STOMP 實現即時通訊(一)—— 疑問解答 Spring Websocket+SockJS+STOMP 實現即時通訊(二)—— 簡單的訊息代理 Spr
Spring Websocket+SockJS+STOMP 實現即時通訊(三)—— ChannelInterceptor與ExecutorChannelInterceptor
ChannelInterceptor: Message被髮送到執行緒池,在傳送動作執行前(後)攔截,發生在當前執行緒。 ExecutorChannelInterceptor: Message被髮送到執行緒池後,線上程池持有的新執行緒中,在Message
Spring Websocket+SockJS+STOMP 實現即時通訊(四)—— MessageChannel
兩種MessageChannel實現 TemporaryReplyChannel 用於接收單個回覆訊息的臨時通道。在整個斷點除錯過程中沒有追蹤到,所以在這裡不詳細說明。 ExecutorSubscribableChannel 正如字面上所表示的這樣Ex
用ReentrantLock和Condition實現生產者和消費者模式 wait、notify應用場景(生產者-消費者模式)
前面一篇文章《wait、notify應用場景(生產者-消費者模式)》是一種生產者消費者模式實現,今晚這是Lock方式實現,下面是原始碼: 生產者程式碼: /** * 生產者 * * @author tangquanbin * @date 2018/12/18 22:10 */ public
Spring Websocket+SockJS+STOMP 實現即時通訊(六)—— SubProtocolWebSocketHandler
目錄 WebsocketHandler SubProtocolWebSocketHandler 四個重要成員變數 protocolHandlerLookup 子協議
Spring Websocket+SockJS+STOMP 實現即時通訊(四)—— MessageHandler
目錄 MessageHandler的作用 MessageHandler實現類 兩類MessageHandler有什麼區別? MessageHandler的作用 上一節中我們提到過,E
Spring Websocket+SockJS+STOMP 實現即時通訊(五)—— UserRegistryMessageHandler與NoOpMessageHandler
目錄 UserRegistryMessageHandler 處理來自其它應用服務的登錄檔廣播 定期廣播本地登錄檔 使用場景 使用條件 啟用配
Android手機客戶端通過JSP實現與Tomcat伺服器端通訊(Msql資料庫,Json作為載體)--服務端程式碼
伺服器端主要程式碼: 1.首先構建一個Person類,用來儲存使用者資訊 public class Person private String name; private String address; private Integer age; public P
HashTable和HashMap實現原理和區別
HashTable和HashMap都是map介面的實現類,這兩個類的實現原理基本是一致的,都是基於陣列加連結串列的資料結構 一、實現原理: HashTable和HashMap都實現了map介面,只是HashTable繼承了Dictionary抽象類而HashMap繼承了A