Advertisement

云服务器部署WebSocket项目

阅读量:

基于 TCP 协议家族中的 WebSocket 标准,在一个单一 TCP 连接上实现了全双工通信的可能性。该协议旨在通过可靠的数据传输机制,在 Web 浏览器与 Web 服务器之间支持实时数据传输(Real-Time Web Communication)。

WebSocket协议的优点包括:

更高的网络利用效率:相较于HTTP而言,在WebSocket中进行连接建立只需一次操作。与传统的HTTP协议相比,在建立连接后,客户端和服务器可以直接进行数据传输。

实时效果更为显著:WebSocket通过双向通信机制实现了即时交互功能,并避免了等待客户端或服务器端的回复

3. 更低的通信开销与传输延迟;WebSocket支持二进制数据传输而无需进行文本编码;相较于HTTP而言, WebSocket的消息头体积更为缩减

项目内容

1.WebSocketConfig

表示这是一个配置类,可以定义 Spring Bean

当Spring遍历该类时,它会将其中的所有@Bean方法返回的对象整合到应用上下文中。

@Bean 方法

serverEndpointExporter 方法负责生成并登记一个 ServerEndpointExporter 实例。

ServerEndpointExporter 是 Spring 支持的一个类,
负责根据 @ServerEndpoint 注解自动生成符合 Java 标准的 WebSocket 端点。

它负责将 @ServerEndpoint 注解标记的 WebSocket 类注册到容器中

ServerEndpointExporter 的作用:

在Spring Boot容器环境中,在@ServerEndpoint注解标注的对象会被ServerEndpointExporter识别并注册为 WebSocket 端口;常见于嵌入式 Servlet容器如Tomcat;对于独立部署的 Servlet容器(例如外部Tomcat),则无需设置或配置 ServerEndpointExporter

复制代码
 package com.qcby.chatroom1117.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();
    
     }
    
 }
    
    
    
    
    java
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/cm7fWXYPAyNLMT62KptIU508BjVq.png)

2.ChatController

获取在线用户列表:

  • 通过调用WebSocketServer.getWebSocketSet()函数来获取所有在线用户
    • 如果用户的 sid字段值不是 'admin' ,直接将该用户添加进去

管理员发送消息:

  • 通过 @RequestParam 接收请求中的目标用户的ID(sid)以及信息内容(message)
    • 向 WebSocketServer 发送到指定的用户发送信息
复制代码
 package com.qcby.chatroom1117.controller;

    
  
    
 import com.qcby.chatroom1117.server.WebSocketServer;
    
 import org.springframework.web.bind.annotation.*;
    
  
    
 import java.io.IOException;
    
 import java.util.ArrayList;
    
 import java.util.List;
    
  
    
 @RestController
    
 @RequestMapping("/api/chat")
    
 public class ChatController {
    
  
    
     /** * 获取在线用户列表,不包含管理员
    
      */
    
     @GetMapping("/online-users")
    
     public List<String> getOnlineUsers() {
    
     List<String> sidList = new ArrayList<>();
    
     for (WebSocketServer server : WebSocketServer.getWebSocketSet()) {
    
         //排除管理员
    
         if (!server.getSid().equals("admin")) {
    
             sidList.add(server.getSid());
    
         }
    
     }
    
     return sidList;
    
     }
    
  
    
     /** * 管理员发送消息给指定用户
    
      */
    
     @PostMapping("/send")
    
     public void sendMessageToUser(@RequestParam String sid, @RequestParam String message) throws IOException {
    
     WebSocketServer.sendInfo(message, sid);
    
     }
    
  
    
  
    
 }
    
    
    
    
    java
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/mWhTbAxHrSnGcq3XEfwgNv0IFUis.png)

3.WebSocketServer

  • Upon connection, the client performs operations to establish connections and records the sid value of the user.
  • Upon disconnection, the client removes itself from the connection set and updates the online user count.
  • Upon receiving messages, the client processes them and forwards to the specified user.
  • sendCommand: The service sends individual messages to the client.
  • sendInfo: The service can broadcast messages or send them individually to a specific client.
  • getOnlineCount: The service maintains real-time monitoring of current online users.
  • addOnlineCount and subOnlineCount: These commands manage online user counts by incrementing or decrementing them.
  • Upon receiving errors, the client captures exceptions and logs them for later error analysis.
