zoukankan      html  css  js  c++  java
  • springboot使用WebSocket

    springboot使用WebSocket

    来源:https://blog.lqdev.cn/2018/08/14/springboot/chapter-nineteen/

    类似聊天室的功能,

    WebSocketHTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。

    WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

    浏览器通过JavaScript向服务器发出建立WebSocket连接的请求,连接建立以后,客户端和服务器端就可以通过TCP连接直接交换数据。

    当获取Web Socket连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。

    前端:

    对于前端,创建一个WebSocket对象,如下:

    var Socket = new WebSocket(url, [protocol] );
    说明:第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
    

    WebSocker属性

    属性 描述
    Socket.readyState 只读属性 readyState 表示连接状态,可以是以下值: 0 - 表示连接尚未建立。 1 - 表示连接已建立,可以进行通信。 2 - 表示连接正在进行关闭。 3 - 表示连接已经关闭或者连接不能打开。
    Socket.bufferedAmount 只读属性 bufferedAmount 已被 send() 放入正在队列中等待传输,但是还没有发出的 UTF-8 文本字节数。

    WebSocket事件

    事件 事件处理程序 描述
    open Socket.onopen 连接建立时触发
    message Socket.onmessage 客户端接收服务端数据时触发
    error Socket.onerror 通信发生错误时触发
    close Socket.onclose 连接关闭时触发

    WebSocket方法

    方法 描述
    Socket.send() 使用连接发送数据
    Socket.close() 关闭连接

    后端

    后端关于WebSocket的实现是基于JSR356标准的。该标准的出现,统一了 WebSocket的代码写法。只要支持web容器支持JSR356标准,那么实现方式是一致的。而目前实现方式有两种,一种是注解方式,另一种就是继承继承javax.websocket.Endpoint类了。

    常用注解说明

    • @WebSocketEndpoint
      注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址。
    • @onOpen
      打开一个新连接,即有新连接时,会调用被此注解的方法。
    • @onClose
      关闭连接时调用。
    • @onMessage
      当服务器接收到客户端发送的消息时所调用的方法。
    • @PathParam
      接收uri参数的,与@PathVariable功能差不多,可通过url获取对应值

    配置

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-websocket</artifactId>
    </dependency>
    

    工具类WebSocketUtil

    public class WebSocketUtil {
     
        /**
         * 简单使用map进行存储在线的session
         *
         */
        private static final Map<String, Session> ONLINE_SESSION = new ConcurrentHashMap<>();
     
        public static void addSession(String userNick,Session session) {
            //putIfAbsent 添加键—值对的时候,先判断该键值对是否已经存在
            //不存在:新增,并返回null
            //存在:不覆盖,直接返回已存在的值
    //        ONLINE_SESSION.putIfAbsent(userNick, session);
            //简单示例 不考虑复杂情况。。怎么简单怎么来了。。
            ONLINE_SESSION.put(userNick, session);
        }
     
        public static void remoteSession(String userNick) {
            ONLINE_SESSION.remove(userNick);
        }
     
        /**
         * 向某个用户发送消息
         * @param session 某一用户的session对象
         * @param message
         */
        public static void sendMessage(Session session, String message) {
            if(session == null) {
                return;
            }
            // getAsyncRemote()和getBasicRemote()异步与同步
            Async async = session.getAsyncRemote();
            //发送消息
            async.sendText(message);
        }
     
        /**
         * 向所有在线人发送消息
         * @param message
         */
        public static void sendMessageForAll(String message) {
            //jdk8 新方法
            ONLINE_SESSION.forEach((sessionId, session) -> sendMessage(session, message));
        }
    }
    

    controller使用

    注意点:

    1. @ServerEndpoint的value值填写时,开头需要加上/,不然会提示路径无效。
    2. 需要加上类型@Component注解,使得能被扫描到。
    3. 这里的session等,都在包javax.websocket包下的,注意区分。
    /**
    * websocket 简易聊天
    * @author oKong
    *
    */
    //由于是websocket 所以原本是@RestController的http形式
    //直接替换成@ServerEndpoint即可,作用是一样的 就是指定一个地址
    //表示定义一个websocket的Server端
    @Component
    @ServerEndpoint(value = "/my-chat/{usernick}")
    @Slf4j
    public class WebSocketController {
     
        /**
         * 连接事件 加入注解
         * @param session
         */
        @OnOpen
        public void onOpen(@PathParam(value = "usernick") String userNick,Session session) {
            String message = "有新游客[" + userNick + "]加入聊天室!";
            log.info(message);
            WebSocketUtil.addSession(userNick, session);   
            //此时可向所有的在线通知 某某某登录了聊天室           
            WebSocketUtil.sendMessageForAll(message);
        }
     
        @OnClose
        public void onClose(@PathParam(value = "usernick") String userNick,Session session) {
            String message = "游客[" + userNick + "]退出聊天室!";
            log.info(message);
            WebSocketUtil.remoteSession(userNick);   
            //此时可向所有的在线通知 某某某登录了聊天室           
            WebSocketUtil.sendMessageForAll(message);
        }
     
        @OnMessage
        public void OnMessage(@PathParam(value = "usernick") String userNick, String message) {
            //类似群发
            String info = "游客[" + userNick + "]:" + message;
            log.info(info);
            WebSocketUtil.sendMessageForAll(message);
        }
     
        @OnError
        public void onError(Session session, Throwable throwable) {
            log.error("异常:", throwable);
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            throwable.printStackTrace();
        }
     
    }
    

    主类设置

    主启动类,主要是加入注解@EnableWebSocket和申明一个Websocket endpoint

    @SpringBootApplication
    @EnableWebSocket
    @Slf4j
    public class Chapter19Application {
     
        public static void main(String[] args) {
            SpringApplication.run(Chapter19Application.class, args);
            log.info("Chapter19启动!");
        }
     
        /**
         * 会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
         * 要注意,如果使用独立的servlet容器,
         * 而不是直接使用springboot的内置容器,
         * 就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。
         */
        @Bean
        public ServerEndpointExporter serverEndpointExporter() {
            return new ServerEndpointExporter();
        }
    }
    
  • 相关阅读:
    5917
    安装wdcp后,反向代理全过程
    今天 想了个问题,阿里旺旺及时消息
    5917全部电影 我反代了一个站
    曾经4000多IP的站,被百度K了
    asp.net 出现Operation is not valid due to the current state of the object.
    自然语言处理 |文本相似度计算与文本匹配问题
    Node.js v16.13.0 连接MySQL数据库8.0.27失败问题
    NLP自然语言处理 | Prolog 语言入门教程:
    NLP自然语言处理 | TFIDF与余弦相似性的应用(二):找出相似文章
  • 原文地址:https://www.cnblogs.com/ziyue7575/p/10341232.html
Copyright © 2011-2022 走看看