IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 后端数据变化,通知前端实时更新数据 -> 正文阅读

[网络协议]后端数据变化,通知前端实时更新数据

作者:token annotation punctuation

背景

? 项目中需要做一个消息提示功能,当有用户处理相关待办信息后,别的用户需要实时更新处理后的待办信息。

解决方案:

? 1、使用最原始的方法,写个定时器去查询待办信息。但这种方式在大多数情况是不被允许的,它会浪费系统中的许多资源,同时也并不是完全意义上的实时更新。

? 2、使用WebSocket通信技术去实现一个实时更新,它可以实现广播和私信的模式。当一个用户与WebSocket服务建立连接后,用户可以给它发送一个消息,此时WebSocket服务会接收到这个消息并做出回信(此时可以回信给所有与其建立连接的用户——广播,也可以回信给指定用户——私信)。接下来将从前后端去讲解WebSocket的使用。

一、WebSocket服务的搭建(SpringBoot后端)

SpringBoot自带的WebSocket有以下5个注解需要注意:

  1. @ServerEndpoint

    暴露出的ws应用的路径,支持RESTful风格传参,类似/websocket/{username}

  2. @OnOpen

    与当前客户端连接成功,有入参Session对象(当前连接对象),同时可以利用@PathParam()获取上述应用路径中传递的参数,比如@PathParam(“username”) String username。

  3. @OnClose

    与当前客户端连接失败,有入参Session对象(当前连接对象),同时也可以利用@PathParam()获取上述应用路径中传递的参数。

  4. @OnError

    与当前客户端连接异常,有入参Session对象(当前连接对象)、Throwable对象(异常对象),同时也可以利用@PathParam()获取上述应用路径中传递的参数。

  5. @OnMessage

    当前客户端发送消息,有入参Session对象(当前连接对象)、String message对象(当前客户端传递过来的字符串消息)

1、引入所需依赖

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

2、使用自定义类开启WebSocket

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

/**
 * @program: webSocketTest
 * @description: WebSocket相关配置
 * @author: 黄珺瑜
 * @create: 2022-06-30 16:24
 **/

@Configuration
@EnableWebSocket
public class WebSocketConfig {

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

}

3、配置WebSocket服务

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @program: webSocketTest
 * @description: WebSocket服务
 * @author: 黄珺瑜
 * @create: 2022-06-30 16:25
 **/

@Component
@Slf4j
@ServerEndpoint("/websocket") //暴露的ws应用的路径
public class WebSocket {

    // 用来存储服务连接对象
    private static Map<String ,Session> clientMap = new ConcurrentHashMap<>();

    /**
     * 客户端与服务端连接成功
     * @param session
     */
    @OnOpen
    public void onOpen(Session session){
        /*
            do something for onOpen
            与当前客户端连接成功时
         */
        clientMap.put(session.getId(),session);
    }

    /**
     * 客户端与服务端连接关闭
     * @param session
     */
    @OnClose
    public void onClose(Session session){
        /*
            do something for onClose
            与当前客户端连接关闭时
         */
        clientMap.remove(session.getId());
    }

    /**
     * 客户端与服务端连接异常
     * @param error
     * @param session
     */
    @OnError
    public void onError(Throwable error,Session session) {
        error.printStackTrace();
    }

    /**
     * 客户端向服务端发送消息
     * @param message
     * @throws IOException
     */
    @OnMessage
    public void onMsg(Session session,String message) throws IOException {
        /*
            do something for onMessage
            收到来自当前客户端的消息时
         */
        sendAllMessage(message);
    }

    //向所有客户端发送消息(广播)
    private void sendAllMessage(String message){
        Set<String> sessionIdSet = clientMap.keySet(); //获得Map的Key的集合
        // 此处相当于一个广播操作
        for (String sessionId : sessionIdSet) { //迭代Key集合
            Session session = clientMap.get(sessionId); //根据Key得到value
            session.getAsyncRemote().sendText(message); //发送消息给客户端
        }
    }
}

二、与WebSocket服务建立连接(Vue前端)