复制代码
 package com.qcby.chatroom1117.server;

    
  
    
 import com.fasterxml.jackson.databind.ObjectMapper;
    
 import lombok.extern.slf4j.Slf4j;
    
 import org.springframework.stereotype.Component;
    
 import org.springframework.stereotype.Service;
    
  
    
 import javax.websocket.*;
    
 import javax.websocket.server.PathParam;
    
 import javax.websocket.server.ServerEndpoint;
    
 import java.io.IOException;
    
 import java.util.HashMap;
    
 import java.util.Map;
    
 import java.util.concurrent.CopyOnWriteArraySet;
    
  
    
 /** * WebSocket 服务端
    
  */
    
 @Component
    
 @Slf4j
    
 @Service
    
 @ServerEndpoint("/api/websocket/{sid}")
    
 public class WebSocketServer {
    
     //当前在线连接数
    
     private static int onlineCount = 0;
    
  
    
     //存放每个客户端对应的 WebSocketServer 对象
    
     private static final CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>();
    
  
    
     //用户信息
    
     private Session session;
    
  
    
     //当前用户的 sid
    
     private String sid = "";
    
  
    
     //JSON解析工具
    
     private static final ObjectMapper objectMapper = new ObjectMapper();
    
  
    
     /** * 连接建立成功调用的方法
    
      */
    
     @OnOpen
    
     public void onOpen(Session session, @PathParam("sid") String sid) {
    
     this.session = session;
    
     this.sid = sid;
    
     webSocketSet.add(this); //加入集合
    
     addOnlineCount(); //在线数加1
    
     try {
    
         sendMessage("conn_success");
    
         log.info("有新窗口开始监听: " + sid + ", 当前在线人数为: " + getOnlineCount());
    
     } catch (IOException e) {
    
         log.error("WebSocket IO Exception", e);
    
     }
    
     }
    
  
    
     /** * 连接关闭调用的方法
    
      */
    
     @OnClose
    
     public void onClose() {
    
     webSocketSet.remove(this); //从集合中删除
    
     subOnlineCount(); //在线数减1
    
     log.info("释放的 sid 为:" + sid);
    
     log.info("有一连接关闭!当前在线人数为 " + getOnlineCount());
    
     }
    
  
    
     /** * 收到客户端消息后调用的方法
    
      */
    
     @OnMessage
    
     public void onMessage(String message, Session session) {
    
     log.info("收到来自窗口 " + sid + " 的信息: " + message);
    
  
    
     //解析消息中的 targetSid
    
     String targetSid;
    
     String msgContent;
    
     try {
    
         Map<String, String> messageMap = objectMapper.readValue(message, Map.class);
    
         targetSid = messageMap.get("targetSid");
    
         msgContent = messageMap.get("message");
    
     } catch (IOException e) {
    
         log.error("消息解析失败", e);
    
         return;
    
     }
    
  
    
     //构造消息
    
     Map<String, String> responseMap = new HashMap<>();
    
     responseMap.put("sourceSid", sid);
    
     responseMap.put("message", msgContent);
    
  
    
     String jsonResponse;
    
     try {
    
         jsonResponse = objectMapper.writeValueAsString(responseMap);
    
     } catch (IOException e) {
    
         log.error("JSON 序列化失败", e);
    
         return;
    
     }
    
  
    
     //按 targetSid 发送消息
    
     for (WebSocketServer item : webSocketSet) {
    
         try {
    
             if (targetSid.equals(item.sid)) {
    
                 item.sendMessage(jsonResponse);
    
                 break; //找到目标用户后不再继续发送
    
             }
    
         } catch (IOException e) {
    
             log.error("消息发送失败", e);
    
         }
    
     }
    
     }
    
  
    
  
    
     /** * 判断是否是管理员
    
      */
    
     private boolean isAdmin(String sid) {
    
     return "admin_sid".equals(sid);
    
     }
    
  
    
     /** * 发生错误时调用的方法
    
      */
    
     @OnError
    
     public void onError(Session session, Throwable error) {
    
     log.error("发生错误", error);
    
     }
    
  
    
     /** * 实现服务器主动推送
    
      */
    
     public void sendMessage(String message) throws IOException {
    
     this.session.getBasicRemote().sendText(message);
    
     }
    
  
    
     /** * 群发自定义消息
    
      */
    
     public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
    
     log.info("推送消息到窗口 " + sid + ",推送内容: " + message);
    
  
    
     for (WebSocketServer item : webSocketSet) {
    
         try {
    
             if (sid == null) {
    
                 item.sendMessage(message); //推送给所有人
    
             } else if (item.sid.equals(sid)) {
    
                 item.sendMessage(message); //推送给指定 sid
    
             }
    
         } catch (IOException e) {
    
             log.error("推送消息失败", e);
    
         }
    
     }
    
     }
    
  
    
     public static synchronized int getOnlineCount() {
    
     return onlineCount;
    
     }
    
  
    
     public static synchronized void addOnlineCount() {
    
     WebSocketServer.onlineCount++;
    
     }
    
  
    
     public static synchronized void subOnlineCount() {
    
     WebSocketServer.onlineCount--;
    
     }
    
  
    
     public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
    
     return webSocketSet;
    
     }
    
  
    
     public String getSid() {
    
     return this.sid;
    
     }
    
 }
    
    
    
    
    java
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/bvOITLNKRjfyCwdlnqpsF30EBmr4.png)

