1. Springboot整合websocket實(shí)現(xiàn)一對一消息推送和廣播消息推送

        共 5916字,需瀏覽 12分鐘

         ·

        2020-12-23 10:20

        作者:kunm

        segmentfault.com/a/1190000011908831

        springboot基礎(chǔ)環(huán)境

        請參考springboot文檔

        maven依賴
        ????????<dependency>
        ????????????<groupId>org.springframework.bootgroupId>
        ????????????<artifactId>spring-boot-starter-websocketartifactId>
        ????????dependency>
        代碼準(zhǔn)備
        準(zhǔn)備常量類
        ????//webSocket相關(guān)配置
        ????//鏈接地址
        ????public?static?String?WEBSOCKETPATHPERFIX?=?"/ws-push";
        ????public?static?String?WEBSOCKETPATH?=?"/endpointWisely";
        ????//消息代理路徑
        ????public?static?String?WEBSOCKETBROADCASTPATH?=?"/topic";
        ????//前端發(fā)送給服務(wù)端請求地址
        ????public?static?final?String?FORETOSERVERPATH?=?"/welcome";
        ????//服務(wù)端生產(chǎn)地址,客戶端訂閱此地址以接收服務(wù)端生產(chǎn)的消息
        ????public?static?final?String?PRODUCERPATH?=?"/topic/getResponse";
        ????//點(diǎn)對點(diǎn)消息推送地址前綴
        ????public?static?final?String?P2PPUSHBASEPATH?=?"/user";
        ????//點(diǎn)對點(diǎn)消息推送地址后綴,最后的地址為/user/用戶識別碼/msg
        ????public?static?final?String?P2PPUSHPATH?=?"/msg";
        接收前端消息實(shí)體
        public?class?WiselyMessage?{
        ????private?String?name;

        ????public?String?getName()?{
        ????????return?name;
        ????}

        ????public?void?setName(String?name)?{
        ????????this.name?=?name;
        ????}
        }
        后臺發(fā)送消息實(shí)體
        private?String?responseMessage;

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

        ????public?String?getResponseMessage()?{
        ????????return?responseMessage;
        ????}

        ????public?void?setResponseMessage(String?responseMessage)?{
        ????????this.responseMessage?=?responseMessage;
        ????}
        配置websocket
        @Configuration
        //?@EnableWebSocketMessageBroker注解用于開啟使用STOMP協(xié)議來傳輸基于代理(MessageBroker)的消息,這時(shí)候控制器(controller)
        //?開始支持@MessageMapping,就像是使用@requestMapping一樣。
        @EnableWebSocketMessageBroker
        public?class?WebSocketConfig?extends?AbstractWebSocketMessageBrokerConfigurer?{

        ????@Override
        ????public?void?registerStompEndpoints(StompEndpointRegistry?stompEndpointRegistry)?{
        ????????//注冊一個(gè)Stomp的節(jié)點(diǎn)(endpoint),并指定使用SockJS協(xié)議。
        ????????stompEndpointRegistry.addEndpoint(Constant.WEBSOCKETPATH).withSockJS();
        ????}

        ????@Override
        ????public?void?configureMessageBroker(MessageBrokerRegistry?registry)?{
        ????????//服務(wù)端發(fā)送消息給客戶端的域,多個(gè)用逗號隔開
        ????????registry.enableSimpleBroker(Constant.WEBSOCKETBROADCASTPATH,?Constant.P2PPUSHBASEPATH);
        ????????//定義一對一推送的時(shí)候前綴
        ????????registry.setUserDestinationPrefix(Constant.P2PPUSHBASEPATH);
        ????????//定義websoket前綴
        ????????registry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX);
        ????}
        }
        service
        @Service
        public?class?WebSocketService?{

        ????@Autowired
        ????private?SimpMessagingTemplate?template;

        ????/**
        ?????*?廣播
        ?????*?發(fā)給所有在線用戶
        ?????*
        ?????*?@param?msg
        ?????*/

        ????public?void?sendMsg(WiselyResponse?msg)?{
        ????????template.convertAndSend(Constant.PRODUCERPATH,?msg);
        ????}

        ????/**
        ?????*?發(fā)送給指定用戶
        ?????*?@param?users
        ?????*?@param?msg
        ?????*/

        ????public?void?send2Users(List?users,?WiselyResponse?msg)?{
        ????????users.forEach(userName?->?{
        ????????????template.convertAndSendToUser(userName,?Constant.P2PPUSHPATH,?msg);
        ????????});
        ????}
        }
        控制器
        @Controller
        public?class?WsController?{

        ????@Resource
        ????WebSocketService?webSocketService;

        ????@MessageMapping(Constant.FORETOSERVERPATH)//@MessageMapping和@RequestMapping功能類似,用于設(shè)置URL映射地址,瀏覽器向服務(wù)器發(fā)起請求,需要通過該地址。
        ????@SendTo(Constant.PRODUCERPATH)//如果服務(wù)器接受到了消息,就會(huì)對訂閱了@SendTo括號中的地址傳送消息。
        ????public?WiselyResponse?say(WiselyMessage?message)?throws?Exception?{
        ????????List?users?=?Lists.newArrayList();
        ????????users.add("d892bf12bf7d11e793b69c5c8e6f60fb");//此處寫死只是為了方便測試,此值需要對應(yīng)頁面中訂閱個(gè)人消息的userId
        ????????webSocketService.send2Users(users,?new?WiselyResponse("admin?hello"));

        ????????return?new?WiselyResponse("Welcome,?"?+?message.getName()?+?"!");
        ????}
        }
        頁面

        <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">貌似你的瀏覽器不支持websocketh2>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();">發(fā)送button>
        ????????<p?id="response">p>
        ????????<p?id="response1">p>
        ????div>
        div>

        <script?src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js">script>
        <script?src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js">script>
        <script?src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js">script>
        <script?th:inline="javascript">
        ????var?stompClient?=?null;
        ????//此值有服務(wù)端傳遞給前端,實(shí)現(xiàn)方式?jīng)]有要求
        ????var?userId?=?[[${userId}]];

        ????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連接SockJS的endpoint是“endpointWisely”,與后臺代碼中注冊的endpoint要一樣。
        ????????stompClient?=?Stomp.over(socket);//2創(chuàng)建STOMP協(xié)議的webSocket客戶端。
        ????????stompClient.connect({},?function(frame)?{//3連接webSocket的服務(wù)端。
        ????????????setConnected(true);
        ????????????console.log('開始進(jìn)行連接Connected:?'?+?frame);
        ????????????//4通過stompClient.subscribe()訂閱服務(wù)器的目標(biāo)是'/topic/getResponse'發(fā)送過來的地址,與@SendTo中的地址對應(yīng)。
        ????????????stompClient.subscribe('/topic/getResponse',?function(respnose){
        ????????????????showResponse(JSON.parse(respnose.body).responseMessage);
        ????????????});
        ????????????//4通過stompClient.subscribe()訂閱服務(wù)器的目標(biāo)是'/user/'?+?userId?+?'/msg'接收一對一的推送消息,其中userId由服務(wù)端傳遞過來,用于表示唯一的用戶,通過此值將消息精確推送給一個(gè)用戶
        ????????????stompClient.subscribe('/user/'?+?userId?+?'/msg',?function(respnose){
        ????????????????console.log(respnose);
        ????????????????showResponse1(JSON.parse(respnose.body).responseMessage);
        ????????????});
        ????????});
        ????}


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

        ????function?sendName()?{
        ????????var?name?=?$('#name').val();
        ????????//通過stompClient.send()向地址為"/welcome"的服務(wù)器地址發(fā)起請求,與@MessageMapping里的地址對應(yīng)。因?yàn)槲覀兣渲昧藃egistry.setApplicationDestinationPrefixes(Constant.WEBSOCKETPATHPERFIX);所以需要增加前綴/ws-push/
        ????????stompClient.send("/ws-push/welcome",?{},?JSON.stringify({?'name':?name?}));
        ????}

        ????function?showResponse(message)?{
        ????????var?response?=?$("#response");
        ????????response.html(message);
        ????}
        ????function?showResponse1(message)?{
        ????????var?response?=?$("#response1");
        ????????response.html(message);
        ????}
        script>
        body>
        html>
        測試


        點(diǎn)擊連接控制臺輸出

        表示連接成功并且訂閱了兩個(gè)地址

        此時(shí)在文本框內(nèi)輸入任意值,結(jié)果如圖所示則代表成功

        控制臺中顯示依次為,發(fā)送信息,目標(biāo)長度內(nèi)容

        此時(shí)服務(wù)端控制器接收到請求

        同時(shí)給指定用戶發(fā)送了消息,所以控制臺接收到消息

        同時(shí)因?yàn)榭刂破饔凶⒔釦SendTo所以會(huì)向@SendTo的地址廣播消息,客戶端訂閱了廣播地址所有控制臺顯示接收了消息


        推薦閱讀

        面試題:InnoDB 中一棵 B+ 樹能存多少行數(shù)據(jù)?【面試不翻車,翻車就跑路】

        我畫了35張圖就是為了讓你深入 AQS

        Map 集合怎么也有這么多坑?一不小心又踩了好幾個(gè)!

        瀏覽 94
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 亚洲午夜成人精品一区二区 | 国产第一夜 | 国产交换配乱淫视频a免费 | 男女在床干事免费视频 | 久久五月天影院 |