WebSocket是js自带的一个对象,所以此处不需要任何引入第三方依赖包的操作。

WebSocket对象讲解:

  1. 创建WebSocket对象

    const ws = new WebSocket('ws://127.0.0.1:8088/websocket')
    // WebSocket服务的建立需要使用ws协议或者wss协议
    
  2. onopen事件监听

    // 建立连接后的回调函数
    openCallback(e){
        console.log('与服务端连接打开->',e)
    }
    
  3. onerror事件监听

    // 连接异常后的回调函数
    errorCallback(e){
        console.log('与服务端连接打开->',e)
    }
    
  4. onclose事件监听

    // 关闭连接的回调函数
    closeCallback(e){
        console.log('与服务端连接打开->',e)
    }
    
  5. onmessage事件监听

    // 接收到服务端的回信后的回调函数
    messageCallback(e){
        console.log('与服务端连接打开->',e)
    }
    

1、包装后的webSocket.js

/**
 * 参数说明:
 *  webSocketURL:String    webSocket服务地址    eg: ws://127.0.0.1:8088/websocket (后端接口若为restful风格可以带参数)  
 *  callback:为带一个参数的回调函数
 *  message:String 要传递的参数值(不是一个必要的参数)
 */
export default{
    // 初始化webSocket
    webSocketInit(webSocketURL){      // ws://127.0.0.1:8088/websocket
        this.webSocket = new WebSocket(webSocketURL);
        this.webSocket.onopen = this.onOpenwellback;
        this.webSocket.onmessage = this.onMessageCallback;
        this.webSocket.onerror = this.onErrorCallback;
        this.webSocket.onclose = this.onCloseCallback;
    },

    // 自定义回调函数
    setOpenCallback(callback){ //  与服务端连接打开回调函数
        this.webSocket.onopen = callback;
    },
    setMessageCallback(callback){   //  与服务端发送消息回调函数
        this.webSocket.onmessage = callback;
    },
    setErrorCallback(callback){ //  与服务端连接异常回调函数
        this.webSocket.onerror = callback;
    },
    setCloseCallback(callback){ //  与服务端连接关闭回调函数
        this.webSocket.onclose = callback;
    },

    close(){    // 关闭连接
        this.webSocket.close();
    },
    sendMessage(message){   // 发送消息函数
        this.webSocket.send(message);
    },
}

2、Vue中WebSocket对象的使用

<template>
  <el-button type="primary" @click="sendMessage">发送消息</el-button>
</template>

<script>
import webSocket from '@/api/evgis/webSocket'
export default {
    name:"WebSocketTest",
    data(){
        return{
            webSocketObject: null,
        }
    },
    created() {
        // webSocket.webSocketInit(process.env.VUE_APP_BASE_API.replace("http","ws")+"/evgis/todoStatus")
        webSocket.webSocketInit('ws://127.0.0.1:8088/websocket')	//初始化webSocket
        // 按需进行绑定回调函数
        webSocket.setOpenCallback(res=>{
            console.log("连接建立成功",res);
        })
        webSocket.setMessageCallback(res=>{	
            // 在此处进行数据刷新操作即可实现数据发生改变时实时更新数据
            console.log("接收到回信",res);
        })
        webSocket.setErrorCallback(res=>{
            console.log("连接异常",res);
        })
        webSocket.setCloseCallback(res=>{
            console.log("连接关闭",res);
        })
    },
    methods:{
        sendMessage(){
            // 数据发生改变时给WebSocket发送消息,让其进行广播操作
            webSocket.sendMessage();
        }
    }
}
</script>

<style>
</style>

三、实践时遇到困难

1、由于使用的时若依框架,配置好WebSocket服务后需要开放出ws的服务地址,否则会提示未带token,WebSocket连接不上。

2、在配置WebSocket服务时,没有在关闭连接方法中移除连接对象。导致建立WebSocket连接后一发送消息就断开连接。

参考文章:前后端使用利用WebSocket进行通信服务器推送消息到前端实现页面数据实时刷新-分布式Websocket技术方案

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 23:19:41  更:2022-07-04 23:20:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:33:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码