4.admin页面

复制代码
 <!DOCTYPE html>

    
 <html lang="en">
    
 <head>
    
     <meta charset="UTF-8">
    
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
     <title>管理员端 - 聊天窗口</title>
    
     <style>
    
     * {
    
         margin: 0;
    
         padding: 0;
    
         box-sizing: border-box;
    
     }
    
     body {
    
         font-family: Arial, sans-serif;
    
         display: flex;
    
         height: 100vh;
    
         margin: 0;
    
         background-color: #f4f7fc;
    
         color: #333;
    
     }
    
     /* 左侧在线用户列表 */
    
     #onlineUsersContainer {
    
         width: 250px;
    
         padding: 20px;
    
         background-color: #fff;
    
         border-right: 1px solid #ddd;
    
         box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
    
         overflow-y: auto;
    
     }
    
     #onlineUsers {
    
         list-style-type: none;
    
         padding: 0;
    
         margin-top: 20px;
    
     }
    
     #onlineUsers li {
    
         padding: 10px;
    
         cursor: pointer;
    
         border-radius: 5px;
    
         transition: background-color 0.3s ease;
    
     }
    
     #onlineUsers li:hover {
    
         background-color: #e9f1fe;
    
     }
    
     #onlineUsers li.selected {
    
         background-color: #d0e7fe;
    
     }
    
     /* 右侧聊天窗口 */
    
     #chatBox {
    
         flex: 1;
    
         display: flex;
    
         flex-direction: column;
    
         padding: 20px;
    
         background-color: #fff;
    
     }
    
     #messages {
    
         border: 1px solid #ddd;
    
         height: 500px;
    
         overflow-y: scroll;
    
         margin-bottom: 20px;
    
         padding: 15px;
    
         background-color: #f9f9f9;
    
         border-radius: 10px;
    
         box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.1);
    
     }
    
     .message {
    
         padding: 10px;
    
         margin: 8px 0;
    
         border-radius: 10px;
    
         max-width: 80%;
    
         line-height: 1.6;
    
         word-wrap: break-word;
    
     }
    
     .message-right {
    
         background-color: #dcf8c6;
    
         text-align: right;
    
         margin-left: auto;
    
     }
    
     .message-left {
    
         background-color: #f1f0f0;
    
         text-align: left;
    
         margin-right: auto;
    
     }
    
     #messageInput {
    
         width: 80%;
    
         padding: 12px;
    
         border-radius: 25px;
    
         border: 1px solid #ccc;
    
         margin-right: 10px;
    
         font-size: 16px;
    
         transition: border-color 0.3s ease;
    
     }
    
     #messageInput:focus {
    
         border-color: #007bff;
    
         outline: none;
    
     }
    
     button {
    
         padding: 12px 20px;
    
         border-radius: 25px;
    
         border: 1px solid #007bff;
    
         background-color: #007bff;
    
         color: white;
    
         cursor: pointer;
    
         font-size: 16px;
    
         transition: background-color 0.3s ease;
    
     }
    
     button:hover {
    
         background-color: #0056b3;
    
     }
    
     h3 {
    
         font-size: 18px;
    
         color: #333;
    
         margin-bottom: 20px;
    
     }
    
     #onlineUsers li.unread {
    
         font-weight: bold;
    
         color: red;
    
     }
    
  
    
     @media (max-width: 768px) {
    
         #onlineUsersContainer {
    
             width: 100%;
    
             padding: 15px;
    
         }
    
         #chatBox {
    
             padding: 15px;
    
         }
    
         #messageInput {
    
             width: calc(100% - 100px);
    
         }
    
         button {
    
             width: 80px;
    
         }
    
     }
    
     </style>
    
 </head>
    
 <body>
    
 <div id="onlineUsersContainer">
    
     <h3>在线用户</h3>
    
     <ul id="onlineUsers"></ul>
    
 </div>
    
 <div id="chatBox">
    
     <h3>聊天窗口</h3>
    
     <div id="messages"></div>
    
     <div style="display: flex;">
    
     <input id="messageInput" type="text" placeholder="请输入消息">
    
     <button onclick="sendMessage()">发送</button>
    
     </div>
    
 </div>
    
  
    
 <script>
    
     let websocket;
    
     const sid = "admin";
    
     let currentUserSid = null; //当前聊天对象的sid
    
     let chatHistory = {}; //用于存储每个用户的聊天记录
    
  
    
     //页面加载时初始化
    
     window.onload = () => {
    
     connectWebSocket();
    
     getOnlineUsers(); //页面加载时刷新在线用户列表
    
     restoreSelectedUser(); //恢复选中的用户
    
     };
    
  
    
     function connectWebSocket() {
    
     websocket = new WebSocket("ws://localhost:8080/api/websocket/" + sid);
    
  
    
     websocket.onopen = () => {
    
         console.log("连接成功,管理员ID:" + sid);
    
     };
    
  
    
     websocket.onmessage = (event) => {
    
         try {
    
             let data;
    
             if (event.data.startsWith("{") && event.data.endsWith("}")) {
    
                 data = JSON.parse(event.data); // 如果是有效的 JSON 格式,进行解析
    
             } else {
    
                 // 如果是无效的 JSON(比如 "conn_success" 这样的字符串),进行处理
    
                 console.log("接收到非 JSON 消息:", event.data);
    
                 return;
    
             }
    
  
    
             const { sourceSid, message } = data;
    
  
    
             if (sourceSid) {
    
                 //初始化聊天记录存储
    
                 if (!chatHistory[sourceSid]) {
    
                     chatHistory[sourceSid] = [];
    
                 }
    
                 //存储对方的消息
    
                 chatHistory[sourceSid].push({ sender: 'left', message });
    
                 //如果消息来源是当前聊天对象,更新聊天窗口
    
                 if (sourceSid === currentUserSid) {
    
                     displayMessages();
    
                 } else {
    
                     //消息来源不是当前对象,提示未读消息
    
                     notifyUnreadMessage(sourceSid);
    
                 }
    
             }
    
         } catch (e) {
    
             console.error("解析消息失败", e);
    
         }
    
     };
    
  
    
  
    
  
    
     websocket.onclose = () => {
    
         console.log("连接关闭");
    
     };
    
  
    
     websocket.onerror = (error) => {
    
         console.error("WebSocket发生错误", error);
    
     };
    
     }
    
  
    
     function notifyUnreadMessage(userSid) {
    
     const userListItems = document.querySelectorAll("#onlineUsers li");
    
     userListItems.forEach(item => {
    
         if (item.textContent === userSid) {
    
             item.classList.add("unread"); //添加未读消息样式
    
         }
    
     });
    
     }
    
  
    
     //清除未读消息提示
    
     function clearUnreadMessage(userSid) {
    
     const userListItems = document.querySelectorAll("#onlineUsers li");
    
     userListItems.forEach(item => {
    
         if (item.textContent === userSid) {
    
             item.classList.remove("unread");
    
         }
    
     });
    
     }
    
  
    
  
    
     function sendMessage() {
    
     const message = document.getElementById("messageInput").value;
    
  
    
     if (!currentUserSid) {
    
         alert("请选择一个用户进行聊天!");
    
         return;
    
     }
    
  
    
     if (message.trim() !== "") {
    
         websocket.send(JSON.stringify({ targetSid: currentUserSid, message }));
    
         chatHistory[currentUserSid] = chatHistory[currentUserSid] || [];
    
         chatHistory[currentUserSid].push({ sender: 'right', message });
    
         document.getElementById("messageInput").value = '';
    
         displayMessages();
    
     }
    
     }
    
  
    
  
    
     //显示当前用户的聊天记录
    
     function displayMessages() {
    
     const messagesDiv = document.getElementById("messages");
    
     messagesDiv.innerHTML = "";
    
     if (currentUserSid && chatHistory[currentUserSid]) {
    
         chatHistory[currentUserSid].forEach(msg => {
    
             const messageDiv = document.createElement("div");
    
             messageDiv.classList.add("message", msg.sender === 'right' ? "message-right" : "message-left");
    
             messageDiv.textContent = msg.message;
    
             messagesDiv.appendChild(messageDiv);
    
         });
    
     }
    
     scrollToBottom();
    
     }
    
  
    
     function scrollToBottom() {
    
     const messagesDiv = document.getElementById("messages");
    
     messagesDiv.scrollTop = messagesDiv.scrollHeight;
    
     }
    
  
    
     //获取在线用户列表(不包括管理员)
    
     function getOnlineUsers() {
    
     fetch("/api/chat/online-users")
    
         .then(response => response.json())
    
         .then(users => {
    
             const userList = document.getElementById("onlineUsers");
    
             userList.innerHTML = "";
    
             users.forEach(user => {
    
                 if (user !== "admin") {
    
                     const li = document.createElement("li");
    
                     li.textContent = user;
    
                     li.onclick = () => selectUser(user, li);
    
                     userList.appendChild(li);
    
                 }
    
             });
    
         });
    
     }
    
  
    
     //选择用户进行聊天
    
     function selectUser(user, liElement) {
    
     //清除所有选中状态
    
     const userListItems = document.querySelectorAll("#onlineUsers li");
    
     userListItems.forEach(item => item.classList.remove("selected"));
    
  
    
     //高亮显示当前选中的用户
    
     liElement.classList.add("selected");
    
  
    
     if (currentUserSid !== user) {
    
         currentUserSid = user;
    
         //清除未读消息提示
    
         clearUnreadMessage(user);
    
         //显示与该用户的聊天记录
    
         displayMessages();
    
         //保存当前选中的用户
    
         localStorage.setItem('selectedUserSid', user);
    
     }
    
     scrollToBottom();
    
     }
    
  
    
  
    
     //恢复选中的用户
    
     function restoreSelectedUser() {
    
     const savedUserSid = localStorage.getItem('selectedUserSid');
    
     if (savedUserSid) {
    
         currentUserSid = savedUserSid;
    
         const userListItems = document.querySelectorAll("#onlineUsers li");
    
         userListItems.forEach(item => {
    
             if (item.textContent === savedUserSid) {
    
                 item.classList.add("selected");
    
             }
    
         });
    
         displayMessages();
    
     }
    
     }
    
 </script>
    
 </body>
    
 </html>
    
    
    
    
    html
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/HDWbpamjXtqnuUR2Osc9LAh7JSN3.png)

