【开源宝藏】Jeepay VUE和React构建WebSocket通用模板

WebSocket 服务实现:Spring Boot 示例

在现代应用程序中,WebSocket 是实现双向实时通信的重要技术。本文将介绍如何使用 Spring Boot 创建一个简单的 WebSocket 服务,并提供相关的代码示例。

1. WebSocket 简介

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。与传统的 HTTP 请求-响应模式相比,WebSocket 允许服务器主动向客户端推送消息,适用于实时应用,如在线聊天、实时通知和游戏等。

2. 项目结构

在开始之前,确保你的项目中包含必要的依赖。在 pom.xml 中添加以下依赖:

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

3. WebSocket 配置类

为了启用 WebSocket 支持,我们需要创建一个配置类 WebSocketConfig,如下所示:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** 开启WebSocket支持* * @author terrfly* @site https://www.jeequan.com* @date 2021/6/22 12:57*/
@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

3.1 配置类解析

  • @Configuration: 表示该类是一个配置类,Spring 会在启动时加载它。
  • ServerEndpointExporter: 这个 Bean 会自动注册所有带有 @ServerEndpoint 注解的 WebSocket 端点。

4. WebSocket 服务类

以下是一个简单的 WebSocket 服务类 WsChannelUserIdServer 的实现。该类负责处理客户端的连接、消息接收和发送。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;@ServerEndpoint("/api/anon/ws/channelUserId/{appId}/{cid}")
@Component
public class WsChannelUserIdServer {private final static Logger logger = LoggerFactory.getLogger(WsChannelUserIdServer.class);private static int onlineClientSize = 0;private static Map<String, Set<WsChannelUserIdServer>> wsAppIdMap = new ConcurrentHashMap<>();private Session session;private String cid = "";private String appId = "";@OnOpenpublic void onOpen(Session session, @PathParam("appId") String appId, @PathParam("cid") String cid) {try {this.cid = cid;this.appId = appId;this.session = session;Set<WsChannelUserIdServer> wsServerSet = wsAppIdMap.get(appId);if (wsServerSet == null) {wsServerSet = new CopyOnWriteArraySet<>();}wsServerSet.add(this);wsAppIdMap.put(appId, wsServerSet);addOnlineCount();logger.info("cid[{}], appId[{}] 连接开启监听!当前在线人数为 {}", cid, appId, onlineClientSize);} catch (Exception e) {logger.error("ws监听异常 cid[{}], appId[{}]", cid, appId, e);}}@OnClosepublic void onClose() {Set<WsChannelUserIdServer> wsSet = wsAppIdMap.get(this.appId);wsSet.remove(this);if (wsSet.isEmpty()) {wsAppIdMap.remove(this.appId);}subOnlineCount();logger.info("cid[{}], appId[{}] 连接关闭!当前在线人数为 {}", cid, appId, onlineClientSize);}@OnErrorpublic void onError(Session session, Throwable error) {logger.error("ws发生错误", error);}public void sendMessage(String message) throws IOException {this.session.getBasicRemote().sendText(message);}public static void sendMsgByAppAndCid(String appId, String cid, String msg) {try {logger.info("推送ws消息到浏览器, appId={}, cid={}, msg={}", appId, cid, msg);Set<WsChannelUserIdServer> wsSet = wsAppIdMap.get(appId);if (wsSet == null || wsSet.isEmpty()) {logger.info("appId[{}] 无ws监听客户端", appId);return;}for (WsChannelUserIdServer item : wsSet) {if (!cid.equals(item.cid)) {continue;}try {item.sendMessage(msg);} catch (Exception e) {logger.info("推送设备消息时异常,appId={}, cid={}", appId, item.cid, e);}}} catch (Exception e) {logger.info("推送消息时异常,appId={}", appId, e);}}public static synchronized int getOnlineClientSize() {return onlineClientSize;}public static synchronized void addOnlineCount() {onlineClientSize++;}public static synchronized void subOnlineCount() {onlineClientSize--;}
}

5. 代码解析

5.1 连接管理

  • @OnOpen: 当客户端连接成功时调用此方法。可以在此方法中获取客户端的 appIdcid,并将当前连接的会话存储到 wsAppIdMap 中。
  • @OnClose: 当客户端连接关闭时调用此方法,从 wsAppIdMap 中移除该连接。
  • @OnError: 处理连接错误。

