websocket 实现后端主动前端推送数据、及时通讯(vue3 + springboot)

这篇具有很好参考价值的文章主要介绍了websocket 实现后端主动前端推送数据、及时通讯(vue3 + springboot)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介

WebSocket 是一种全双工通信协议,用于在 Web 浏览器和服务器之间建立持久的连接。

  1. WebSocket 协议由 IETF 定为标准,WebSocket API 由 W3C 定为标准。
  2. 一旦 Web 客户端与服务器建立连接,之后的全部数据通信都通过这个连接进行。
  3. 可以互相发送 JSON、XML、HTML 或图片等任意格式的数据。

WebSocket 与 HTTP 协议的异同:

相同点:

  • 都是基于 TCP 的应用层协议。
  • 都使用 Request/Response 模型进行连接的建立。
  • 可以在网络中传输数据。

不同点:

  • WebSocket 使用 HTTP 来建立连接,但定义了一系列新的 header 域,这些域在 HTTP 中并不会使用。
  • WebSocket 支持持久连接,而 HTTP 协议不支持持久连接。

WebSocket 优点:
高效性: 允许在一条 WebSocket 连接上同时并发多个请求,避免了传统 HTTP 请求的多个 TCP 连接。
WebSocket 的长连接特性提高了效率,避免了 TCP 慢启动和连接握手的开销。
节省带宽:HTTP 协议的头部较大,且请求中的大部分头部内容是重复的。WebSocket 复用长连接,避免了这一问题。
服务器推送:WebSocket 支持服务器主动推送消息,实现实时消息通知。

WebSocket 缺点:
长期维护成本:服务器需要维护长连接,成本较高。
浏览器兼容性:不同浏览器对 WebSocket 的支持程度不一致。
受网络限制:WebSocket 是长连接,受网络限制较大,需要处理好重连。

WebSocket 应用场景:

  • 实时通信领域:
  • 社交聊天弹幕
  • 多玩家游戏
  • 协同编辑
  • 股票基金实时报价
  • 体育实况更新
  • 视频会议/聊天
  • 基于位置的应用
  • 在线教育
  • 智能家居等需要高实时性的场景。

一、后端代码

1、安装核心jar包: spring-boot-starter-websocket
<dependencies>
        <!-- SpringBoot Websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.1.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.22</version>
        </dependency>

    </dependencies>
2. 来一个配置类注入
package com.codeSE.config;

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

@Configuration
public class WebSocketConfig2 {
    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }
}
3. 写个基础webSocket服务
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
//import org.apache.commons.lang3.StringUtils;
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.util.concurrent.ConcurrentHashMap;


/**
 * @ClassName: 开启WebSocket支持
 */
@ServerEndpoint("/dev-api/websocket/{userId}")
@Component
public class WebSocketServer {

    static Log log = LogFactory.get(WebSocketServer.class);
    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    /**
     * 接收userId
     */
    private String userId = "";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
            //加入set中
        } else {
            webSocketMap.put(userId, this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }

        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());

        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用户消息:" + userId + ",报文:" + message);
        //可以群发消息
        //消息保存到数据库、redis

        if (! StringUtils.isEmpty(message)) {
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 实现服务器主动推送
     */
    public static void sendAllMessage(String message) throws IOException {
        ConcurrentHashMap.KeySetView<String, WebSocketServer> userIds = webSocketMap.keySet();
        for (String userId : userIds) {
            WebSocketServer webSocketServer = webSocketMap.get(userId);
            webSocketServer.session.getBasicRemote().sendText(message);
            System.out.println("webSocket实现服务器主动推送成功userIds====" + userIds);
        }
    }

    /**
     * 发送自定义消息
     */
    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
        log.info("发送消息到:" + userId + ",报文:" + message);
        if (!StringUtils.isEmpty(message) && webSocketMap.containsKey(userId)) {
            webSocketMap.get(userId).sendMessage(message);
        } else {
            log.error("用户" + userId + ",不在线!");
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }
}
4. 写一个测试类,定时向客户端推送数据或者可以发起请求推送
package com.codeSE.controller;

import com.alibaba.fastjson2.JSONObject;
import com.codeSE.config.WebSocketServer;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;



@RestController
@RequestMapping("/money")
public class Test {

    //设置定时十秒一次
    @Scheduled(cron = "0/10 * * * * ?")
    @PostMapping("/send")
    public String sendMessage() throws Exception {
        Map<String,Object> map = new HashMap<>();

        // 获取当前日期和时间
        LocalDateTime nowDateTime = LocalDateTime.now();
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(dateTimeFormatter.format(nowDateTime));
        map.put("server_time",dateTimeFormatter.format(nowDateTime));
        map.put("server_code","200");
        map.put("server_message","这是服务器推送到客户端的消息哦!!");
        JSONObject jsonObject =  new JSONObject(map);
        WebSocketServer.sendAllMessage(jsonObject.toString());
        return jsonObject.toString();
    }

}

