有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在构建一个类似slack的应用程序。我有很多客户在网络和手机上运行。它们通过Stomp连接到websocket。我想实时检测哪个用户在线和离线Websocket服务器正在spring framework上运行。 spring接受如下请求。我将heartbeat{}和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;
        }
    }

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


共 (3) 个答案

  1. # 1 楼答案

    这在规范第节
    中有描述 20.4.12监听应用程序上下文事件并拦截消息

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

    • SessionConnectedEvent — 在SessionConnect事件后不久发布,此时代理已发送STOMP连接帧以响应CONNECT。在这一点上,跺脚会议可以被认为是完全建立起来的

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

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

  2. # 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. # 3 楼答案

    经过更多的搜索,我找到了一个描述为here的解决方案。我实现了ApplicationListener<SessionDisconnectEvent>并重写了下面的方法

    @Override
         public void onApplicationEvent(SessionDisconnectEvent event) {
    
         }
    

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