Websocket在Java中的實踐——整合Rabbitmq和STOMP

大綱

  • Rabbitmq
    • 開啟STOMP支持
  • 服務端
    • 依賴
    • 參數
    • 參數映射類
    • 配置類
    • 邏輯處理類
  • 測試
    • 測試頁面
    • Controller
    • 測試案例

在《Websocket在Java中的實踐——STOMP通信的最小Demo》一文中,我們使用enableSimpleBroker啟用一個內置的內存級消息代理。本文我們將使用Rabbitmq作為消息代理,這樣我們的服務就可以變成分布式部署。

Rabbitmq

開啟STOMP支持

在Rabbitmq所在的機器上執行下面的命令:

sudo -H -u rabbitmq bash -c "/usr/lib/rabbitmq/bin/rabbitmq-plugins enable rabbitmq_stomp"

在這里插入圖片描述
然后啟動Rabbitmq

sudo service rabbitmq-server start

服務端

依賴

spring-boot-starter-websocket用于Websocket服務。
spring-boot-starter-amqp和spring-rabbit-stream都是用于Rabbitmq操作。
reactor-netty用于Broker。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-stream</artifactId>
</dependency>
<dependency><groupId>io.projectreactor.netty</groupId><artifactId>reactor-netty</artifactId><version>1.1.20</version>
</dependency>

參數

src/main/resources/application.properties
需要注意的是,rabbitmq_stomp啟動后會開啟61613端口。

spring.rabbitmq.host=172.30.254.255
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=fangliang
spring.rabbitmq.stomp.port=61613

在這里插入圖片描述
還有一點需要注意,很多文章上說使用guest用戶登錄。但是guest用戶只能在Rabbitmq所在的機器上使用,如果跨機器使用會報下列錯誤。而且這和是否設置guest為全域無關。所以我們使用admin賬戶。

Received ERROR {message=[Bad CONNECT], content-type=[text/plain], version=[1.0,1.1,1.2], content-length=[26]} session=system text/plain payload=non-loopback access denied

spring.rabbitmq.stomp.port是一個自定義參數,它只是供Broker連接Rabbitmq使用。
spring.rabbitmq.port在當前本文例子中沒有使用。

參數映射類

這個類主要是映射上述參數,方便后續使用。
src/main/java/com/nyctlc/stomprbmq/component/RabbitMQProperties.java

package com.nyctlc.stomprbmq.component;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class RabbitMQProperties {@Value("${spring.rabbitmq.password}")private String rabbitmqPassword;public String getRabbitmqPassword() {return rabbitmqPassword;}@Value("${spring.rabbitmq.username}")private String rabbitmqUsername;public String getRabbitmqUsername() {return rabbitmqUsername;}@Value("${spring.rabbitmq.host}")private String rabbitmqHost;public String getRabbitmqHost() {return rabbitmqHost;}@Value("${spring.rabbitmq.port}")private String rabbitmqPort;public String getRabbitmqPort() {return rabbitmqPort;}@Value("${spring.rabbitmq.stomp.port}")private String rabbitmqStompPort;public String getRabbitmqStompPort() {return rabbitmqStompPort;}
}

配置類

/handshake是STOMP和Websocket建立握手的接口。
enableStompBrokerRelay(“/topic”)會訂閱Rabbitmq默認的交換器amq.topic的綁定關系中定義的隊列。(所以我們看到很多文章訂閱的前綴使用的是“topic”,而不用其他字段,這是有淵源的)
在這里插入圖片描述
在這里插入圖片描述

setRelayPort方法傳遞的是Rabbitmq的STOMP端口,即61613。
setClientLogin、setClientPasscode、setSystemLogin和setSystemPasscode都要設置為admin及其密碼,否則會報錯。

src/main/java/com/nyctlc/stomprbmq/config/WebSocketConfig.java