5.user页面

复制代码
 <!DOCTYPE html>

    
 <html lang="en">
    
 <head>
    
     <meta charset="UTF-8">
    
     <title>用户端 - 聊天窗口</title>
    
     <style>
    
     * {
    
         margin: 0;
    
         padding: 0;
    
         box-sizing: border-box;
    
     }
    
     body {
    
         font-family: Arial, sans-serif;
    
         background-color: #f0f4f8;
    
         display: flex;
    
         justify-content: center;
    
         align-items: center;
    
         min-height: 100vh;
    
     }
    
     #chatBox {
    
         position: fixed;
    
         bottom: 10px;
    
         right: 10px;
    
         width: 400px;
    
         height: 500px;
    
         background-color: #ffffff;
    
         border-radius: 8px;
    
         padding: 20px;
    
         box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    
         background: linear-gradient(to top right, #f9f9f9, #e9eff7);
    
         display: flex;
    
         flex-direction: column;
    
         max-height: 80vh;
    
     }
    
     #chatBox h3 {
    
         font-size: 20px;
    
         margin-bottom: 15px;
    
         color: #333;
    
         text-align: center;
    
     }
    
     #messages {
    
         flex: 1;
    
         border: 1px solid #ddd;
    
         padding: 15px;
    
         overflow-y: auto;
    
         background-color: #f9f9f9;
    
         border-radius: 8px;
    
         margin-bottom: 15px;
    
         font-size: 14px;
    
         color: #333;
    
         line-height: 1.5;
    
         box-shadow: inset 0 0 8px rgba(0, 0, 0, 0.1);
    
     }
    
     .message {
    
         padding: 10px;
    
         margin: 5px 0;
    
         border-radius: 8px;
    
         max-width: 80%;
    
         word-wrap: break-word;
    
     }
    
     .message-right {
    
         background-color: #dcf8c6;
    
         text-align: right;
    
         margin-left: auto;
    
     }
    
     .message-left {
    
         background-color: #f1f0f0;
    
         text-align: left;
    
         margin-right: auto;
    
     }
    
     #inputWrapper {
    
         display: flex;
    
         width: 100%;
    
     }
    
     #messageInput {
    
         width: calc(100% - 80px);
    
         padding: 12px;
    
         border-radius: 25px;
    
         border: 1px solid #ccc;
    
         margin-right: 10px;
    
         font-size: 16px;
    
         transition: border-color 0.3s ease;
    
     }
    
     #messageInput:focus {
    
         border-color: #007bff;
    
         outline: none;
    
     }
    
     button {
    
         padding: 12px 20px;
    
         border-radius: 25px;
    
         border: 1px solid #007bff;
    
         background-color: #007bff;
    
         color: white;
    
         cursor: pointer;
    
         font-size: 16px;
    
         transition: background-color 0.3s ease;
    
         width: 60px;
    
         display: inline-flex;
    
         align-items: center;
    
         justify-content: center;
    
     }
    
     button:hover {
    
         background-color: #0056b3;
    
     }
    
     @media (max-width: 768px) {
    
         #chatBox {
    
             width: 100%;
    
             bottom: 20px;
    
             padding: 15px;
    
         }
    
         #messageInput {
    
             width: calc(100% - 100px);
    
         }
    
         button {
    
             width: 70px;
    
             padding: 10px;
    
         }
    
     }
    
  
    
     </style>
    
     <script>
    
     let websocket;
    
     const sid = Math.random().toString(36).substring(2, 15); //用户端的sid
    
     const isAdmin = false; //这是用户端,管理员标识为false
    
  
    
     function connectWebSocket() {
    
         websocket = new WebSocket("ws://localhost:8080/api/websocket/" + sid);
    
  
    
         websocket.onopen = () => {
    
             console.log("连接成功,用户ID:" + sid);
    
             document.getElementById("messages").innerHTML += `<div class="message-left">连接成功,您的ID是:${sid}</div>`;
    
         };
    
  
    
         websocket.onmessage = (event) => {
    
             try {
    
                 let data;
    
                 // 检查消息是否是有效的 JSON
    
                 if (event.data && event.data.startsWith("{")) {
    
                     data = JSON.parse(event.data);
    
                     const { targetSid, message, sourceSid } = data;
    
  
    
                     // 确保消息是发送给当前用户的
    
                     if (sourceSid === "admin" || targetSid === sid) {
    
                         document.getElementById("messages").innerHTML += `<div class="message-left">${message}</div>`;
    
                         scrollToBottom();
    
                     }
    
                 } else {
    
                     // 如果不是 JSON 格式,可以直接处理其他类型的消息
    
                     document.getElementById("messages").innerHTML += `<div class="message-left">${event.data}</div>`;
    
                     scrollToBottom();
    
                 }
    
             } catch (e) {
    
                 console.error("解析消息失败", e);
    
             }
    
         };
    
  
    
  
    
  
    
  
    
         websocket.onclose = () => {
    
             console.log("连接关闭");
    
         };
    
  
    
         websocket.onerror = (error) => {
    
             console.error("WebSocket发生错误", error);
    
         };
    
     }
    
  
    
     function sendMessage() {
    
         const message = document.getElementById("messageInput").value;
    
         const targetSid = "admin"; //目标为管理员
    
  
    
         if (message.trim() !== "") {
    
             websocket.send(JSON.stringify({ targetSid, message }));
    
             document.getElementById("messages").innerHTML += `<div class="message-right">${message}</div>`;
    
             document.getElementById("messageInput").value = '';
    
             scrollToBottom();
    
         }
    
     }
    
  
    
  
    
     function scrollToBottom() {
    
         const messagesDiv = document.getElementById("messages");
    
         messagesDiv.scrollTop = messagesDiv.scrollHeight;
    
     }
    
  
    
     connectWebSocket();
    
     </script>
    
 </head>
    
 <body>
    
 <div id="chatBox">
    
     <h3>用户聊天窗口</h3>
    
     <div id="messages"></div>
    
     <div id="inputWrapper">
    
     <input id="messageInput" type="text" placeholder="请输入消息">
    
     <button onclick="sendMessage()">发送</button>
    
     </div>
    
 </div>
    
 </body>
    
 </html>
    
    
    
    
    html
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/elthO3qdUC2yJm47PbFjDHczALMu.png)

