黑马 - websocket搭建在线聊天室

这里写自定义目录标题

一、消息推送常见方式

1、轮训方式

2、SSE(server-send event)服务器发送事件

3、websocket

二、websocket 是什么?

websocket 是一种基于TCP 连接上进行全双工通信的协议

三、websocket api的介绍

1、客户端 (浏览器)

  • websocket对象创建

  • websocket对象相关事件

  • websocket 对象提供的方法

2、服务端api Tomcat 的7.0.5版本开始支持 websocket , 并且实现了Java websocket 规范。

Java websocket 应用由一系列的 Endpoint组成。

Endpoint 是一个java对象,代表websocket连接的一段。对于服务端,我们可以视其为处理具体websocket消息的接口

我们可以通过两种方式定义EndPoint:

编程式,继承类 javax.websocket.Endpoint 并实现其方法

注解式,定义一个pojo,并添加@ServerEndPoint相关注解

  • 服务端如何接收客户端发过来的数据呢?

    • 编程式

      通过添加MessageHandler消息处理器来接收消息

    • 注解式

      在定义endpoint时,通过@OnMessage 注解指定接收消息的方法

  • 服务器如何推送消息给客户端

    发送消息由RemoteEndpoint完成,其实例由Session维护。

四、实现在线聊天室

1、需求

通过websocket实现在线聊天室

2、聊天室流程分析

3、消息格式

4、代码实现

1) 引入依赖

xml 复制代码
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>

2)编写配置类

扫描所有添加 @ServerEndpoint注解的Bean

java 复制代码
@Configuration
public class WebsocketConfig {

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

编写配置类,用于获取 HttpSession 对象

java 复制代码
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {

    /**
     * @param sec
     * @param request  握手请求
     * @param response
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 获取HttpSession对象
        HttpSession httpSession = (HttpSession) request.getHttpSession();
        // 将 HttpSession对象保存起来
        sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
    }
}

在@ServerEndpoint 注解中引入配置器 @ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfig.class)

java 复制代码
@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {

    /**
     * 使用static
     * ChatEndpoint是多例的,多个实例共享一个Map对象
     */
    private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();

    private HttpSession httpSession;

    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
        String userName = (String) httpSession.getAttribute("user");
        // 1、将我们的session进行保存
        onlineUsers.put(userName, session);
        // 2、广播消息,将登录的用户推送给所有的用户
        String message = MessageUtils.getMessage(true, null, userName + "上线");
        boardcast(message);
        // 3、

    }


    /**
     * 广播消息
     */
    private void boardcast(String message) {
        // 遍历 map 集合
        Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();
        for (Map.Entry<String, Session> entry : entries) {
            Session session = entry.getValue();
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                // 记录日志
            }
        }
    }

    /**
     * 浏览器发送消息到服务端,该方法会被调用
     */
    @OnMessage
    public void onMessage(String message, EndpointConfig endpointConfig) {
        try {
            this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
            String fromName = (String) httpSession.getAttribute("user");
            // 将消息推送给指定的用户   message : {"toName":"张三","message":"你好"}
            ClientMessage message1 = JSON.parseObject(message, ClientMessage.class);
            String toName = message1.getToName();
            Session session = onlineUsers.get(toName);
            String message2 = MessageUtils.getMessage(false, fromName, message1.getMessage());
            session.getBasicRemote().sendText(message2);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 当websocket连接断开时,此方法会被处罚
     */
    @OnClose
    public void onClose(Session session, EndpointConfig endpointConfig) {
        // 从在线用户集合中剔除断开连接的用户
        this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
        String userName = (String) httpSession.getAttribute("user");
        onlineUsers.remove(userName);
        // 通知其他用户当前用户下线
        String message = MessageUtils.getMessage(true, null, userName + "上线");
        boardcast(message);
    }
}
相关推荐
阿里云云原生21 分钟前
LoongSuite:解决 WebSocket 全链路可观测性难题,赋能 AI 应用的实时链路追踪
人工智能·websocket·网络协议·阿里云·云原生·可观测
unique_perfect15 小时前
vue2与springboot实现deepseek打印机聊天
spring boot·websocket·ai·vue2·deepseek
捧 花1 天前
Go Web 中 WebSocket 原理与实战详解
网络·后端·websocket·网络协议·http·golang·web
想用offer打牌1 天前
一站式了解长轮询,SSE和WebSocket
java·网络·后端·websocket·网络协议·系统架构
代码or搬砖1 天前
flask与vue实现通过websocket通信
vue.js·websocket·flask
2501_921649491 天前
外汇与贵金属行情 API 集成指南:WebSocket 与 REST 调用实践
网络·后端·python·websocket·网络协议·金融
weixin79893765432...1 天前
主流 AI 应用的“流式技术”的探索交流
websocket·sse·ai的流式技术·llm token·http chunked·async generator·message stream
Yu_Lijing2 天前
【个人项目】C++基于websocket的多用户网页五子棋(下)
网络·websocket·网络协议
两个人的幸福online3 天前
cocos 使用 WebSocket(goEasy版)
网络·websocket·网络协议
爱吃土豆的马铃薯ㅤㅤㅤㅤㅤㅤㅤㅤㅤ3 天前
aspect实现请求校验,但是WebSocket 端点类不能被 AOP 代理解决方案
网络·websocket·网络协议