package com.nyctlc.stomprbmq.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;import com.nyctlc.stomprbmq.component.RabbitMQProperties;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Autowiredprivate RabbitMQProperties rabbitMQProperties;@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/handshake");}@Overridepublic void configureMessageBroker(MessageBrokerRegistry registry) {registry.setApplicationDestinationPrefixes("/send");registry.enableStompBrokerRelay("/topic").setRelayHost(rabbitMQProperties.getRabbitmqHost()).setRelayPort(Integer.parseInt(rabbitMQProperties.getRabbitmqStompPort())).setClientLogin(rabbitMQProperties.getRabbitmqUsername()).setClientPasscode(rabbitMQProperties.getRabbitmqPassword()).setSystemLogin(rabbitMQProperties.getRabbitmqUsername()).setSystemPasscode(rabbitMQProperties.getRabbitmqPassword());}
}

邏輯處理類

這個類的handle方法會接受/send/msg-from-user端點發來的消息,然后轉發給Rabbitmq的amp.topic交換器下msg-to-user路由鍵對應的隊列。上述代碼創建的Broker會持續監聽這個隊列,如果收到消息,則發送給客戶端。

src/main/java/com/nyctlc/stomprbmq/controller/WebSocketController.java

package com.nyctlc.stomprbmq.controller;import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;@Controller
public class WebSocketController {@MessageMapping("/msg-from-user")@SendTo("/topic/msg-to-user")public String handle(String msg) {System.out.println("Received message: " + msg);return msg;}
}

測試

測試頁面