项目部署

1.准备云服务器

2.在服务器上安装jdk

(1)yum install -y java-1.8.0-openjdk-devel.x86_64

(2)输入java -version查看已安装的jdk版本

3.在服务器上安装tomcat

执行以下wget命令从指定位置下载tomcat-9版本软件包

(2)解压后进入到文件目录,启动

3.修改项目

(1)修改pom文件

添加打包方式:

添加tomcat和websocket依赖:

复制代码
     <dependency>

    
         <groupId>org.springframework.boot</groupId>
    
         <artifactId>spring-boot-starter-tomcat</artifactId>
    
         <scope>provided</scope> <!-- 提示该依赖已由外部服务器提供 -->
    
     </dependency>
    
     <dependency>
    
         <groupId>javax.websocket</groupId>
    
         <artifactId>javax.websocket-api</artifactId>
    
         <version>1.1</version>
    
     </dependency>
    
    
    
    
    XML
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/YfReZdrcMBH1F6UtQWlp2nG53Nho.png)

添加插件:

复制代码
         <plugin>

    
             <groupId>org.apache.maven.plugins</groupId>
    
             <artifactId>maven-war-plugin</artifactId>
    
             <configuration>
    
                 <failOnMissingWebXml>false</failOnMissingWebXml>
    
             </configuration>
    
         </plugin>
    
    
    
    
    XML

