WebSocket實現簡易版的多人聊天室

一、websocket簡介     

     WebSocket是一種在單個TCP連接上進行全雙工通信的協議。WebSocket使得客戶端和服務器之間的數據交換變得更加簡單,允許服務端主動向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。(百度百科)

二、多人聊天室的實現

1、後端服務器

(1)後端使用springboot搭建服務器,在IDEA中新建一個springboot工程,在pom.xml文件中引入spring-boot-starter-websocket依賴

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-websocket</artifactId>
    <version>2.0.4.RELEASE</version>
</dependency>

(2)寫一個配置類

@Configuration
public class WebSocketConfig {

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

(3)controller

package com.joe.study.eshopdemo.controller;

import org.springframework.stereotype.Controller;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

@Controller
@ServerEndpoint("/groupChat/{roomId}/{username}")
public class GroupChatController {

    // 保存 聊天室id -> 聊天室成員 的映射關係
    private static ConcurrentHashMap<String, List<Session>> rooms = new ConcurrentHashMap<>();

    // 收到消息調用的方法,羣成員發送消息
    @OnMessage
    public void onMessage(@PathParam("roomId") String roomId,
                          @PathParam("username") String username, String message) {
        List<Session> sessionList = rooms.get(roomId);
        // 分別向聊天室的成員發送消息
        sessionList.forEach(item -> {
            try {
                String text = username + ": " + message;
                item.getBasicRemote().sendText(text);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    // 建立連接調用的方法,羣成員加入
    @OnOpen
    public void onOpen(Session session, @PathParam("roomId") String roomId) {
        List<Session> sessionList = rooms.get(roomId);
        if (sessionList == null) {
            sessionList = new ArrayList<>();
            rooms.put(roomId, sessionList);
        }
        sessionList.add(session);
        System.out.println("成員加入---- 聊天室號:" + roomId + "  當前聊天室人數:" + sessionList.size());
    }

    // 關閉連接調用的方法,羣成員退出
    @OnClose
    public void onClose(Session session, @PathParam("roomId") String roomId) {
        List<Session> sessionList = rooms.get(roomId);
        sessionList.remove(session);
        System.out.println("成員退出---- 聊天室號:" + roomId + "  當前聊天室人數:" + sessionList.size());
    }

    // 傳輸消息錯誤調用的方法
    @OnError
    public void OnError(Throwable error) {
        System.out.println("消息傳遞出錯");
    }
}

2、前端

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>websocket多人聊天室</title>

    <style>
	  .container {
		margin-top: 30px;
		margin-left: 30px;
	  }
      .span1 {
        display: inline-block;
        width: 80px;
        font-size: 13px;
      }
      input {
        width: 200px;
        height: 30px;
        outline: none;
        border: 1px solid #3998f7;
        border-radius: 3px;
        padding: 0 10px;
      }
      input:hover,
      textarea:hover {
        box-shadow: 0 0 3px #3998f7;
      }
      #name {
        margin-top: 15px;
      }
      button {
        width: 100px;
        height: 30px;
        outline: none;
        color: #fff;
        font-size: 13px;
        font-weight: bold;
        background-color: #168ed1;
        border: none;
        border-radius: 5px;
        cursor: pointer;
      }
      #connectBtn,
      #content,
      #sendBtn,
      #closeBtn {
        margin-top: 10px;
      }
	  #messages {
		margin-top: 20px;
	  }
      textarea {
        width: 300px;
        height: 80px;
        outline: none;
        border: 1px solid #3998f7;
        border-radius: 3px;
        color: rgba(0, 0, 0, 0.7);
        font-size: 13px;
        font-weight: bold;
        padding: 5px;
      }
      #messages, .me, .name {
        color: rgba(0, 0, 0, 0.7);
        font-size: 14px;
        font-weight: bold;
      }
	  .me {
		color: red;
	  }
	  .name {
		color: royalblue;
	  }
    </style>
	</head>
	
  <body>
    <div class="container">
      <span class="span1">聊天室id:</span><input type="text" id="roomId" placeholder="請輸入聊天室id" /><br />
      <span class="span1">暱稱:</span><input type="text" id="name" placeholder="請輸入你的暱稱" /><br />
      <button id="connectBtn">連接</button><br />
      <textarea id="content" placeholder="請輸入要發送的消息"></textarea><br />
      <button id="sendBtn">發送</button>
      <button id="closeBtn">退出</button><br />
	  <div id="messages"></div>
    </div>

    <script type="text/javascript">
      const connectBtn = document.getElementById("connectBtn");
      const sendBtn = document.getElementById("sendBtn");
      const closeBtn = document.getElementById("closeBtn");
      const roomIdDOM = document.getElementById("roomId");
      const nameDOM = document.getElementById("name");
      const messagesDOM = document.getElementById("messages");
      const contentDOM = document.getElementById("content");
      let webSocket = null;

      // 加入聊天室
      connectBtn.addEventListener("click", () => {
        const roomId = roomIdDOM.value;
        const name = nameDOM.value;
        if (!roomId || !name) {
          alert("房間號和用戶名不能爲空");
          return;
        }
        const url = "ws://localhost:8787/groupChat/" + roomId + "/" + name;
        webSocket = new WebSocket(url);

        webSocket.onerror = e => {
          alert("出錯了");
        };
        webSocket.onopen = e => {
		  messagesDOM.innerHTML = "您已加入聊天室!";
		  connectBtn.style.display = 'none'
        };

        webSocket.onmessage = e => {
		  const nickname = e.data.split(":")[0];
		  const data = e.data.slice(e.data.indexOf(':') + 1)
          messagesDOM.innerHTML += `<br /><span class='${
            nickname === name ? "me" : "name"
          }'>${nickname === name ? "我" : nickname}: </span>&nbsp&nbsp;${data}`;
        };

        webSocket.onclose = e => {
		  connectBtn.style.display = 'none'
		  alert("您已退出聊天室");
        };
      });

      // 發送消息
      sendBtn.addEventListener("click", () => {
        webSocket.send(contentDOM.value);
        contentDOM.value = "";
      });

      // 退出聊天室
      closeBtn.addEventListener("click", () => {
        webSocket.close();
      });
    </script>
  </body>
</html>

 3、效果

發佈了20 篇原創文章 · 獲贊 0 · 訪問量 1443
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章