【问题标题】:Detect offline and online clients realtime in Spring framework via Websocket通过 Websocket 在 Spring 框架中实时检测离线和在线客户端
【发布时间】:2020-01-20 16:23:29
【问题描述】:

我正在构建一个像 slack 这样的应用程序。我有很多客户端在网络和移动设备上运行。它们通过Stomp连接到 websocket。我想实时检测哪个用户在线和离线。Websocket服务器正在spring framework 上运行。 spring 接受如下请求。我将 heartbeat incomingoutgoing 值设置为 20000 ms

    @Configuration
    @EnableWebSocketMessageBroker
    public class WebSocketConfig  implements WebSocketMessageBrokerConfigurer {

        private List<StompPrincipal> onlineUsers = new ArrayList<>();

        @Override
        public void registerStompEndpoints(StompEndpointRegistry registry) {

            registry.addEndpoint("/ws")
                    .setAllowedOrigins("*")
                    .setHandshakeHandler(new CustomHandshakeHandler())
                    .withSockJS();
        }

        @Override
        public void configureMessageBroker(MessageBrokerRegistry config) {
            config.setApplicationDestinationPrefixes("/ws");
            config.enableSimpleBroker("/ws")
                 .setTaskScheduler(new DefaultManagedTaskScheduler())
                 .setHeartbeatValue(new long[]{20000,20000});
        }
}

为了确定哪些用户请求Websocket,我添加了如下握手处理程序。

class CustomHandshakeHandler extends DefaultHandshakeHandler {
         @Override
        protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
                                          Map<String, Object> attributes) {

       String username=(String)attributes.get("name");
       StompPrincipal user = new StompPrincipal(username)

             onlineUsers.add(user);
            return user;
        }
    }

    class StompPrincipal implements Principal {
        String name;

        StompPrincipal(String name) {
            this.name = name;
        }

        @Override
        public String getName() {
            return name;
        }
    }

正如上面的代码,我可以看到用户在请求websocket server 之后添加了onlineUser。 但问题是,我无法确定用户在线后是否离线。请您建议我确定这一点。 通过这种方式确定在线和离线用户也是最佳实践吗?如果没有,等待您的建议。非常感谢。

【问题讨论】:

    标签: java spring spring-boot websocket spring-websocket


    【解决方案1】:

    经过更多搜索,我找到了描述here的解决方案。我实现了ApplicationListener&lt;SessionDisconnectEvent&gt;并覆盖了下面的方法。

    @Override
         public void onApplicationEvent(SessionDisconnectEvent event) {
    
         }
    

    通过这种方式,我可以捕捉到哪个用户与 websocket 连接断开连接。 我仍在等待您的最佳实践建议..

    【讨论】:

      【解决方案2】:

      使用会话 ID 检测用户

      SocketJS

      this.client = over(new SockJS(environment.SOCKET+'/end'));
      this.client.connect({userId:'UserIdHere'}, () => {
      });
      

      春季启动

      @Component
      public class WebSocketEventListener {
      
      private static final Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);
      
      @Autowired
      private SimpMessageSendingOperations messagingTemplate;
      
      @EventListener
      public void handleWebSocketConnectListener(SessionConnectedEvent event) {
      
          StompHeaderAccessor stompAccessor = StompHeaderAccessor.wrap(event.getMessage());
          @SuppressWarnings("rawtypes")
          GenericMessage connectHeader = (GenericMessage) stompAccessor
                  .getHeader(SimpMessageHeaderAccessor.CONNECT_MESSAGE_HEADER); // FIXME find a way to pass the username
                                                                                  // to the server
          @SuppressWarnings("unchecked")
          Map<String, List<String>> nativeHeaders = (Map<String, List<String>>) connectHeader.getHeaders()
                  .get(SimpMessageHeaderAccessor.NATIVE_HEADERS);
      
          String login = nativeHeaders.get("userId").get(0);
          String sessionId = stompAccessor.getSessionId();
      
          logger.info("Chat connection by user <{}> with sessionId <{}>", login, sessionId);
      
      }
      
      @EventListener
      public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
          StompHeaderAccessor stompAccessor = StompHeaderAccessor.wrap(event.getMessage());
          String sessionId = stompAccessor.getSessionId();
          logger.info("Chat connection by user <{}> with sessionId <{}>", "Nop", sessionId);
      
      }
      

      }

      【讨论】:

        【解决方案3】:

        这在
        20.4.12 监听 ApplicationContext 事件和拦截消息部分的规范中进行了描述

        https://docs.spring.io/spring-framework/docs/4.1.0.RC2/spring-framework-reference/html/websocket.html#websocket-stomp-appplication-context-events

        • SessionConnectedEvent — 在 SessionConnectEvent 之后不久发布,此时代理已发送 STOMP CONNECTED 帧以响应 CONNECT。此时可以认为 STOMP 会话已完全建立。

        • SessionDisconnectEvent — 在 STOMP 会话结束时发布。 DISCONNECT 可能是从客户端发送的,也可能是在 WebSocket 会话关闭时自动生成的。在某些情况下,此事件可能会在每个会话中发布不止一次。组件应该对多个断开连接事件是幂等的。

        如果需要,您可以将在线用户存储在缓存中,并在相关用户来来去去时通过 websocket 将相关用户的在线状态流式传输到客户端。

        【讨论】:

          猜你喜欢
          • 2019-12-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-12-11
          • 1970-01-01
          • 1970-01-01
          • 2017-05-03
          • 1970-01-01
          相关资源
          最近更新 更多