(2)修改启动类

复制代码
 package com.qcby.chatroom1117;

    
  
    
 import javafx.application.Application;
    
 import org.springframework.boot.SpringApplication;
    
 import org.springframework.boot.autoconfigure.SpringBootApplication;
    
 import org.springframework.boot.builder.SpringApplicationBuilder;
    
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
    
  
    
 @SpringBootApplication
    
 public class ChatRoom1117Application extends SpringBootServletInitializer {
    
  
    
     public static void main(String[] args) {
    
     SpringApplication.run(ChatRoom1117Application.class, args);
    
     }
    
  
    
     @Override  //这个表示使用外部的tomcat容器
    
     protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
    
     // 注意这里要指向原先用main方法执行的启动类
    
     return builder.sources(ChatRoom1117Application.class);
    
     }
    
  
    
 }
    
    
    
    
    java
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-07-13/Qhi9UFwxD8uMSXoqY1VpEOZTlr0C.png)

(3)修改前端代码

4.打包

先执行clean,再执行install

5.上传war包到tomcat文件夹的webapp目录下

6.重新启动tomcat,访问

[用户端 - 聊天窗口

icon-default.png?t=O83A

http://47.96.252.224:8080/chatroom1117-0.0.1-SNAPSHOT/user](http://47.96.252.224:8080/chatroom1117-0.0.1-SNAPSHOT/user "用户端 - 聊天窗口")

[管理员端 - 聊天窗口

icon-default.png?t=O83A

该链接指向后端管理界面下的通讯室(即聊天窗口),供管理员使用

至此,部署完成

全部评论 (0)

还没有任何评论哟~