5. 启动springboot
package com.codeSE;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling //定时任务
@ServletComponentScan //webSocket
@SpringBootApplication
public class WebSocketAppMain {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketAppMain.class);
    }
}

使用网上的测试工具试一下:http://coolaf.com/tool/chattest 或者http://www.jsons.cn/websocket/
效果如下:
springboot+vue使用websocket实现前后端数据实时交互,websocket,前端,spring boot,vue,网络协议
springboot+vue使用websocket实现前后端数据实时交互,websocket,前端,spring boot,vue,网络协议

二、前端代码

使用vue3和原生websocket

1、简单写一个websocket的公共类

需求:commentUtil/WebsocketTool.js

//需求:在JavaScript中实现WebSocket连接失败后3分钟内尝试重连3次的功能,你可以设置一个重连策略,
//     包括重连的间隔时间、尝试次数以及总时间限制。

/**
 * @param {string} url  Url to connect
 * @param {number} maxReconnectAttempts Maximum number of times
 * @param {number} reconnect Timeout
 * @param {number} reconnectTimeout Timeout
 *
 */
class WebSocketReconnect {
 
  constructor(url, maxReconnectAttempts = 3, reconnectInterval = 20000, maxReconnectTime = 180000) {
    this.url = url
    this.maxReconnectAttempts = maxReconnectAttempts
    this.reconnectInterval = reconnectInterval
    this.maxReconnectTime = maxReconnectTime
    this.reconnectCount = 0
    this.reconnectTimeout = null
    this.startTime = null
    this.socket = null

    this.connect()
  }

  //连接操作
  connect() {
    console.log('connecting...')
    this.socket = new WebSocket(this.url)

    //连接成功建立的回调方法
    this.socket.onopen = () => {
      console.log('WebSocket Connection Opened!')
      this.clearReconnectTimeout()
      this.reconnectCount = 0
    }
    //连接关闭的回调方法
    this.socket.onclose = (event) => {
      console.log('WebSocket Connection Closed:', event)
      this.handleClose()
    }
    //连接发生错误的回调方法
    this.socket.onerror = (error) => {
      console.error('WebSocket Connection Error:', error)
      this.handleClose() //重连
    }
  }

  //断线重连操作
  handleClose() {
    if (this.reconnectCount < this.maxReconnectAttempts && (this.startTime === null || 
    Date.now() - this.startTime < this.maxReconnectTime)) {
      this.reconnectCount++
      console.log(`正在尝试重连 (${this.reconnectCount}/${this.maxReconnectAttempts})次...`)
      this.reconnectTimeout = setTimeout(() => {
        this.connect()
      }, this.reconnectInterval)

      if (this.startTime === null) {
        this.startTime = Date.now()
      }
    } else {
      console.log('超过最大重连次数或重连时间超时,已放弃连接!Max reconnect attempts reached or exceeded max reconnect time. Giving up.')
      this.reconnectCount = 0 // 重置连接次数0
      this.startTime = null // 重置开始时间
    }
  }

  //清除重连定时器
  clearReconnectTimeout() {
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout)
      this.reconnectTimeout = null
    }
  }

  //关闭连接
  close() {
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.close()
    }
    this.clearReconnectTimeout()
    this.reconnectCount = 0
    this.startTime = null
  }
}

// WebSocketReconnect 类封装了WebSocket的连接、重连逻辑。
// maxReconnectAttempts 是最大重连尝试次数。
// reconnectInterval 是每次重连尝试之间的间隔时间。
// maxReconnectTime 是总的重连时间限制,超过这个时间后不再尝试重连。
// reconnectCount 用于记录已经尝试的重连次数。
// startTime 用于记录开始重连的时间。
// connect 方法用于建立WebSocket连接,并设置相应的事件监听器。
// handleClose 方法在WebSocket连接关闭或发生错误时被调用,根据条件决定是否尝试重连。
// clearReconnectTimeout 方法用于清除之前设置的重连定时器。
// close 方法用于关闭WebSocket连接,并清除重连相关的状态。

// 使用示例
// const webSocketReconnect = new WebSocketReconnect('ws://your-websocket-url')
// 当不再需要WebSocket连接时,可以调用close方法
// webSocketReconnect.close();

export default WebSocketReconnect

2、在任意Vue页面
<template>
    <div>
      <el-input v-model="textarea1" :rows="5" type="textarea" placeholder="请输入" />
    </div>
</template>

<script setup>
import { ref, reactive,, onMounted, onUnmounted } from 'vue'
import WebSocketReconnect from '@/commentUtil/WebsocketTool'

// --------------------------------------------
let textarea1 = ref('【消息】---->')
let websocket = null
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
  //连接WebSocket节点
  websocket = new WebSocketReconnect('ws://127.0.0.1:8080' + '/dev-api/websocket/1122334455')
} else {
  alert('浏览器不支持webSocket')
}

