使用WebSocket实现一个简易的聊天室

我这里的框架是SpringBoot

首先,我们要有一个前端页面

html 复制代码
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org"
      xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout"
      layout:decorate="layout">
<head>
  <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js" defer></script>
  <meta charset="UTF-8"/>
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
  <title>websocket</title>
</head>
<body>
<input type="text" placeholder="请输入您想显示的昵称" name="username" id="username" />
<button onclick="connection()">链接服务器</button>
<!--<button onclick="send()">发送数据到服务器</button>-->
<button onclick="closeSocket()">关闭连接</button>
<p style="border: 1px solid black;width: 680px;height: 500px" id="talkMsg"></p>
<input id="message"/><button id="sendBtn" onclick="send()">发送</button>
</body>
<script>
  let sock=""
  let username=""
  function connection(){
    username = $("#username").val()
    //ws是WebSocket协议
    sock = new WebSocket('ws://localhost:8080/v1/point/' + username);

    //WebSocket事件
    sock.onopen = () => {
      console.log("已经与服务器建立连接.")
    }
    sock.onmessage = (e) => {
      console.log("\n已获取服务器响应的数据.")
      console.log(e)
      document.getElementById("talkMsg").innerHTML = e.data
    }
    sock.onclose = () => {
      console.log("已关闭与服务器的连接.")
    }
    sock.onerror = (e) => {
      console.log("连接发生异常.")
      console.log(e)
    }
  }


  /**
   * 发送数据到服务端
   */
  function send() {
    // sock.send(JSON.stringify({'message': ' hello world! '}))
    // sock.send(JSON.stringify({'message': document.getElementById("message").value }))
    if(document.getElementById("message").value===""){
      alert("抱歉,消息不能为空^_^")
    }else{
      var message = username + ":" +document.getElementById("message").value
      sock.send(message)
      //发送完信息之后输入框变为空
      document.getElementById("message").value=""
      document.getElementById("talkMsg").innerHTML=""
    }
  }

  /**
   * 关闭当前用户与WebSocket的连接
   */
  function closeSocket() {
    //代码只能是 1000,或者[3000, 4999]之间
    let code = 3000;
    let reason = "我想关闭连接!";
    sock.close(code, reason)
  }
</script>
</html>

其次,要有相关配置类以及Controller

配置类

java 复制代码
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 注解会把该方法的返回值当做一个JavaBean,存放在Spring上下文中,以供使用
     * ServerEndpointExporter类的作用是,会扫描所有的服务器端点,
     * 把带有  @ServerEndpoint 注解的所有类都添加进来
     * @return
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

Controller

java 复制代码
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.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 该类是用于ws的
 * value:当前 WebSocket 服务的访问(监听)地址
 */
@Component  //生产对象,声明为类
@ServerEndpoint(value = "/v1/point/{username}")     //表明监听地址
public class EndPointController {

    //存储用户,通过一个Map来完成存储
    private static final Map<String,EndPointController> online = new ConcurrentHashMap<>();

    //发送数据是通过session对象实现的,那么就要给每个用户一个session对象
    private Session session;

    //记录所发出的信息
    private static StringBuffer stringBuffer = new StringBuffer();
    //以下方法都是被触发,而不是访问
    /**
     * 连接建立时被调用。
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session, EndpointConfig config) throws IOException {
//        System.out.println("连接已经建立.");
        this.session = session;     //等号之前的session指的是第24行的,后面的是该方法的
        online.put(username,this);
        //给前端的控制台返回数据
//        session.getBasicRemote().sendText(username+"已加入群聊");
        String message = username + "已加入群聊";
        stringBuffer.append(message + "<br/>");
//        broadcastAllUsers(stringBuffer.toString());
    }

    /**
     * 收到消息时被调用。
     * @param message 前端传递过来的消息。
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
//        System.out.println("收到了消息:" + message);
        //将消息推送到前端
//        session.getBasicRemote().sendText("谢谢,我收到了你的消息:" + message);

        stringBuffer.append(message);
        broadcastAllUsers(stringBuffer.toString());
    }

    /**
     * 连接关闭时被调用.
     *
     * @param session
     * @param reason  关闭的理由
     */
    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("连接已关闭,关闭理由:" + reason);
    }

    /**
     * 当连接发生异常时被调用
     *
     * @param session
     * @param e
     */
    @OnError
    public void onError(Session session, Throwable e) {
        System.out.println("连接发生异常:" + e.getMessage());
        e.printStackTrace();
    }

    //遍历map将数据发送给每个用户
    private void broadcastAllUsers(String message) throws IOException {
        Set<String> names = online.keySet();    //keySet返回所有key值列表
        for (String name : names) {
            EndPointController endPoint = online.get(name);
            //将数据发送给每一个人
            stringBuffer.setLength(0);
            stringBuffer.append(message+ "<br/>");
            endPoint.session.getBasicRemote().sendText(stringBuffer.toString());
//            System.out.println(stringBuffer.toString());
        }
    }
}
相关推荐
青草地溪水旁7 分钟前
网络连接的核心机制
网络
花开富贵贼富贵1 小时前
计算机网络技术学习-day4《路由器配置》
网络·智能路由器·php
绵绵细雨中的乡音2 小时前
网络基础知识
linux·网络
还听珊瑚海吗3 小时前
基于WebSocket和SpringBoot聊天项目ChatterBox测试报告
spring boot·websocket·网络协议
想睡hhh3 小时前
网络基础——协议认识
网络·智能路由器
G_H_S_3_5 小时前
【网络运维】Linux 文本处理利器:sed 命令
linux·运维·网络·操作文本
绝缘体15 小时前
折扣大牌点餐api接口对接适合本地生活吗?
大数据·网络·搜索引擎·pygame
猿究院--王升6 小时前
HTTP的协议
网络
猿究院--冯磊6 小时前
计算机网络--HTTP协议
网络协议·计算机网络·http
G_H_S_3_7 小时前
【网络运维】Linux:正则表达式
linux·运维·网络·正则表达式