成品图:
对WebSocket的理解(在使用之前建议先了解Tcp,三次握手,四次挥手 ):
首先页面与WebSocket建立连接、向WebSocket发送信息、后端WebSocket向所有连接上WebSoket的客户端发送当前信息。
推荐浏览网站:WebSocket 是什么?你需要知道的一切
第一步:在后端引入WebSocket依赖
<!-- WebSocket -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
第二步:在后端配置WebSocket
package cn.ryanfan.virtulab_back.config;
import cn.ryanfan.virtulab_back.websocket.ChatHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new ChatHandler(), "/chat").setAllowedOrigins("*");
}
}
第三步:建立WebSocket自定义支持
package cn.ryanfan.virtulab_back.websocket;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class ChatHandler extends TextWebSocketHandler {
private final List<WebSocketSession> sessions = new ArrayList<>();
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
sessions.add(session);
}
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
for (WebSocketSession s : sessions) {
if (s.isOpen()) {
s.sendMessage(message);
}
}
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
sessions.remove(session);
}
}
第四步:在前端开启WebSocket通信
<template>
<div class="chat-container">
<div class="chat-header">
<h3>在线聊天</h3>
</div>
<div class="chat-messages">
<!-- 显示消息列表 -->
<div
v-for="(message, index) in messages"
:key="index"
class="message-item"
:class="{'my-message': message.sender === currentUser}"
>
<strong>{{ message.sender }}:</strong>
<div class="message-content">{{ message.content }}</div>
</div>
</div>
<div class="chat-input">
<input
v-model="newMessage"
@keyup.enter="sendMessage"
type="text"
placeholder="输入消息"
class="message-input"
/>
<button @click="sendMessage" class="send-button">发送</button>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
interface Message {
sender: string;
content: string;
}
// 消息列表
const messages = ref<Message[]>([]);
// 当前用户输入的消息
const newMessage = ref('');
// 假设的发送方
const currentUser = 'User1';
// WebSocket 对象
let socket: WebSocket | null = null;
// 连接 WebSocket,并处理接收和发送消息的逻辑
const connectWebSocket = () => {
socket = new WebSocket('ws://localhost:8667/VirtuLab_back/chat'); // 连接到后端 WebSocket
// WebSocket 打开时触发
socket.onopen = () => {
console.log('WebSocket 连接已建立');
};
// 接收 WebSocket 消息时触发
socket.onmessage = (event: MessageEvent) => {
const data = JSON.parse(event.data); // 假设收到的消息是 JSON 格式
console.log('WebSocket 对话已建立');
console.log(data)
messages.value.push({ sender: data.sender, content: data.content });
};
// WebSocket 关闭时触发
socket.onclose = () => {
console.log('WebSocket 连接已关闭');
};
// WebSocket 出现错误时触发
socket.onerror = (error) => {
console.error('WebSocket 错误:', error);
};
};
// 发送消息
const sendMessage = () => {
if (newMessage.value.trim() !== '' && socket && socket.readyState === WebSocket.OPEN) {
const message = {
sender: currentUser,
content: newMessage.value
};
socket.send(JSON.stringify(message)); // 发送 JSON 格式的消息到服务器
newMessage.value = ''; // 清空输入框
}
};
// 当组件挂载时连接 WebSocket
onMounted(() => {
connectWebSocket();
});
// 当组件卸载时关闭 WebSocket
onUnmounted(() => {
if (socket) {
socket.close();
}
});
</script>
<style scoped>
.chat-container {
width: 400px;
border: 1px solid #ccc;
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 500px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
}
.chat-header {
padding: 15px;
background-color: #007bff;
color: white;
text-align: center;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
font-weight: bold;
}
.chat-messages {
flex: 1;
padding: 15px;
overflow-y: auto;
background-color: #f9f9f9;
border-bottom: 1px solid #ddd;
}
.message-item {
margin-bottom: 10px;
padding: 10px;
border-radius: 8px;
}
.my-message {
background-color: #007bff;
color: white;
align-self: flex-end;
}
.message-content {
margin-top: 5px;
}
.chat-input {
display: flex;
padding: 10px;
background-color: #f1f1f1;
border-bottom-left-radius: 8px;
border-bottom-right-radius: 8px;
}
.message-input {
flex: 1;
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
margin-right: 10px;
transition: border-color 0.3s;
}
.message-input:focus {
border-color: #007bff;
outline: none;
}
.send-button {
padding: 10px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.send-button:hover {
background-color: #0056b3;
}
</style>