为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

温温酱 2023-08-09 15:48:33
我正在构建一个像 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。但问题是,我无法确定用户上线后是否离线。您能否建议我确定这一点。通过这种方式确定在线和离线用户是最佳实践吗?如果没有,等待您的建议。现在非常感谢。
查看完整描述

4 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

您还可以使用org.springframework.messaging.simp.user.SimpUserRegistry;


将其注入您的控制器或服务


@Autowired

SimpUserRegistry simpUserRegistry;

然后在方法中创建逻辑,您可以simpUserRegistry.findSubscriptions(matcher)像这样调用:


public Set<SimpSubscription> onlineUsers(String chatroomId) {

        if(null == chatroomId || StringUtils.isEmpty(chatroomId)) {

            return findSubscriptions("");

        }

        Set<SimpSubscription> subscriptions = new HashSet<>();

        List<String> list = chatRoomService.listUserIdsInChatRoom(chatroomId);

        for (String userId: list) {

            subscriptions.addAll(findSubscriptions(userId));

        }

        return subscriptions;

    }

    

public Set<SimpSubscription> findSubscriptions(String userId) {

            return simpUserRegistry.findSubscriptions(new SimpSubscriptionMatcher() {

                @Override

                public boolean match(SimpSubscription subscription) {

                    return StringUtils.isEmpty(userId) ? true : subscription.getDestination().contains(userId);

                }

            });

        }

它实际上是做什么的,它获取所有在线用户并将它们与您的特定 userId 进行匹配,如果 chatroomId 为空,它将为您获取所有聊天室的所有在线用户。


查看完整回答
反对 回复 2023-08-09
?
鸿蒙传说

TA贡献1865条经验 获得超7个赞

实现ApplicationListener<SessionDisconnectEvent>并覆盖了下面的方法。

@Override
     public void onApplicationEvent(SessionDisconnectEvent event) {

     }

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


查看完整回答
反对 回复 2023-08-09
?
qq_花开花谢_0

TA贡献1835条经验 获得超7个赞

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

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

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


查看完整回答
反对 回复 2023-08-09
?
慕容森

TA贡献1853条经验 获得超18个赞

使用会话 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);


}

}


查看完整回答
反对 回复 2023-08-09
  • 4 回答
  • 0 关注
  • 265 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信