• 53、springboot对websocket的支持有两种方式-------1、基于注解开发 WebSocket ,简洁实现多人聊天界面


    基于注解开发 WebSocket

    –注解就是: @OnOpen、 @OnClose 、 @OnMessage 、@OnError这些

    ★ WebSocket的两种开发方式

    ▲ Spring Boot为WebSocket提供了两种开发方式:

    • 基于spring-boot-starter-websocket.jar开发WebSocket

    • 基于Spring WebFlux开发WebSocket

    两种方式对比:
    springboot API
    在这里插入图片描述

    Socket:套接字。
    插座。
    在通信的两端分别建立虚拟的Socket(插座),网络协议就会负责在两个Socket之间建立虚拟线路。然后通信的两端即可通过该虚拟线路进行实时的、可靠的通信。

    WebSocket 就是在服务器与客户端浏览器之间的建立双向通信的Socket。从而保证服务器与客户端浏览器之间可进行实时的双向通信。

    ▲ 传统Web应用: 请求 - 响应。 这种模型没办法让服务器主动将数据推送客户端的浏览器。 还有比如SSE(服务器事件机制)

    ★ 基于Spring Boot自动配置来开发WebSocket

    两步:

    (1)定义一个WebSocket处理类
    该处理类有两种开发方式(历史原因造成):
    
    第一种方式:   - 直接使用JDK提供的 WebSocket注解 修饰处理方法,
                    并使用 @ServerEndpoint  注解修饰该处理类即可。
                    WebSocket注解就是: @OnOpen、 @OnClose 、 @OnMessage 、@OnError这些
      ——这种方式下方法签名可以随便写,方法参数也可以自行定义,非常灵活。
      官方也推荐尽量使用第一种方式
    
    第二种方式:    - 实现WebSocketHandler接口、并实现该接口中定义的各种处理方法。
      ——Java语法规定,实现接口时,实现的方法必须与接口中定义的方法有相同的方法签名。
      ——这种方式就不够灵活。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    (2)配置或导出WebSocket处理类
    如果采用注解方式开发WebSocket处理类,
    这一步只需要在 Spring容器 中配置一个ServerEndpointExporter Bean  (导出器)即可。
    该导出器会负责将容器中所有的@ServerEndpoint注解修饰的处理Bean都导出成WebSocket。
    因此无论程序有多少个WebSocket处理Bean,导出器Bean只要配置一个即可。
    ——非常简单、方便。
    
    如果采用是实现接口的方式开发WebSocket处理类,
    这一步就需要使用WebSocketConfigurer来配置WebSocket。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    代码演示

    创建项目
    在这里插入图片描述

    开发websocket的两步。
    在这里插入图片描述

    注解:@PathParam()

    属于 WebSocket 的,用于获取路径上的参数。
    在这里插入图片描述

    发送消息的简单解释:
    在这里插入图片描述

    完整代码:

    前端页面
    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title> 基于WebSocket的多人聊天 </title>
    	<script type="text/javascript">
    		// 定义Web Socket对象
    		var webSocket = null;
    		let sendMsg = function()
    		{
    			if (webSocket == null || webSocket.readyState != 1)
    			{
    				document.getElementById('show').innerHTML
    					+= "还未连接服务器,请先连接WebSocket服务器
    "
    ; return; } let inputElement = document.getElementById('msg'); // 发送消息 webSocket.send(inputElement.value); // 清空单行文本框 inputElement.value = ""; } let connect = function() { let name = document.getElementById('name').value.trim(); if (name == null || name == "") { document.getElementById('show').innerHTML += "用户名不能为空
    "
    ; return; } if (webSocket && webSocket.readyState == 1) { webSocket.close(); } webSocket = new WebSocket("ws://127.0.0.1:8080/websocket/" + name); webSocket.onopen = function() { document.getElementById('show').innerHTML += "恭喜您,连接服务器成功!
    "
    ; document.getElementById('name').value = ""; // 为onmessage事件绑定监听器,接收消息 webSocket.onmessage= function(event) { // 接收、并显示消息 document.getElementById('show').innerHTML += event.data + "
    "
    ; } }; } </script> </head> <body> <input type="text" size="20" id="name" name="name"/> <input type="button" value="连接" onclick="connect();"/> <div style="width:600px;height:240px; overflow-y:auto;border:1px solid #333;" id="show"></div> <input type="text" size="80" id="msg" name="msg"/> <input type="button" value="发送" onclick="sendMsg();"/> </body> </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    MyWebSocketHandler 注解开发各方法
    package cn.ljh.app.websocket;
    
    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    import javax.websocket.*;
    import javax.websocket.server.PathParam;
    import javax.websocket.server.ServerEndpoint;
    import java.util.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    
    //基于注解开发 WebSocket --注解就是: @OnOpen、 @OnClose 、 @OnMessage 、@OnError这些
    
    @Component
    //这个注解需要指定指定映射地址
    @ServerEndpoint("/websocket/{name}")
    @Slf4j
    public class MyWebSocketHandler
    {
        //可以用注解来修饰不同的处理方法
    
        //假设是一个聊天室,map 中的key 是每个用户的 Session , value 是用户的name
        //创建一个线程安全的map ,用这个map来保存各用户的Session与name之间的对应关系
        public final static Map<Session,String> myClients = new ConcurrentHashMap<>();
    
        //当浏览器 与 Websocket 服务器建立连接的时候触发该方法
        //这个Session参数代表浏览器 与 WebSocket 服务器所建立连接会话,它用于通信。
        //这个 @PathParam() 相当于spring mvc 中的 @PathVariable,
        //都是用来获取路径中的参数--获取这个路径"/websocket/{name}" 中的name参数
    
        @OnOpen
        public void onOpen(Session session , @PathParam("name") String name)
        {
            //当用户登录的时候,把信息存进去
            myClients.put(session,name);
            log.debug("--------- onOpen ----------");
        }
    
        //当浏览器与WebSocket服务器 关闭的时候触发该方法
        @OnClose
        public void onClose(Session session)
        {
            //当连接关闭的时候,就将该客户端从map中删除
            myClients.remove(session);
            log.debug("--------- onClose ----------");
        }
    
    
        //当 WebSocket服务器 收到 浏览器 发送过来的消息时触发该方法
        @SneakyThrows
        @OnMessage
        public String onMessage(Session session, String message)
        {
            //收到消息,把消息广播给每个客户端      keySet()-->将map中的所有key存到set集合中
            for (Session client : myClients.keySet())
            {
                //此处的 client 就代表每个客户端
                //向client 发送信息,这个 client 代表了一个浏览器
                //getBasicRemote() 表示给客户端发送消息是同步的、阻塞的    ,   sendText()  发送消息
                client.getBasicRemote().sendText(myClients.get(session)+" 说:"+message);
    
            }
            log.debug("--------- onMessage ----------"+message);
            return null;
        }
    
        //但 WebSocket 服务器 与 浏览器通信出现异常时触发该方法
        //这个 Throwable 参数就代表了出现的异常
        @OnError
        public void onError(Session session, Throwable ex)
        {
            //当连接出现异常的时候,将该客户端从 Map 中栅除
            myClients.remove(session);
            log.debug("--------- onError ----------");
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    MyWebSocketConfig 配置 WebSocket 导出器
    package cn.ljh.app.config;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.socket.server.standard.ServerEndpointExporter;
    
    /**
     * author JH
     * date 2023/9/7  0007 12:28
     */
    
    @Configuration
    public class MyWebSocketConfig
    {
        /*
         *配置 WebSocket 导出器
         *
         *   该导出器会负责将容器中所有的 @ServerEndpoint 注解修饰的 处理Bean 都导出成 WebSocket。
         *  因此无论程序有多少个 WebSocket 处理Bean,导出器Bean 只要配置一个即可。
         */
    
        @Bean
        public ServerEndpointExporter serverEndpointExporter()
        {
            return new ServerEndpointExporter();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    application.yml 配置日志级别
    #给这个包设置日志级别为debug
    logging:
      level:
        cn:
          ljh:
            app:
              websocket: debug
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    测试:

    进行websocket连接
    在这里插入图片描述

    成功基于注解开发WebSocket 的多人聊天室
    在这里插入图片描述

  • 相关阅读:
    万丈高楼平地起,每个API皆根基
    SpringCloud的新闻资讯项目03--- 自媒体文章发布
    跨境商城源码有哪些独特的功能和优势
    趣味问题《寻人启事》的Python程序解决
    foxmail群发邮件怎么发?
    Hive分组排序取topN的sql查询示例
    分布式文件存储 - - - MinIO从入门到飞翔
    远程Linux ssh 免密登录(本机为Windows)
    SpringCloud(三) RestTemplate实现服务间调用
    洛谷 P3808 【模板】AC 自动机(简单版)
  • 原文地址:https://blog.csdn.net/weixin_44411039/article/details/132686847