最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊的方法詳解

 更新時(shí)間:2022年05月19日 15:32:54   作者:june-YiDai  
這篇文章主要為大家詳細(xì)介紹了如何利用SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊功能,文中示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定參考價(jià)值,需要的可以參考一下

環(huán)境信息

名稱版本號(hào)
Spring Boot2.4.5
Idea2021.3.2

服務(wù)端實(shí)現(xiàn)

導(dǎo)入依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

注意:Spring Boot在父工程中已經(jīng)管理了websocket的版本信息,所以不用指定版本號(hào)也是可以的

創(chuàng)建配置類

package com.fenzhichuanmei.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author Yi Dai 484201132@qq.com
 * @since 2022/5/13 11:34
 */

@Configuration
public class WebsocketConfiguration {

    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

創(chuàng)建此配置類的目的只是為了把ServerEndpointExporter 這個(gè)類的實(shí)例交給spring 容器進(jìn)行管理,您可以用任意一種方式交給容器,如使用@Import(ServerEndpointExporter.class)這種方式等進(jìn)行操作;此處只是我的編碼風(fēng)格如此;并非必須這樣操作

創(chuàng)建一個(gè)注解式的端點(diǎn)并在其中通過(guò)配套注解聲明回調(diào)方法

package com.fenzhichuanmei.websocket;

import com.fenzhichuanmei.websocket.utils.SessionManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

/**
 * @author Yi Dai 484201132@qq.com
 * @since 2022/3/7 15:47
 */

@Slf4j
@Component
@ServerEndpoint("/arcticFoxServerEndpoint/{websocketClientType}")
public class ArcticFoxServerEndpoint {

    private static SessionManager sessionManager;

    @Resource
    public void setProcessor(SessionManager sessionManager) {
        ArcticFoxServerEndpoint.sessionManager = sessionManager;
    }

    /**
     * 建立連接成功的回調(diào)方法
     *
     * @param session             會(huì)話對(duì)象
     * @param websocketClientType 此參數(shù)就是路徑中{websocketClientType}位置傳入的參數(shù)
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("websocketClientType") int websocketClientType) {
        sessionManager.onOpen(session, websocketClientType);
    }

    /**
     * 當(dāng)會(huì)話關(guān)閉時(shí)執(zhí)行的回調(diào)方法
     *
     * @param session             會(huì)話對(duì)象
     * @param websocketClientType 此參數(shù)就是路徑中{websocketClientType}位置傳入的參數(shù)
     */
    @OnClose
    public void onClose(Session session, @PathParam("websocketClientType") int websocketClientType) {
        sessionManager.onClose(session, websocketClientType);
    }

    /**
     * 當(dāng)收到客戶端信息時(shí)執(zhí)行的回調(diào)方法
     *
     * @param session             會(huì)話對(duì)象
     * @param message             客戶端傳遞過(guò)來(lái)的信息
     * @param websocketClientType 此參數(shù)就是路徑中{websocketClientType}位置傳入的參數(shù)
     */
    @OnMessage
    public void onMessage(Session session, String message, @PathParam("websocketClientType") int websocketClientType) {
        sessionManager.onMessage(session, message, websocketClientType);
    }

