基于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>
相关推荐
不脱发的猴子39 分钟前
Wireshark使用教程
网络·测试工具·wireshark
EasyCVR2 小时前
EasyRTC嵌入式视频通话SDK的跨平台适配,构建web浏览器、Linux、ARM、安卓等终端的低延迟音视频通信
android·arm开发·网络协议·tcp/ip·音视频·webrtc
小羊在奋斗3 小时前
【Linux网络】NAT技术、DNS系统、五种IO模型
linux·网络·智能路由器
暴躁的小胡!!!5 小时前
Linux权限维持之协议后门(七)
linux·运维·服务器·网络·安全
车载测试工程师5 小时前
车载以太网测试-3【Wireshark介绍】
经验分享·功能测试·网络协议·车载系统
遇见火星5 小时前
2025年Linux 安全与运维指南
网络
苏格拉真没有底5 小时前
python实现mqtt消息转Tcp消息
网络·python·tcp/ip
dxaiofcu6 小时前
双网卡电脑,IP地址漂移
linux·服务器·网络
煲冬瓜的程序猿8 小时前
BGP(三)联盟、反射器
网络·网络协议
Joeysoda8 小时前
JavaEE进阶(2) Spring Web MVC: Session 和 Cookie
java·前端·网络·spring·java-ee