5.2 消息发送

  • sendMessage(String message): 通过当前会话向客户端发送消息。
  • sendMsgByAppAndCid(String appId, String cid, String msg): 根据 appIdcid 向特定客户端推送消息。

5.3 在线人数管理

使用 onlineClientSize 变量记录当前在线的客户端数量,并提供相应的增减方法。

好的!下面我将为你提供一个简单的前端实现示例,使用 Vue.jsReact 来连接我们之前创建的 WebSocket 服务。这样,你可以看到如何在前端与后端进行实时通信。

6. Vue.js 前端实现

6.1 安装 Vue.js

如果你还没有创建 Vue 项目,可以使用 Vue CLI 创建一个新的项目:

npm install -g @vue/cli
vue create websocket-demo
cd websocket-demo

6.2 创建 WebSocket 组件

src/components 目录下创建一个名为 WebSocketComponent.vue 的文件,并添加以下代码:

<template><div><h1>WebSocket Demo</h1><input v-model="message" placeholder="Type a message" /><button @click="sendMessage">Send</button><div><h2>Messages:</h2><ul><li v-for="(msg, index) in messages" :key="index">{{ msg }}</li></ul></div></div>
</template><script>
export default {data() {return {socket: null,message: '',messages: [],appId: 'yourAppId', // 替换为你的 appIdcid: 'yourClientId'  // 替换为你的客户端自定义ID};},created() {this.connect();},methods: {connect() {this.socket = new WebSocket(`ws://localhost:8080/api/anon/ws/channelUserId/${this.appId}/${this.cid}`);this.socket.onopen = () => {console.log('WebSocket connection established.');};this.socket.onmessage = (event) => {const data = JSON.parse(event.data);this.messages.push(data.message);};this.socket.onclose = () => {console.log('WebSocket connection closed.');};this.socket.onerror = (error) => {console.error('WebSocket error:', error);};},sendMessage() {if (this.socket && this.socket.readyState === WebSocket.OPEN) {this.socket.send(JSON.stringify({ message: this.message }));this.message = ''; // 清空输入框} else {console.error('WebSocket is not open.');}}}
};
</script><style scoped>
/* 添加样式 */
</style>

6.3 使用组件

src/App.vue 中使用这个组件:

<template><div id="app"><WebSocketComponent /></div>
</template><script>
import WebSocketComponent from './components/WebSocketComponent.vue';export default {components: {WebSocketComponent}
};
</script><style>
/* 添加样式 */
</style>

6.4 运行 Vue 应用

在项目根目录下运行以下命令启动 Vue 应用:

npm run serve

7. React 前端实现

7.1 安装 React

如果你还没有创建 React 项目,可以使用 Create React App 创建一个新的项目:

npx create-react-app websocket-demo
cd websocket-demo

7.2 创建 WebSocket 组件

src 目录下创建一个名为 WebSocketComponent.js 的文件,并添加以下代码:

import React, { useEffect, useState } from 'react';const WebSocketComponent = () => {const [socket, setSocket] = useState(null);const [message, setMessage] = useState('');const [messages, setMessages] = useState([]);const appId = 'yourAppId'; // 替换为你的 appIdconst cid = 'yourClientId'; // 替换为你的客户端自定义IDuseEffect(() => {const ws = new WebSocket(`ws://localhost:8080/api/anon/ws/channelUserId/${appId}/${cid}`);setSocket(ws);ws.onopen = () => {console.log('WebSocket connection established.');};ws.onmessage = (event) => {const data = JSON.parse(event.data);setMessages((prevMessages) => [...prevMessages, data.message]);};ws.onclose = () => {console.log('WebSocket connection closed.');};ws.onerror = (error) => {console.error('WebSocket error:', error);};return () => {ws.close();};}, [appId, cid]);const sendMessage = () => {if (socket && socket.readyState === WebSocket.OPEN) {socket.send(JSON.stringify({ message }));setMessage(''); // 清空输入框} else {console.error('WebSocket is not open.');}};return (<div><h1>WebSocket Demo</h1><inputvalue={message}onChange={(e) => setMessage(e.target.value)}placeholder="Type a message"/><button onClick={sendMessage}>Send</button><div><h2>Messages:</h2><ul>{messages.map((msg, index) => (<li key={index}>{msg}</li>))}</ul></div></div>);
};export default WebSocketComponent;

7.3 使用组件

src/App.js 中使用这个组件:

import React from 'react';
import WebSocketComponent from './WebSocketComponent';function App() {return (<div className="App"><WebSocketComponent /></div>);
}export default App;

7.4 运行 React 应用

在项目根目录下运行以下命令启动 React 应用:

npm start

8. 总结

通过以上步骤,我们实现了一个简单的 WebSocket 前端示例,分别使用了 Vue.js 和 React。用户可以通过输入框发送消息,接收来自 WebSocket 服务器的消息。

8.1 注意事项

  • 确保 WebSocket 服务器正在运行,并且前端应用能够访问到它。
  • 替换 yourAppIdyourClientId 为实际的应用 ID 和客户端 ID。

希望这能帮助你更好地理解如何在前端实现 WebSocket 通信!如有任何问题,请随时询问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/67333.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图论的起点——七桥问题

普瑞格尔河从古堡哥尼斯堡市中心流过&#xff0c;河中有小岛两座&#xff0c;筑有7座古桥&#xff0c;哥尼斯堡人杰地灵&#xff0c;市民普遍爱好数学。1736年&#xff0c;该市一名市民向大数学家Euler提出如下的所谓“七桥问题”&#xff1a; 从家里出发&#xff0c;7座桥每桥…

Fabric区块链网络搭建:保姆级图文详解

目录 前言1、项目环境部署1.1 基础开发环境1.2 网络部署 2、后台环境2.1、环境配置2.2、运行springboot项目 3、PC端3.1、安装依赖3.2、修改区块链网络连接地址3.3、启动项目 前言 亲爱的家人们&#xff0c;创作很不容易&#xff0c;若对您有帮助的话&#xff0c;请点赞收藏加…

02JavaWeb——JavaScript-Vue(项目实战)

一、JavaScript html完成了架子&#xff0c;css做了美化&#xff0c;但是网页是死的&#xff0c;我们需要给他注入灵魂&#xff0c;所以接下来我们需要学习 JavaScript&#xff0c;这门语言会让我们的页面能够和用户进行交互。 1.1 介绍 通过JS/js效果演示提供资料进行效果演…

Windows 蓝牙驱动开发-蓝牙设备栈

蓝牙设备栈 蓝牙驱动程序堆栈包含 Microsoft 为蓝牙协议提供支持的核心部分。 有了这个堆栈&#xff0c;已启用蓝牙的设备可以彼此定位并建立连接。 在此类连接中&#xff0c;设备可以通过各种应用程序交换数据并彼此交互。 下图显示了蓝牙驱动程序堆栈中的模块&#xff0c;以…

GPU 硬件原理架构(一)

这张费米管线架构图能看懂了&#xff0c;整个GPU的架构基本就熟了。市面上有很多GPU厂家&#xff0c;他们产品的架构各不相同&#xff0c;但是核心往往差不多&#xff0c;整明白一了个基本上就可以触类旁通了。下面这张图信息量很大&#xff0c;可以结合博客GPU 英伟达GPU架构回…

CSS布局与响应式

学习链接 Grid网格布局 前端五大主流网页布局 flex布局看这一篇就够了 grid布局看这一篇就够了 用六个案例学会响应式布局 伸缩盒响应式页面布局实战 实现响应式布局的五种方式 - csdn 如何完成响应式布局&#xff0c;有几种方法&#xff1f;看这个就够了 响应式布局总…

大疆最新款无人机发布,可照亮百米之外目标

近日&#xff0c;DJI 大疆发布全新小型智能多光旗舰 DJI Matrice 4 系列&#xff0c;包含 Matrice 4T 和 Matrice 4E 两款机型。DJI Matrice 4E 价格为27888 元起&#xff0c;DJI Matrice 4T价格为38888元起。 图片来源&#xff1a;大疆官网 DJI Matrice 4E DJI Matrice 4T D…

Nmap入门

- 在已有的参数上加上哄骗或是使用文件 nmap -iL data.txt ------- nmap -PS -PA -O -ttl 200 -F -D dcay1, dcay2,dcay3... -vv -P 3306 1.1.1.0/24 -oN data.txtNmap端口的6个状态 open 应用程序正在该端口接收TCP或UDP报文 closed 关闭的端口对于Nmap也是可访问的(它接受…

ubuntu18.04开发环境下samba服务器的搭建

嵌入式linux的发展很快&#xff0c;最近准备在一个新项目上采用新一代的linux核心板&#xff0c;发现linux内核的版本已经更新到5.4以上甚至6.0以上&#xff1b;之前常用的linux内核版本是2.6.4&#xff0c;虽然在某些项目上还能用但是明显跟不上时代的步伐了&#xff0c;所以要…

计算机网络速成

前言&#xff1a;最近在做一些动态的crypto&#xff0c;但是配置总搞不好&#xff0c;正好也有学web的想法&#xff0c;就先学学web再回去做密码&#xff0c;速成视频推荐b站建模老哥 目录 计算机网络概述网络的范围分级电路交换网络&#xff08;电路交换&#xff09;报文交换网…

【React】静态组件动态组件

目录 静态组件动态组件创建一个构造函数(类)使用 class 实现组件**使用 function 实现类组件** 静态组件 函数组件是静态组件&#xff1a; 组件第一次渲染完毕后&#xff0c;无法基于内部的某些操作让组件更新「无法实现自更新」&#xff1b;但是&#xff0c;如果调用它的父组…

Qt/C++ 基于 QGraphicsView 的绘图软件 (附源码下载链接)

基于 Qt 的 QGraphicsView 绘图软件项目进行深入讲解&#xff0c;分析其核心代码与功能实现&#xff0c;帮助开发者理解 QGraphicsView 的用法。 项目概览 该项目实现了一个简单的绘图应用&#xff0c;用户可以在界面中创建和编辑矩形、椭圆、直线、多边形和文本等图形对象。功…

Vue2+OpenLayers给2个标点Feature分别添加独立的点击事件(提供Gitee源码)

前言&#xff1a;之前开发都是将所有的点位存放在一个图层上面&#xff0c;并统一赋予它们相同的点击事件&#xff0c;如果其中某些点的点击事件不一样呢&#xff0c;这种问题如何解决呢&#xff0c;本篇博客就是解决这个通点。 目录 一、案例截图 二、安装OpenLayers库 三…

李宏毅机器学习课程笔记03 | 类神经网络优化技巧

文章目录 类神经网络优化技巧局部最小值local minima 与 鞍点saddle pointSaddle Point 的情况更常见 Tips for training&#xff1a;Batch and MomentumSmall Batch vs Large Batch回顾&#xff1a;optimization优化 找到参数使L最小问题&#xff1a;为什么要用Batch&#xff…

如何学习网络安全?有哪些小窍门?

学好网络安全其实没有所谓的捷径&#xff0c;也没有什么小窍门。 入门网络安全首先要有浓厚的学习兴趣&#xff0c;不然很容易就变成了从入门到放弃了。 其次要能静下心&#xff0c;踏踏实实的打好基础。如果你是零基础&#xff0c;建议从Web安全入手&#xff0c;课程难度相对…

测试工程师的linux 命令学习(持续更新中)

1.ls """1.ls""" ls -l 除文件名称外&#xff0c;亦将文件型态、权限、拥有者、文件大小等资讯详细列出 ls -l等同于 ll第一列共10位&#xff0c;第1位表示文档类型&#xff0c;d表示目录&#xff0c;-表示普通文件&#xff0c;l表示链接文件。…

K8S 亲和性与反亲和性 深度好文

今天我们来实验 pod 亲和性。官网描述如下&#xff1a; 假设有如下三个节点的 K8S 集群&#xff1a; k8s31master 是控制节点 k8s31node1、k8s31node2 是工作节点 容器运行时是 containerd 一、镜像准备 1.1、镜像拉取 docker pull tomcat:8.5-jre8-alpine docker pull nginx…

Nginx三种不同类型的虚拟主机(基于域名、IP 和端口)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; Nginx-从零开始的服务器之旅专栏&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年1月15日13点14分 目录 1. 基于域名的虚拟主机 …

解析OVN架构及其在OpenStack中的集成

引言 随着云计算技术的发展&#xff0c;虚拟化网络成为云平台不可或缺的一部分。为了更好地管理和控制虚拟网络&#xff0c;Open Virtual Network (OVN) 应运而生。作为Open vSwitch (OVS) 的扩展&#xff0c;OVN 提供了对虚拟网络抽象的支持&#xff0c;使得大规模部署和管理…

【Flink系列】9. Flink容错机制

9. 容错机制 在Flink中&#xff0c;有一套完整的容错机制来保证故障后的恢复&#xff0c;其中最重要的就是检查点。 9.1 检查点&#xff08;Checkpoint&#xff09; 9.1.1 检查点的保存 1&#xff09;周期性的触发保存 “随时存档”确实恢复起来方便&#xff0c;可是需要我…