    /**
     * 當(dāng)發(fā)生錯(cuò)誤時(shí)的回調(diào)方法
     *
     * @param session             會(huì)話對(duì)象
     * @param e                   異常對(duì)象
     * @param websocketClientType 此參數(shù)就是路徑中{websocketClientType}位置傳入的參數(shù)
     */
    @OnError
    public void onError(Session session, Throwable e, @PathParam("websocketClientType") int websocketClientType) {
        sessionManager.onError(session, e, websocketClientType);
    }

}

@ServerEndpoint注解標(biāo)注此類為一個(gè)服務(wù)端的端點(diǎn)類,此注解有一個(gè)必須的參數(shù),用于指定客戶端訪問(wèn)的地址,本案例中為:/arcticFoxServerEndpoint,而路徑后面的/{websocketClientType}這個(gè)是路徑中參數(shù)的占位符,有點(diǎn)類似與Spring Mvc中Rest接口和@PathVariable注解的作用

注意事項(xiàng): 一定要將此類交給spring 容器進(jìn)行管理??!還有一個(gè)坑就是,此類的實(shí)例時(shí)非單例的,所以如果要在此類中注入其他的bean,不能使直接在屬性上使用@Resource注解或者@Autowired等注解進(jìn)行注入,否則會(huì)報(bào)錯(cuò)。正確操作應(yīng)該是把要注入的字段設(shè)置為靜態(tài)的,然后通過(guò)非靜態(tài)的set方法進(jìn)行注入,具體代碼請(qǐng)看上方實(shí)例

服務(wù)端主動(dòng)發(fā)送消息給客戶端

通過(guò)上面的代碼我們可以知道每個(gè)回調(diào)方法中都會(huì)收到一個(gè)Session對(duì)象,正如您所想,要向客戶端發(fā)送消息正是要借助此對(duì)象;Session對(duì)象有一個(gè)getAsyncRemote方法,調(diào)用此方法可以得到一個(gè)RemoteEndpoint.Async對(duì)象,查看此對(duì)象,發(fā)現(xiàn)有很多send打頭的方法;

是的,這些方法就是發(fā)送消息的方法,博主這個(gè)項(xiàng)目中主要是通過(guò)JSON來(lái)進(jìn)行交互的,所以我使用了sendText方法,示例代碼:

RemoteEndpoint.Async asyncRemote = session.getAsyncRemote();
asyncRemote.sendText(jsonString);

很顯然中轉(zhuǎn)變量asyncRemote 沒(méi)什么太大的用處,不如直接寫成:

session.getAsyncRemote().sendText(jsonString);

通過(guò)方法名看到,似乎還可以發(fā)送對(duì)象,二進(jìn)制序列等,博主沒(méi)有深入研究,有興趣的小伙伴可以嘗試嘗試

客戶端實(shí)現(xiàn)

一般來(lái)講客戶端應(yīng)該是用Java Script實(shí)現(xiàn),但是博主這個(gè)項(xiàng)目比較特殊,需要用Java來(lái)實(shí)現(xiàn)客戶端,下面博主先以Java客戶端說(shuō)明其實(shí)現(xiàn)細(xì)節(jié),然后再說(shuō)再前端如何實(shí)現(xiàn)

Java客戶端實(shí)現(xiàn)

導(dǎo)入依賴

<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.3</version>
</dependency>

其實(shí)Java中實(shí)現(xiàn)WebSocket的第三方包還有很多,博主這個(gè)地方使用的是Java-WebSocket,有興趣的小伙伴可以試試其他的包

建立連接和處理回調(diào)

package com.fenzhichuanmei.websocket;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fenzhichuanmei.components.PaymentComponent;
import com.fenzhichuanmei.pojo.Instructions;
import com.fenzhichuanmei.utils.WebsocketClientType;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.enums.ReadyState;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.net.URI;
import java.net.URISyntaxException;

/**
 * @author Yi Dai 484201132@qq.com
 * @since 2022/5/13 10:16
 */

@Slf4j
@Component
public class ArcticFoxWebSocketClient {

    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private PaymentComponent paymentComponent;

    @Resource
    private ArcticFoxWebSocketClientProperties properties;

