Spring框架中通过Websocket实时检测离线和在线客户端

我正在构建一个像 slack 这样的应用程序。我有很多客户端在网络和移动设备上运行。它们通过 websocket 连接Stomp。我想实时检测哪个用户在线和离线。Websocket服务器正在运行spring framework。spring 接受如下请求。我将其heartbeat incoming设置outgoing为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;

        }

    }

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


温温酱
浏览 266回答 4
4回答

蛊毒传说

您还可以使用org.springframework.messaging.simp.user.SimpUserRegistry;将其注入您的控制器或服务@AutowiredSimpUserRegistry simpUserRegistry;然后在方法中创建逻辑,您可以simpUserRegistry.findSubscriptions(matcher)像这样调用:public Set<SimpSubscription> onlineUsers(String chatroomId) {&nbsp; &nbsp; &nbsp; &nbsp; if(null == chatroomId || StringUtils.isEmpty(chatroomId)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return findSubscriptions("");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; Set<SimpSubscription> subscriptions = new HashSet<>();&nbsp; &nbsp; &nbsp; &nbsp; List<String> list = chatRoomService.listUserIdsInChatRoom(chatroomId);&nbsp; &nbsp; &nbsp; &nbsp; for (String userId: list) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subscriptions.addAll(findSubscriptions(userId));&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return subscriptions;&nbsp; &nbsp; }&nbsp; &nbsp;&nbsp;public Set<SimpSubscription> findSubscriptions(String userId) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return simpUserRegistry.findSubscriptions(new SimpSubscriptionMatcher() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public boolean match(SimpSubscription subscription) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return StringUtils.isEmpty(userId) ? true : subscription.getDestination().contains(userId);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; }它实际上是做什么的,它获取所有在线用户并将它们与您的特定 userId 进行匹配,如果 chatroomId 为空,它将为您获取所有聊天室的所有在线用户。

鸿蒙传说

实现ApplicationListener<SessionDisconnectEvent>并覆盖了下面的方法。@Override      public void onApplicationEvent(SessionDisconnectEvent event) {      }通过这种方式,我可以捕获哪个用户与 websocket 连接断开。我仍在等待您的最佳实践建议..

qq_花开花谢_0

SessionConnectedEvent — 当代理发送 STOMP CONNECTED 帧以响应 CONNECT 时,在 SessionConnectEvent 之后不久发布。此时可以认为STOMP会话完全建立。SessionDisconnectEvent — STOMP 会话结束时发布。DISCONNECT 可能是从客户端发送的,也可能是在 WebSocket 会话关闭时自动生成的。在某些情况下,每个会话可能会多次发布此事件。组件对于多个断开事件应该是幂等的。如果需要,您可以将在线用户存储在缓存中,并在相关用户出入时通过 Websocket 将其在线状态流式传输到客户端。

慕容森

使用会话 ID 来检测用户SocketJSthis.client = over(new SockJS(environment.SOCKET+'/end'));this.client.connect({userId:'UserIdHere'}, () => {});春季启动@Componentpublic class WebSocketEventListener {private static final Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);@Autowiredprivate SimpMessageSendingOperations messagingTemplate;@EventListenerpublic void handleWebSocketConnectListener(SessionConnectedEvent event) {&nbsp; &nbsp; StompHeaderAccessor stompAccessor = StompHeaderAccessor.wrap(event.getMessage());&nbsp; &nbsp; @SuppressWarnings("rawtypes")&nbsp; &nbsp; GenericMessage connectHeader = (GenericMessage) stompAccessor&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getHeader(SimpMessageHeaderAccessor.CONNECT_MESSAGE_HEADER); // FIXME find a way to pass the username&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // to the server&nbsp; &nbsp; @SuppressWarnings("unchecked")&nbsp; &nbsp; Map<String, List<String>> nativeHeaders = (Map<String, List<String>>) connectHeader.getHeaders()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .get(SimpMessageHeaderAccessor.NATIVE_HEADERS);&nbsp; &nbsp; String login = nativeHeaders.get("userId").get(0);&nbsp; &nbsp; String sessionId = stompAccessor.getSessionId();&nbsp; &nbsp; logger.info("Chat connection by user <{}> with sessionId <{}>", login, sessionId);}@EventListenerpublic void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {&nbsp; &nbsp; StompHeaderAccessor stompAccessor = StompHeaderAccessor.wrap(event.getMessage());&nbsp; &nbsp; String sessionId = stompAccessor.getSessionId();&nbsp; &nbsp; logger.info("Chat connection by user <{}> with sessionId <{}>", "Nop", sessionId);}}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java