如何在使用Spring 4的WebSocket服务器中捕获连接事件?

7
5个回答

30

Spring WebSocket在从客户端接收消息时发布事件,如果您正在使用STOMP,则会发布以下事件:

最简单的检测连接和断开连接的方法是为上述事件实现一个事件监听器。

@Component
public class WebSocketEventListener {

    @EventListener
    private void handleSessionConnected(SessionConnectEvent event) {
        ...
    }

    @EventListener
    private void handleSessionDisconnect(SessionDisconnectEvent event) {
        ...
    }
}

这里是一个跟踪已连接用户的示例实现:https://github.com/salmar/spring-websocket-chat/blob/master/src/main/java/com/sergialmar/wschat/event/PresenceEventListener.java


1
你把sessionId存储在哪里? - Heril Muratovic

7

可以通过连接握手拦截器 (HttpSessionHandshakeInterceptor) 完成,引用文档:

自定义初始HTTP WebSocket握手请求的最简单方法是使用HandshakeInterceptor,它公开了“before”和“after”握手方法。


谢谢!实际上我使用了WebSocketMessageBrokerConfigurer,但是使用它可以这样工作:registry.addEndpoint("/api/v1/ws/pushService").withSockJS().setInterceptors(wsSessionInterceptor); - Yamit

6

我了解到,这个问题与DISCONNECT事件有关,在这个话题中没有得到解决。握手拦截只提供连接信息而不提供断开连接的信息。

我已经通过入站通道的拦截器来实现这一点:

<websocket:message-broker>
    ...
    <websocket:client-inbound-channel>
        <websocket:interceptors>
            <bean class="com......MyChannelInterception"></bean>
        </websocket:interceptors>
    </websocket:client-inbound-channel>
</websocket:message-broker>

...and class...

import java.security.Principal;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.support.ChannelInterceptorAdapter;

public class MyChannelInterception extends ChannelInterceptorAdapter {

private static final Logger LOGGER = LogManager.getLogger(WrcChannelInterception.class);

@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {

    MessageHeaders headers = message.getHeaders();
    SimpMessageType type = (SimpMessageType) headers.get("simpMessageType");
    String simpSessionId = (String) headers.get("simpSessionId");

    if (type == SimpMessageType.CONNECT) {
        Principal principal = (Principal) headers.get("simpUser");
        LOGGER.debug("WsSession " + simpSessionId + " is connected for user " + principal.getName());
    } else if (type == SimpMessageType.DISCONNECT) {
        LOGGER.debug("WsSession " + simpSessionId + " is disconnected");
    }
    return message;
}
}

请注意,Principal可以在连接时使用,但无法在断开连接时使用,但您拥有可爱的会话ID。

如何通过sessionID获取Principal? - disorderdev
在Connect上,您可以将sessionId和Principal之间的链接存储在数据库中,在Disconnect上,通过Session ID检索Principal。@disorderdev - walv
我们如何识别哪个客户端以及终端客户端已断开连接? - Feroz Siddiqui

0
这段代码片段可能会对你有所帮助:
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
    logger.info("afterConnectionEstablished called");
}

0

虽然原问题是关于Spring 4的 - Sergi已经很好地回答了。这里介绍一种在Spring 5或Spring Boot 2中实现它的方法(Spring Boot 2在内部使用Spring 5)。需要实现ApplicationListener:

@Component
public class WebSocketEventListener implements ApplicationListener<SessionConnectEvent> {
    Logger logger = LoggerFactory.getLogger(WebSocketEventListener.class);

    @Override
    public void onApplicationEvent(SessionConnectEvent event) {
        logger.error("SessionConnectEvent = " + event);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接