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

java后端+前端使用WebSocket實現(xiàn)消息推送的詳細(xì)流程

 更新時間:2022年10月27日 12:04:23   作者:poker_zero  
后端向前端推送消息就需要長連接,首先想到的就是websocket,下面這篇文章主要給大家介紹了關(guān)于java后端+前端使用WebSocket實現(xiàn)消息推送的詳細(xì)流程,需要的朋友可以參考下

 

前言

在項目的開發(fā)時,遇到實現(xiàn)服務(wù)器主動發(fā)送數(shù)據(jù)到前端頁面的功能的需求。實現(xiàn)該功能不外乎使用輪詢和websocket技術(shù),但在考慮到實時性和資源損耗后,最后決定使用websocket?,F(xiàn)在就記錄一下用Java實現(xiàn)Websocket技術(shù)吧~

Java實現(xiàn)Websocket通常有兩種方式:1、創(chuàng)建WebSocketServer類,里面包含open、close、message、error等方法;2、利用Springboot提供的webSocketHandler類,創(chuàng)建其子類并重寫方法。我們項目雖然使用Springboot框架,不過仍采用了第一種方法實現(xiàn)。

創(chuàng)建WebSocket的簡單實例操作流程

1.引入Websocket依賴

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.0</version>
        </dependency>

2.創(chuàng)建配置類WebSocketConfig

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

/**
 * 開啟WebSocket支持
 */
@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

3.創(chuàng)建WebSocketServer

在websocket協(xié)議下,后端服務(wù)器相當(dāng)于ws里面的客戶端,需要用@ServerEndpoint指定訪問路徑,并使用@Component注入容器

@ServerEndpoint:當(dāng)ServerEndpointExporter類通過Spring配置進(jìn)行聲明并被使用,它將會去掃描帶有@ServerEndpoint注解的類。被注解的類將被注冊成為一個WebSocket端點。所有的配置項都在這個注解的屬性中
( 如:@ServerEndpoint(“/ws”) )

下面的栗子中@ServerEndpoint指定訪問路徑中包含sid,這個是用于區(qū)分每個頁面

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目前的類定義成一個websocket服務(wù)器端,
 * 注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址,客戶端可以通過這個URL來連接到WebSocket服務(wù)器端
 */
@ServerEndpoint("/notice/{userId}")
@Component
@Slf4j
public class NoticeWebsocket {

    //記錄連接的客戶端
    public static Map<String, Session> clients = new ConcurrentHashMap<>();

    /**
     * userId關(guān)聯(lián)sid(解決同一用戶id,在多個web端連接的問題)
     */
    public static Map<String, Set<String>> conns = new ConcurrentHashMap<>();

    private String sid = null;

    private String userId;


    /**
     * 連接成功后調(diào)用的方法
     * @param session
     * @param userId
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.sid = UUID.randomUUID().toString();
        this.userId = userId;
        clients.put(this.sid, session);

        Set<String> clientSet = conns.get(userId);
        if (clientSet==null){
            clientSet = new HashSet<>();
            conns.put(userId,clientSet);
        }
        clientSet.add(this.sid);
        log.info(this.sid + "連接開啟!");
    }

    /**
     * 連接關(guān)閉調(diào)用的方法
     */
    @OnClose
    public void onClose() {
        log.info(this.sid + "連接斷開!");
        clients.remove(this.sid);
    }

    /**
     * 判斷是否連接的方法
     * @return
     */
    public static boolean isServerClose() {
        if (NoticeWebsocket.clients.values().size() == 0) {
            log.info("已斷開");
            return true;
        }else {
            log.info("已連接");
            return false;
        }
    }

    /**
     * 發(fā)送給所有用戶
     * @param noticeType
     */
    public static void sendMessage(String noticeType){
        NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
        noticeWebsocketResp.setNoticeType(noticeType);
        sendMessage(noticeWebsocketResp);
    }


