实现简易聊天室功能

embedded/2025/3/10 22:38:02/

实现简易聊天室功能

1.前端设计

 

 

<template><div><div><!-- 连接按钮 --><el-button v-loading="loading" :disabled="loading || isConnected" type="primary" @click="connect">{{ isConnected ? "已连接" : "连接" }}</el-button><!-- 断开连接按钮 --><el-button :disabled="!isConnected" type="danger" @click="disconnect">断开</el-button><!-- 发送消息按钮 --><el-button :disabled="!isConnected" type="success" @click="sendMessage">发送</el-button></div><div><el-input v-model="username" :disabled="isConnected" placeholder="用户名" style="width: 100px"@keyup.enter="sendMessage"/></div><div><!-- 消息输入框 --><el-input v-model="msg" placeholder="输入消息" @keyup.enter="sendMessage"/></div><!-- 消息列表 --><el-card v-if="messages.length > 0"><p v-for="(message, index) in messages" :key="index">{{ message }}</p></el-card></div>
</template><script>
export default {name: "WebSocketChat",data() {return {socket: null, // WebSocket 对象username: null, // 当前用户msg: '', // 发送的消息messages: [], // 消息列表isConnected: false, // 连接状态loading: false, // 是否正在连接};},methods: {// 连接 WebSocketconnect() {const vm = this// 参数校验if (vm.isConnected) {vm.$message.success("WebSocket 已连接");return;} else if (!vm.username) {vm.$message.success("请输入用户名");return;}// 连接vm.loading = true;vm.socket = new WebSocket(`/socket/ws/chat/${this.username}`);// 连接成功vm.socket.onopen = () => {vm.$notify.success("WebSocket 连接成功");vm.isConnected = true;vm.loading = false;};// 接收消息vm.socket.onmessage = (event) => {vm.messages.push(event.data);};// 关闭vm.socket.onclose = () => {vm.$notify.success("WebSocket 连接关闭");vm.cleanupSocket();};// 异常vm.socket.onerror = (error) => {vm.$notify.error("WebSocket 发生错误" + error);vm.cleanupSocket();};},// 发送消息sendMessage() {const vm = thisif (vm.socket && vm.isConnected) {vm.socket.send(vm.msg);vm.messages.push(`我: ${vm.msg}`);vm.msg = "";} else {vm.$notify.warning("WebSocket 未连接,无法发送消息");}},// 断开 WebSocketdisconnect() {const vm = thisif (vm.socket) {vm.socket.close();}vm.isConnected = false;},// 关闭 WebSocket 并清理cleanupSocket() {const vm = thisif (vm.socket) {vm.socket.close();vm.socket = null;}vm.isConnected = false;vm.loading = false;},},beforeUnmount() {this.cleanupSocket();},
};
</script><style scoped>
</style>

 

 2.后端

依赖

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

config 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;@Configuration
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}}

控制类

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Controller;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Controller
@ServerEndpoint("/ws/chat/{username}")
public class WebSocketServer {// 存储在线用户(线程安全)private static final Map<String, Session> userSessionMap = new ConcurrentHashMap<>();private Session session;private String username;/*** 创建时触发 用户在进入聊天室的时候触发** @param username* @param session*/@OnOpenpublic void onOpen(@PathParam("username") String username, Session session) {this.username = username;this.session = session;userSessionMap.put(username, session);System.out.println("【open】用户 " + username + " 连接成功,当前在线人数:" + userSessionMap.size());sendOne("【open-one】" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));sendAll("【open-all】用户 " + username + " 加入聊天室");}/*** 响应字符串** @param message*/@OnMessagepublic void onMessage(String message) {System.out.println("收到消息:" + message);System.out.println("当前用户" + username);sendAllNotMe(username + ":" + message);}/*** 响应字节流** @param session session* @param message message*/@OnMessagepublic void onMessage(Session session, byte[] message) {System.out.println("响应字节流");}/*** 断开 离开聊天室的时候触发*/@OnClosepublic void onClose(Session session, CloseReason closeReason) {userSessionMap.remove(username);System.out.println("用户 " + username + " 断开连接,当前在线人数:" + userSessionMap.size());System.out.println("连接关闭:" + session.getId());sendAll("【all】用户 " + username + " 离开聊天室");}@OnErrorpublic void onError(Session session, Throwable error) {System.out.println("用户 " + username + " 发生错误:" + error.getMessage());try {this.session.close();userSessionMap.remove(username);} catch (IOException e) {e.printStackTrace();}}/*** 发送给所有人* @param message*/private void sendAll(String message) {if (userSessionMap != null && userSessionMap.size() > 0) {for (Map.Entry<String,Session> entry : userSessionMap.entrySet()) {try {entry.getValue().getBasicRemote().sendText(message);} catch (IOException e) {e.printStackTrace();}}}}/*** 发送给除了我的* @param message*/private void sendAllNotMe(String message) {if (userSessionMap != null && userSessionMap.size() > 0) {for (Map.Entry<String,Session> entry : userSessionMap.entrySet()) {try {if (StrUtil.isNotBlank(entry.getKey()) && entry.getKey().equals(username)) {continue;} else {entry.getValue().getBasicRemote().sendText(message);}} catch (IOException e) {e.printStackTrace();}}}}/*** 发送消息给某个用户*/private void sendOne(String message) {try {if (userSessionMap.containsKey(username)) {userSessionMap.get(username).getBasicRemote().sendText(message);}} catch (IOException e) {e.printStackTrace();}}
}


