当前位置: 首页 > news >正文

基于websocket搭建聊天室

基于websocket搭建聊天室

1.后端配置

1.依赖一个web一个websocket

 <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>

2.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 {

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


}

3.ws

import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;


@Component
@ServerEndpoint("/ws/chat/{username}")
public class WebSocketServer {

    private static final CopyOnWriteArraySet<WebSocketServer> clients = new CopyOnWriteArraySet<>();
    // 存储在线用户(线程安全)
    private static final Map<String, Session> userMap = new ConcurrentHashMap<>();
    private Session session;
    private String username; // 当前用户
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        this.username = username;
        userMap.put(username, session);
        this.session = session;
        clients.add(this);
        System.out.println("用户 " + username + " 连接成功,当前在线人数:" + clients.size());
        sendMessage("欢迎 " + username + " 加入聊天室!");
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println("收到消息:" + message);
        broadcast(message);
    }

    @OnClose
    public void onClose() {
        clients.remove(this);
        userMap.remove(username);
        System.out.println("用户 " + username + " 断开连接,当前在线人数:" + clients.size());
        broadcast("用户 " + username + " 离开聊天室");
        System.out.println("连接关闭:" + session.getId());
    }

    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("用户 " + username + " 发生错误:" + error.getMessage());
    }

    private void broadcast(String message) {
        for (WebSocketServer client : clients) {
            try {
                client.session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 发送消息给某个用户
     */
    private void sendMessage(String message) {
        try {
            if (userMap.containsKey(username)) {
                userMap.get(username).getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2.前端

1.vue2+element ui

2.前端代理vue.config.js

"use strict"
const path = require("path")

function resolve(dir) {
  return path.join(__dirname, dir)
}
const name =  "vue Template"
module.exports = {
  publicPath: "./",
  assetsDir: "static",
  lintOnSave: false,
  devServer: {
    proxy: {
      "^/socket": {
        target: "ws://localhost:8888",
        ws: true,
        changeOrigin: true,
        pathRewrite: {'/socket':''}
      },
      "^/api": {
        target: "http://localhost:8888",
        changeOrigin: true,
        // pathRewrite: {'/datashare':'/'}
      },

    },
  },
  productionSourceMap: false,
  configureWebpack: {
    name: name,
    resolve: {
      alias: {
        "@": resolve("src"),
      },
    },
  },

}

3.测试代码

<template>
  <div>
    <!-- 连接按钮 -->
    <el-button type="primary" :disabled="loading || isConnected" @click="connect" v-loading="loading">
      {{ isConnected ? "已连接" : "连接" }}
    </el-button>

    <!-- 断开连接按钮 -->
    <el-button type="danger" :disabled="!isConnected" @click="disconnect">
      断开连接
    </el-button>

    <!-- 消息输入框 -->
    <el-input v-model="msg" placeholder="输入消息" @keyup.enter="sendMessage"/>

    <!-- 发送消息按钮 -->
    <el-button type="success" :disabled="!isConnected" @click="sendMessage">
      发送
    </el-button>

    <!-- 消息列表 -->
    <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: "Jack", // 当前用户
      msg: "", // 发送的消息
      messages: [], // 消息列表
      isConnected: false, // 连接状态
      loading: false, // 是否正在连接
    };
  },
  methods: {
    // 连接 WebSocket
    connect() {
      if (this.isConnected) {
        console.log("WebSocket 已连接");
        return;
      }

      this.loading = true;
      this.socket = new WebSocket(`/socket/ws/chat/${this.username}`);

      this.socket.onopen = () => {
        console.log("WebSocket 连接成功");
        this.isConnected = true;
        this.loading = false;
      };

      this.socket.onmessage = (event) => {
        console.log("收到消息:" + event.data);
        this.messages.push(event.data);
      };

      this.socket.onclose = () => {
        console.warn("WebSocket 连接关闭");
        this.isConnected = false;
        this.cleanupSocket();
      };

      this.socket.onerror = (error) => {
        console.error("WebSocket 发生错误", error);
        this.isConnected = false;
        this.cleanupSocket();
      };
    },

    // 发送消息
    sendMessage() {
      if (this.socket && this.isConnected) {
        this.socket.send(this.msg);
        console.log("发送消息:" + this.msg);
        this.messages.push(`我: ${this.msg}`);
        this.msg = "";
      } else {
        console.warn("WebSocket 未连接,无法发送消息");
      }
    },

    // 断开 WebSocket
    disconnect() {
      if (this.socket) {
        this.socket.close();
      }
      this.isConnected = false;
    },

    // 关闭 WebSocket 并清理
    cleanupSocket() {
      if (this.socket) {
        this.socket.close();
        this.socket = null;
      }
      this.isConnected = false;
      this.loading = false;
    },
  },
  beforeUnmount() {
    this.cleanupSocket();
  },
};
</script>

<style scoped>
</style>

相关文章:

  • 深度学习基础--CNN经典网络之“DenseNet”简介,源码研究与复现(pytorch)
  • no space left on device,内存不足/inode不足
  • PyTorch模型优化设计一个高效的神经网络架构实例
  • 下载Hugging Face模型的几种方式
  • EPLAN常见功能使用
  • 第四十五篇-Tesla P40+QWQ-32B部署与测试
  • C++ primer plus 第七节 函数探幽完结版
  • 【数据分析】转录组基因表达的KEGG通路富集分析教程
  • 第18周:YOLOv5-C3模块实现
  • 用Kotlin写一个Android闹钟
  • 边缘智联新基建:5G+边缘计算重塑制造业神经末梢
  • C语言 第三章 函数(2)
  • Spring 构造器注入和setter注入的比较
  • 【Python修仙编程】(二) Python3灵源初探(7)
  • c++ 调用 gurobi 库,cmake,mac
  • 云原生边缘计算:重塑分布式智能的时空边界
  • 在16卡服务器上使用最新版的CUDA和驱动训练`llama - 2 - 7b`和`llama - 2 - 70b`模型,并生成训练指标数据
  • MyBatis-Plus 使用技巧
  • 通过 Python 实现“机器学习”小项目教程案例:鸢尾花分类
  • 前端数据模拟 Mock.js 学习笔记
  • 2015年做哪些网站能致富/seo云优化
  • 南京电商网站建设/百中搜
  • 做网站难吗?/下载百度地图2022最新版官方
  • 做的网站搜不到/网络广告网站
  • 烟台网站排名优化/百度ai人工智能平台
  • 江阴市住房和城乡建设局网站/淘宝关键词搜索工具