    /**
     * 發(fā)送給所有用戶
     * @param noticeWebsocketResp
     */
    public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp){
        String message = JSONObject.toJSONString(noticeWebsocketResp);
        for (Session session1 : NoticeWebsocket.clients.values()) {
            try {
                session1.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 根據(jù)用戶id發(fā)送給某一個用戶
     * **/
    public static void sendMessageByUserId(String userId, NoticeWebsocketResp noticeWebsocketResp) {
        if (!StringUtils.isEmpty(userId)) {
            String message = JSONObject.toJSONString(noticeWebsocketResp);
            Set<String> clientSet = conns.get(userId);
            if (clientSet != null) {
                Iterator<String> iterator = clientSet.iterator();
                while (iterator.hasNext()) {
                    String sid = iterator.next();
                    Session session = clients.get(sid);
                    if (session != null) {
                        try {
                            session.getBasicRemote().sendText(message);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 收到客戶端消息后調(diào)用的方法
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到來自窗口"+this.userId+"的信息:"+message);
    }

    /**
     * 發(fā)生錯誤時的回調(diào)函數(shù)
     * @param error
     */
    @OnError
    public void onError(Throwable error) {
        log.info("錯誤");
        error.printStackTrace();
    }
}

封裝了一個發(fā)送消息的對象可以直接使用

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("ws通知返回對象")
public class NoticeWebsocketResp<T> {

    @ApiModelProperty(value = "通知類型")
    private String noticeType;

    @ApiModelProperty(value = "通知內(nèi)容")
    private T noticeInfo;

}

4.websocket調(diào)用

一個用戶調(diào)用接口,主動將信息發(fā)給后端,后端接收后再主動推送給指定/全部用戶

@RestController
@RequestMapping("/order")
public class OrderController {
	@GetMapping("/test")
    public R test() {
    	NoticeWebsocket.sendMessage("你好,WebSocket");
        return R.ok();
    }
}

前端WebSocket連接

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SseEmitter</title>
</head>
<body>
<div id="message"></div>
</body>
<script>
var limitConnect = 0;
init();
function init() {
var ws = new WebSocket('ws://192.168.2.88:9060/notice/1');
// 獲取連接狀態(tài)
console.log('ws連接狀態(tài):' + ws.readyState);
//監(jiān)聽是否連接成功
ws.onopen = function () {
    console.log('ws連接狀態(tài):' + ws.readyState);
    limitConnect = 0;
    //連接成功則發(fā)送一個數(shù)據(jù)
    ws.send('我們建立連接啦');
}
// 接聽服務(wù)器發(fā)回的信息并處理展示
ws.onmessage = function (data) {
    console.log('接收到來自服務(wù)器的消息:');
    console.log(data);
    //完成通信后關(guān)閉WebSocket連接
    // ws.close();
}
// 監(jiān)聽連接關(guān)閉事件
ws.onclose = function () {
    // 監(jiān)聽整個過程中websocket的狀態(tài)
    console.log('ws連接狀態(tài):' + ws.readyState);
reconnect();

}
// 監(jiān)聽并處理error事件
ws.onerror = function (error) {
    console.log(error);
}
}
function reconnect() {
    limitConnect ++;
    console.log("重連第" + limitConnect + "次");
    setTimeout(function(){
        init();
    },2000);
   
}
</script>
</html>

項目啟動,打開頁面后控制臺打印連接信息

調(diào)用order/test方法后前端打印推送消息內(nèi)容

這樣,就可以接口或者ws調(diào)用網(wǎng)址的方式進(jìn)行websocket的通信啦~

如果沒有前端頁面也可以使用在線WebSocket測試

總結(jié)

到此這篇關(guān)于java后端+前端使用WebSocket實現(xiàn)消息推送的文章就介紹到這了,更多相關(guān)javaWebSocket實現(xiàn)消息推送內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中

    使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中

    這篇文章主要介紹了使用SpringAop動態(tài)獲取mapper執(zhí)行的SQL,并保存SQL到Log表中問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 詳解spring中的Aware接口功能

    詳解spring中的Aware接口功能

    Spring的依賴注入的最大亮點是所有的Bean對Spring容器的存在是沒有意識的,我們可以將Spring容器換成其他的容器,Spring容器中的Bean的耦合度因此也是極低的,本文重點給大家介紹spring中的Aware接口,感興趣的朋友一起看看吧
    2022-02-02
  • Java基礎(chǔ)教程之理解Annotation詳細(xì)介紹

    Java基礎(chǔ)教程之理解Annotation詳細(xì)介紹

    這篇文章主要介紹了Java基礎(chǔ)教程之理解Annotation詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • java jvm兩種存儲區(qū)的類型知識點講解

    java jvm兩種存儲區(qū)的類型知識點講解

    在本篇文章里小編給大家整理的是一篇關(guān)于java jvm兩種存儲區(qū)的類型知識點講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。
    2021-03-03
  • 淺談使用Maven插件構(gòu)建Docker鏡像的方法

    淺談使用Maven插件構(gòu)建Docker鏡像的方法

    本篇文章主要介紹了淺談使用Maven插件構(gòu)建Docker鏡像的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-12-12
  • mybatis動態(tài)sql之新增與更新方式

    mybatis動態(tài)sql之新增與更新方式

    這篇文章主要介紹了mybatis動態(tài)sql之新增與更新方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • springboot @Valid注解對嵌套類型的校驗功能

    springboot @Valid注解對嵌套類型的校驗功能

    這篇文章主要介紹了springboot~@Valid注解對嵌套類型的校驗,主要介紹 @Valid在項目中的使用,需要的朋友可以參考下
    2018-05-05
  • 淺談Java中FastJson的使用

    淺談Java中FastJson的使用

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著FastJson的使用展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • JDK反序列化時修改類的全限定性名解析

    JDK反序列化時修改類的全限定性名解析

    這篇文章主要介紹了JDK反序列化時修改類的全限定性名解析,具有一定借鑒價值,需要的朋友可以參考下。
    2017-12-12
  • springboot?+rabbitmq+redis實現(xiàn)秒殺示例

    springboot?+rabbitmq+redis實現(xiàn)秒殺示例

    本文主要介紹了springboot?+rabbitmq+redis實現(xiàn)秒殺示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07

最新評論

永靖县| 来凤县| 尼勒克县| 乐亭县| 类乌齐县| 临猗县| 柳林县| 达孜县| 维西| 丽水市| 永安市| 车险| 玉门市| 昭平县| 乌拉特后旗| 遵义县| 吉安市| 嘉鱼县| 阿拉尔市| 千阳县| 霸州市| 保山市| 西林县| 海安县| 防城港市| 安仁县| 长武县| 灌阳县| 新化县| 福泉市| 措勤县| 乌兰察布市| 耿马| 志丹县| 盘山县| 加查县| 秦皇岛市| 四平市| 永寿县| 鄂托克前旗| 炎陵县|