http://www.ppmy.cn/embedded/171596.html

相关文章

可视化大屏出圈密码:地图组件深度解析

01 组件介绍 在数据可视化大屏搭建中&#xff0c;地图组件是使用最频繁且重要的组件之一。它不但能直观展现地理方位相关信息&#xff0c;还能通过与标记点、飞线、图表等各类组件巧妙搭配&#xff0c;达成更加多元、生动的数据呈现效果&#xff0c;在众多行业领域都得到了广泛…

大数据表高效导入导出解决方案,mysql数据库LOAD DATA命令和INTO OUTFILE命令详解

一.问题背景 java项目基于mysql实现大数据表跨服务器导入导出功能。之前整理过百万数据导入内存溢出的解决方案&#xff0c;这次情况又不一样了&#xff0c; 21万包含longtext字段的数据导入导出&#xff0c;解决了内存溢出的问题&#xff0c;速度却很慢&#xff0c;即使开启批…

【每日八股】Golang篇(二):关键字(上)

目录 make 和 new 的区别&#xff1f;概念例子 struct 能不能比较&#xff1f;为什么 slice 之间不能直接比较&#xff1f;slice 的底层实现&#xff1f;slice 和数组的区别&#xff1f;slice 的扩容机制&#xff1f;slice 是线程安全的吗&#xff1f;slice 之间如何比较&#…

PY32MD320单片机 QFN32封装,内置多功能三相 NN 型预驱。

PY32MD320单片机是普冉半导体的一款电机专用MCU&#xff0c;芯片采用了高性能的 32 位 ARM Cortex-M0 内核&#xff0c;主要用于电机控制。PY32MD320嵌入高达 64 KB Flash 和 8 KB SRAM 存储器&#xff0c;最高工作频率 48 MHz。PY32MD320单片机的工作温度范围为 -40 ~ 105 ℃&…

华为欧拉系统 Tomcat 安装详解

1. 安装或确认安装 Java Tomcat 需要 Java 环境(JDK 或 JRE)才能运行。如果系统尚未安装 Java,可以使用以下命令安装 OpenJDK: # 更新软件包索引 yum update -y# 安装 OpenJDK 21(可根据需求安装其他版本,如 8、11、17 等) yum install -y java-21-openjdk java-21-op…

python软件开发安装包配置问题以及如何焕电脑后批量安装安装包的问题

1.在软件开发的过程中往往需要安装许多的python包&#xff0c;如果通过&#xff1a;通过pip install packagex.x.x指定特定版本的话容易出现漏装的情况&#xff0c;于是就需要找到指定包进行安装&#xff0c;但这个时候如果我们新建一个文本文档&#xff1a;requirements&#…

C# 基础知识总结(持续更新中...)

C#有哪些数据类型&#xff1f; 值类型 引用类型 整数类型 实数类型 布尔类型 字符类型 结构类型 枚举类型 类 数组 字符串 接口 委托 对象型 C#有哪几种访问修饰符&#xff0c;有何区别&#xff1f; public 公共成员 访问不受限制 private 私有成员 只限于当前类成员…

计算机网络(1) 网络通信基础,协议介绍,通信框架

网络结构模式 C/S-----客户端和服务器 B/S -----浏览器服务器 MAC地址 每一个网卡都拥有独一无二的48位串行号&#xff0c;也即MAC地址&#xff0c;也叫做物理地址、硬件地址或者是局域网地址 MAC地址表示为12个16进制数 如00-16-EA-AE-3C-40 &#xff08;每一个数可以用四个…