src/main/resources/static/index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>STOMP over WebSocket Example with StompJs.Client</title><script src="https://cdn.jsdelivr.net/npm/@stomp/stompjs"></script>
</head>
<body><h2>STOMP over WebSocket Example with StompJs.Client</h2><button id="connectButton">Connect</button><form id="messageForm"><input type="text" id="messageInput" placeholder="Type a message..."/><button type="submit">Send</button></form><div id="messages"></div><script>var client = null;function connect() {client = new StompJs.Client({brokerURL: 'ws://localhost:8080/handshake', // WebSocket服務端點connectHeaders: {},debug: function (str) {console.log(str);},reconnectDelay: 5000,heartbeatIncoming: 4000,heartbeatOutgoing: 4000,});client.onConnect = function(frame) {console.log('Connected: ' + frame);client.subscribe('/topic/msg-to-user', function(message) { // 訂閱端點showMessageOutput(JSON.parse(message.body).content);});};client.onStompError = function(frame) {console.error('Broker reported error: ' + frame.headers['message']);console.error('Additional details: ' + frame.body);};client.activate();}function sendMessage(event) {event.preventDefault(); // 阻止表單默認提交行為var messageContent = document.getElementById('messageInput').value.trim();if(messageContent && client && client.connected) {var chatMessage = { content: messageContent };client.publish({destination: "/send/msg-from-user", body: JSON.stringify(chatMessage)}); // 發送端點document.getElementById('messageInput').value = '';}}function showMessageOutput(message) {var messagesDiv = document.getElementById('messages');var messageElement = document.createElement('div');messageElement.appendChild(document.createTextNode(message));messagesDiv.appendChild(messageElement);}document.getElementById('messageForm').addEventListener('submit', sendMessage);document.getElementById('connectButton').addEventListener('click', connect);</script>
</body>
</html>

Controller

這個Controller主要是為了讓上述HTML可以通過URL訪問。
src/main/java/com/nyctlc/stomprbmq/controller/FileController.java

package com.nyctlc.stomprbmq.controller;import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;@Controller
public class FileController {@GetMapping("/")public String index() {return "index"; // 返回index.html}@RequestMapping(value = "/favicon.ico")@ResponseStatus(value = HttpStatus.NO_CONTENT)public void favicon() {// No operation. Just to avoid 404 error for favicon.ico}
}

測試案例

在這里插入圖片描述
在這里插入圖片描述
我們在管理后臺直接給這個隊列發送消息,前端頁面也會收到。比如我們發送{“content”:“message from management”}
在這里插入圖片描述
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/43131.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/43131.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/43131.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Unity2D 2022:Particle System】添加拾取粒子特效

一、創建粒子特效游戲物體 二、修改粒子系統屬性 1. 基礎屬性 &#xff08;1&#xff09;修改發射粒子持續時間&#xff08;Duration&#xff09;為3s &#xff08;2&#xff09;取消勾選循環&#xff08;Looping&#xff09; &#xff08;2&#xff09;修改粒子存在時間&…

SQL性能優化策略

發現問題 通過業務監控發現慢SQL或接口響應延遲。利用性能分析工具定位問題。 定位SQL語句 使用監控工具確定影響性能的SQL語句和表。 SQL查詢變慢原因 索引失效&#xff1a;查詢未使用索引或索引效率低。多表連接&#xff1a;JOIN操作導致性能下降。查詢字段過多&#xf…

Monitor結構解讀之EntryQ和WaitSet的區別

EntryQ&#xff08;或_EntryList&#xff09;和WaitSet&#xff08;或_WaitSet&#xff09;在Java的monitor機制中扮演著不同的角色&#xff0c;它們之間的主要區別體現在以下幾個方面&#xff1a; 1. 等待原因和機制 EntryQ&#xff08;或_EntryList&#xff09;&#xff1a…

面試常考題---128陷阱(詳細)

1.問題引入 分別引入了int和Integer變量&#xff0c;并進行比較 int b 128; int b1 128;Integer d 127; Integer d1 127;Integer e 128; Integer e1 128;System.out.println(bb1); System.out.println(dd1); System.out.println(ee1); System.out.println(e.equals(e1)…

刷題(day01)

1、leetcode485.最大連續1的個數 給定一個二進制數組 nums &#xff0c; 計算其中最大連續 1 的個數。 示例 1&#xff1a; 輸入&#xff1a;nums [1,1,0,1,1,1] 輸出&#xff1a;3 解釋&#xff1a;開頭的兩位和最后的三位都是連續 1 &#xff0c;所以最大連續 1 的個數是 3.…

Nginx 高效加速策略:動靜分離與緩存詳解

在現代Web開發中&#xff0c;網站性能是衡量用戶體驗的關鍵指標之一。Nginx&#xff0c;以其出色的性能和靈活性&#xff0c;成為眾多網站架構中不可或缺的一部分。本文將深度解析如何利用Nginx實現動靜分離與緩存&#xff0c;從而大幅提升網站加載速度和響應效率。 理解動靜分…

昇思第18天打卡|ShuffleNet圖像分類

ShuffleNet網絡介紹 ShuffleNetV1是曠視科技提出的一種計算高效的CNN模型&#xff0c;和MobileNet, SqueezeNet等一樣主要應用在移動端&#xff0c;所以模型的設計目標就是利用有限的計算資源來達到最好的模型精度。ShuffleNetV1的設計核心是引入了兩種操作&#xff1a;Pointw…

張大哥筆記:你一旦開竅,就會發現遍地都是錢

大家有沒有發現&#xff0c;窮人總是追逐眼前的利益&#xff0c;總是在追著錢跑&#xff0c;卻總是賺不到錢。而富人有著長遠的見識&#xff0c;追著問題跑&#xff0c;最后卻賺的盆滿缽滿。 我們聽過這樣一句話&#xff0c;錢不是賺來的&#xff0c;而是幫助別人解決問題后給你…

【計算機】同步/異步

同步/異步 在計算機科學和編程中&#xff0c;“同步”&#xff08;Synchronization&#xff09;是一種機制&#xff0c;用于協調不同進程或線程之間的操作&#xff0c;以避免競態條件&#xff08;race conditions&#xff09;、死鎖&#xff08;deadlocks&#xff09;和其他并…

Qt/C++編寫地圖應用/離線地圖下載/路徑規劃/軌跡回放/海量點/坐標轉換

一、前言說明 這個地圖組件寫了很多年了&#xff0c;最初設計的比較粗糙&#xff0c;最開始只是為了滿足項目需要&#xff0c;并沒有考慮太多拓展性&#xff0c;比如最初都是按照百度地圖寫死在代碼中&#xff0c;經過這幾年大量的現場實際應用&#xff0c;以及大量的用戶提出…

Django 新增數據 save()方法

1&#xff0c;添加模型 Test/app11/models.py from django.db import modelsclass Book(models.Model):title models.CharField(max_length100)author models.CharField(max_length100)publication_date models.DateField()price models.DecimalField(max_digits5, decim…

BFC 是什么?

BFC 是塊級格式化上下文&#xff08;Block Formatting Context&#xff09;的縮寫&#xff0c;是 CSS 中一個重要的概念&#xff0c;用于控制塊級盒子的布局及浮動元素的交互。BFC 是一個獨立的渲染區域&#xff0c;內部的塊級盒子會按照特定的規則進行布局&#xff0c;不會影響…

軟件工程(上)

目錄 軟件過程模型&#xff08;軟件開發模型&#xff09; 瀑布模型 原型模型 V模型 構件組裝模型 螺旋模型&#xff08;原型瀑布&#xff09; 基于構件的軟件工程&#xff08;CBSE&#xff09; 快速應用開發模型&#xff08;RAD&#xff09; 統一過程&#xff08;UP&a…

Linux學習看這一篇就夠了,超超超牛的Linux基礎入門

引言 小伙伴們&#xff0c;不管是學習c還是學習其他語言在我們學的路上都繞不過操作系統&#xff0c;而且&#xff0c;老生常談的Linux更是每個計算機人的必修&#xff0c;那么我們對Linux的了解可能只是從別人那聽到的簡單的這個系統很牛&#xff0c;巴拉巴拉的&#xff0c;但…

大模型日報 2024-07-08

大模型日報 2024-07-08 大模型資訊 Anthropic CEO&#xff1a;大模型訓練成本暴漲&#xff0c;2027年將達1000億美元&#xff01; Anthropic首席執行官表示&#xff0c;當前AI模型訓練成本是10億美元&#xff0c;未來三年&#xff0c;這個數字可能會上升到100億美元甚至1000億美…

GitLab管理員常用配置及設置匯總

? 之前在 虛擬機Ubuntu 22.04上搭建GitLab操作步驟 上介紹了在Ubuntu 22.04上如何搭建社區版的GitLab&#xff0c;這里整理下作為GitLab管理員時在搭建完GitLab CE后&#xff0c;如何對其進行配置或設置 更改倉庫存儲位置&#xff1a;切換到root用戶下操作 默認存放位置&…

SSL 證書

自動獲取 Lets Encrypt 免費證書 &#xff08;適用于 Linux 系統&#xff09; 安裝 Certbot sudo apt-get update sudo apt-get install certbot python3-certbot-nginx # Nginx 服務器 sudo apt-get install certbot python3-certbot-apache # Apache 服務器 獲取和安裝證…

小米rdemi紅米ax3000t刷機 20240707最新配套完整程序整理合集

小米rdemi紅米ax3000t刷機程序地址&#xff1a; https://www.123pan.com/s/LA1bVv-EOzVv.html 小米路由器SSH密碼計算器 https://www.1234f.com/fuwu/ax3000t/ 最新更新地址&#xff1a;https://www.1234f.com/fuwu/openwrt/ 依次輸入如下命令&#xff1a; curl -X POST h…

Leetcode 295.數據流的中位數

295.數據流的中位數 問題描述 中位數是有序整數列表中的中間值。如果列表的大小是偶數&#xff0c;則沒有中間值&#xff0c;中位數是兩個中間值的平均值。 例如 arr [2,3,4] 的中位數是 3 。例如 arr [2,3] 的中位數是 (2 3) / 2 2.5 。 實現 MedianFinder 類: Media…