基于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 {@Beanpublic 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; // 当前用户@OnOpenpublic 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 + " 加入聊天室!");}@OnMessagepublic void onMessage(String message) {System.out.println("收到消息:" + message);broadcast(message);}@OnClosepublic void onClose() {clients.remove(this);userMap.remove(username);System.out.println("用户 " + username + " 断开连接,当前在线人数:" + clients.size());broadcast("用户 " + username + " 离开聊天室");System.out.println("连接关闭:" + session.getId());}@OnErrorpublic 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: {// 连接 WebSocketconnect() {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 未连接,无法发送消息");}},// 断开 WebSocketdisconnect() {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>