//接收到消息的回调方法
websocket.socket.onmessage = function (event) {
  let data = event.data
  console.log('后端传递的数据:' + data)
  //将后端传递的数据渲染至页面
  textarea1.value = textarea1.value + data + '\n' + '【消息】---->'
}
//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
  websocket.close()
}
//关闭连接
function closeWebSocket() {
  websocket.close()
}
//发送消息
function send() {
  websocket.socket.send({ kk: 123 })
}

//------------------------------------
</script>

<style scoped>

</style>

效果:
springboot+vue使用websocket实现前后端数据实时交互,websocket,前端,spring boot,vue,网络协议文章来源地址https://www.toymoban.com/news/detail-840742.html

到了这里,关于websocket 实现后端主动前端推送数据、及时通讯(vue3 + springboot)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 服务端(后端)主动通知前端的实现:WebSocket(springboot中使用WebSocket案例)

    我们都知道 http 协议只能浏览器单方面向服务器发起请求获得响应,服务器不能主动向浏览器推送消息。想要实现浏览器的主动推送有两种主流实现方式: 轮询:缺点很多,但是实现简单 websocket:在浏览器和服务器之间建立 tcp 连接,实现全双工通信 springboot 使用 websocket 有

    2023年04月14日
    浏览(68)
  • SpringBoot集成WebSocket实现及时通讯聊天功能!!!

    注意:   至此,后端代码就集成完了,集成完之后,记得重启你的Springboot项目 前端Vue 1:新建Vue 页面  路由: 代码:路由根据你项目的实际情况写 在用户登录的时候,需要将你的用户名存储到本地Session 中  效果图:  用户甲:   用户乙:   注:网上学习来源 SpringBoot集

    2024年02月01日
    浏览(42)
  • Vue使用WebSocket实现实时获取后端推送的数据。

    Vue可以使用WebSocket实现实时获取后端推送的数据。 1.在Vue项目中安装WebSocket库 可以使用npm或yarn安装WebSocket库: 2.创建WebSocket连接 在Vue组件中创建WebSocket连接,连接到后端WebSocket服务器,代码如下: 上面的代码中,使用WebSocket连接到后端WebSocket服务器,通过监听onmessage事件,

    2024年02月08日
    浏览(50)
  • 前端订阅后端推送WebSocket定时任务

            后端定时向前端看板推送数据,每10秒或者30秒推送一次。         HTTP协议是一个应用层协议,它的特点是无状态、无连接和单向的。在HTTP协议中,客户端发起请求,服务器则对请求进行响应。这种请求-响应的模式意味着服务器无法主动向客户端发送消息。   

    2024年04月25日
    浏览(42)
  • Python Flask 后端向前端推送信息——轮询、SSE、WebSocket

    后端向前端推送信息,通知任务完成 轮询 SSE WebSocket 请求方式 HTTP HTTP TCP长连接 触发方式 轮询 事件 事件 优点 实现简单易兼容 实现简单开发成本低 全双工通信,开销小,安全,可扩展 缺点 消耗较大 不兼容IE 传输数据需二次解析,开发成本大 适用场景 服务端向客户端单向

    2023年04月19日
    浏览(90)
  • WebSocket实现后端数据变化,通知前端实时更新数据

    背景 ​ 项目中需要做一个消息提示功能,当有用户处理相关待办信息后,别的用户需要实时更新处理后的待办信息。 解决方案: ​ 1、使用最原始的方法,写个定时器去查询待办信息。但这种方式在大多数情况是不被允许的,它会浪费系统中的许多资源,同时也并不是完全

    2024年04月15日
    浏览(48)
  • Java-WebSocket通信 实现根据查询条件主动实时回传数据给前端&List<Map<String, Object>>转JSON编码器&WebSocket无法注册Bean问题解决方案

    项目背景:Java环境,Get请求根据前端查询条件建立WebSocket连接,每5秒主动实时推送最新查询结果给前端展示。其中也遇到定时器、WebSocket无法注册Bean、No encoder specified for object of class [class java.util.xxx]等问题,相关解决方案也有列举~ Web Sockets 的是在一个单独的持久连接上提

    2024年02月04日
    浏览(50)
  • websocket实时推送统计数据给前端页面

    前提须知:websocket基本使用 业务场景,每秒推送统计数据给前端页面,分别显示前天,昨天,今天的前十名客户数据 @ServerEndpoint(\\\"/smsMCustomerStaTop10Ws\\\") 定义推送数据给到具体的连接标识 以上 onOpen() 方法最终触发的业务方法 smsMonitorService.pushSmsMCustomerStaTop10(); 以上 smsMonitorMapper.findSm

    2024年02月15日
    浏览(48)
  • SpringBoot集成WebSocket,实现后台向前端推送信息

    在一次项目开发中,使用到了Netty网络应用框架,以及MQTT进行消息数据的收发,这其中需要后台来将获取到的消息主动推送给前端,于是就使用到了MQTT,特此记录一下。 WebSocket协议是基于TCP的一种新的网络协议。它实现了客户端与服务器全双工通信,学过计算机网络都知道

    2024年01月16日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包