    public void establishConnection() throws URISyntaxException {
        WebSocketClient webSocketClient = new WebSocketClient(new URI(String.format("%s/%d", properties.getWebSocketServerUrl(), WebsocketClientType.PAYMENT_DEVICE))) {
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                log.info("WebSocketClient: onOpen : {}", serverHandshake);
            }

            @Override
            public void onMessage(String jsonString) {
                try {
                    Instructions instructions = objectMapper.readValue(jsonString, Instructions.class);
                    if (instructions.getType() == Instructions.NOTICE_PAYMENT) {
                        paymentComponent.queryAnUnpaidOrdersAndPay();
                    } else {
                        throw new RuntimeException("錯(cuò)誤的指令類型");
                    }
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onClose(int i, String s, boolean b) {
                log.info("WebSocketClient: onClose : i:{},s:{},b:{}", i, s, b);
                try {
                    Thread.sleep(1000 * 20);
                    establishConnection();
                } catch (InterruptedException | URISyntaxException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onError(Exception e) {
                log.error("WebSocketClient: onError {}", e.getMessage());
            }
        };
        webSocketClient.connect();
        while (!(webSocketClient.getReadyState() == ReadyState.OPEN)) {
            try {
                Thread.sleep(1000 * 2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        log.info("WebSocketClient: connection established successfully");
    }


    @Data
    @Component
    @ConfigurationProperties("arctic-fox-web-socket-client.properties")
    public static class ArcticFoxWebSocketClientProperties {

        private String webSocketServerUrl;

    }
}

代碼解釋: 其實(shí)我的establishConnection方法中上來(lái)就實(shí)例化了一個(gè)WebSocketClient 類的實(shí)例,請(qǐng)注意,此類是個(gè)抽象類,我在這里用匿名實(shí)現(xiàn)類的方式實(shí)現(xiàn)的,此類有幾個(gè)抽象方法需要實(shí)現(xiàn),也就是onOpen,onMessage,onClose,onError四個(gè)方法,其作用其實(shí)已經(jīng)是很見名知意了,和服務(wù)端的回調(diào)方法一樣,就不過(guò)多解釋;實(shí)例化此類需要傳入一個(gè)URI對(duì)象,這個(gè)URI對(duì)象其實(shí)就是封裝了對(duì)服務(wù)端連接的地址,由于博主不希望把服務(wù)端的地址給寫死了,所以我配置到了配置文件中,然后通過(guò)String.format靜態(tài)方法配合占位符拼接url地址和參數(shù);路徑的規(guī)則是:協(xié)議名://IP地址(或域名):端口號(hào)/服務(wù)端聲明的地址/參數(shù);舉個(gè)例子:

ws://192.168.88.88:8080/arcticFoxServerEndpoint/1

ws://localhost:8080/arcticFoxServerEndpoint/2

ws://為協(xié)議;實(shí)例化WebSocketClient 類的實(shí)例之后,調(diào)用其connect()方法即開始建立連接,調(diào)用getReadyState()方法可以獲得其狀態(tài);由于我的服務(wù)端可能隨時(shí)都連不上,所以我在客戶端的onClose回調(diào)函數(shù)中進(jìn)行了一個(gè)遞歸(20秒后),用于重新連接。

客戶端向服務(wù)端發(fā)送消息

通過(guò)WebSocketClient 類的實(shí)例,我們可以看到有以下方法,很明顯send方法就是用來(lái)發(fā)送消息使用的

示例代碼:

//判斷一下是否為空
if (Objects.nonNull(webSocketClient)) {
    try {
    	//通過(guò)jackson將對(duì)象轉(zhuǎn)換為json字符串(非必須)
        String jsonString = objectMapper.writeValueAsString(feedback);
        //發(fā)送信息
        webSocketClient.send(jsonString);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
} else {
    log.warn("no connection established");
}

在前端環(huán)境(vue)中使用websocket

安裝reconnecting-websocket包(非必須)

npm i --save reconnecting-websocket

安裝這個(gè)包是為了websocket能在斷線之后重新連接,其實(shí)不使用這個(gè)包也是可以用原生Java Script實(shí)現(xiàn)的;但是他和原生的api幾乎一樣;

示例代碼:

import ReconnectingWebSocket from "reconnecting-websocket";

export default function initializationWebsocket() {
    let reconnectingWebSocket = new ReconnectingWebSocket(`ws://localhost:8080/arcticFoxServerEndpoint/${2}`);
    reconnectingWebSocket.onopen = event => {
        console.log("on open :", event);
    };

    reconnectingWebSocket.onmessage = event => {
    	//event對(duì)象中data存儲(chǔ)的就是服務(wù)端發(fā)送過(guò)來(lái)的消息
        let parse = JSON.parse(event.data);
        console.log("webSocket on message :", parse);
    };

    reconnectingWebSocket.onclose = event => {
        console.log(event);
    };

    reconnectingWebSocket.onerror = event => {
        console.log(event);
    };
	
	//窗口關(guān)閉時(shí)斷開連接
    window.onbeforeunload = function () {
        reconnectingWebSocket.close();
    }
}

在前端中實(shí)現(xiàn)websocket就比較簡(jiǎn)單了,就上面的幾行代碼即可,不用調(diào)用其他函數(shù)進(jìn)行連接,實(shí)例化之后就開始連接了

想服務(wù)端發(fā)送信息

在前端中發(fā)送信息就更簡(jiǎn)單了,直接調(diào)用reconnectingWebSocketsend方法,傳入要發(fā)送的數(shù)據(jù)即可

到此這篇關(guān)于SpringBoot+WebSocket實(shí)現(xiàn)即時(shí)通訊的方法詳解的文章就介紹到這了,更多相關(guān)SpringBoot WebSocket即時(shí)通訊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java Kafka分區(qū)發(fā)送及消費(fèi)實(shí)戰(zhàn)

    Java Kafka分區(qū)發(fā)送及消費(fèi)實(shí)戰(zhàn)

    本文主要介紹了Kafka分區(qū)發(fā)送及消費(fèi)實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Java搜索與圖論之DFS和BFS算法詳解

    Java搜索與圖論之DFS和BFS算法詳解

    DFS指在進(jìn)行算法運(yùn)算時(shí),優(yōu)先將該路徑的當(dāng)前路徑執(zhí)行完畢,執(zhí)行完畢或失敗后向上回溯嘗試其他途徑。BFS指在進(jìn)行算法運(yùn)算時(shí),優(yōu)先將當(dāng)前路徑點(diǎn)的所有情況羅列出來(lái),然后根據(jù)羅列出來(lái)的情況羅列下一層。本文介紹了二者的實(shí)現(xiàn)與應(yīng)用,需要的可以參考一下
    2022-11-11
  • SpringBoot+Dubbo+Zookeeper知識(shí)整合過(guò)程詳解

    SpringBoot+Dubbo+Zookeeper知識(shí)整合過(guò)程詳解

    本文首先介紹了分布式系統(tǒng)的基本概念和分類,包括單一應(yīng)用架構(gòu)、垂直應(yīng)用架構(gòu)、分布式服務(wù)架構(gòu)和流動(dòng)計(jì)算架構(gòu),通過(guò)一個(gè)完整的Spring Boot + Dubbo + Zookeeper框架搭建示例,展示了如何將這些技術(shù)整合到一個(gè)實(shí)際的項(xiàng)目中,感興趣的朋友一起看看吧
    2025-02-02
  • 最新評(píng)論

    门头沟区| 沙田区| 阳曲县| 红安县| 封开县| 项城市| 恩施市| 鸡东县| 三都| 六盘水市| 涿州市| 新晃| 大埔区| 达孜县| 新龙县| 浮梁县| 鹿泉市| 衡阳县| 台安县| 色达县| 杨浦区| 大埔区| 东宁县| 石河子市| 青州市| 文安县| 龙口市| 三原县| 鄱阳县| 安顺市| 亳州市| 兴山县| 温宿县| 建平县| 临湘市| 南江县| 福海县| 河东区| 仪征市| 诸暨市| 屏南县|