如何在Spring MVC中使用WebSocket检测客户端是否已断开连接

4
我希望能够检测用户是否与服务器失去连接(关闭标签页、断网等)。我在客户端使用stompjs和Sockjs,在服务器上使用spring mvc websockets。如何检测客户端是否失去连接?以下是我的websocket消息brocket配置:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfiguration extends AbstractWebSocketMessageBrokerConfigurer {
    @Autowired
    private TaskScheduler scheduler;

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic").setHeartbeatValue(new long[]{10000, 10000}).setTaskScheduler(scheduler);
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/web").setAllowedOrigins("*").withSockJS();
    }
}

这是我的控制器类,它实际处理传入的套接字消息:

@RestController
@CrossOrigin
public class WebMessagingController {

    @MessageMapping("/chat/message")
    public void newUserMessage(String json) throws IOException {
        messagesProcessor.processUserMessage(json);
    }
}

我知道如果我使用继承自TextWebSocketHandler的类,我将能够重写在客户端连接和断开时调用的方法,但我不认为这对于sock-js客户端会有效。谢谢。
2个回答

10
除了Artem的回答外,您还可以在任何Spring bean中使用@EventListener注释:
@EventListener
public void onDisconnectEvent(SessionDisconnectEvent event) {
    LOGGER.debug("Client with username {} disconnected", event.getUser());
}

你也是一个英雄! - ata
1
如何获取用户断开连接的URL?Stomp头部目标始终为空。 - Feroz Siddiqui
@FerozSiddiqui 在断开连接事件中无法获取目标地址。您可以在SUBSCRIBE时存储会话和会话ID,然后在断开连接时通过会话ID查找。此外,您还可以在SUBSCRIBE事件中接收目标地址,因此您可以将其存储并稍后从数据库中获取URL以在断开连接时使用。 - Gladiator9120

4

StompSubProtocolHandler 实现了 afterSessionEnded() 方法,该方法由 WebSocketHandler.afterConnectionClosed() 调用。前者会像这样发出一个事件:

/**
 * Event raised when the session of a WebSocket client using a Simple Messaging
 * Protocol (e.g. STOMP) as the WebSocket sub-protocol is closed.
 *
 * <p>Note that this event may be raised more than once for a single session and
 * therefore event consumers should be idempotent and ignore a duplicate event.
 *
 * @author Rossen Stoyanchev
 * @since 4.0.3
 */
@SuppressWarnings("serial")
public class SessionDisconnectEvent extends AbstractSubProtocolEvent {

所以,您需要一个ApplicationListener来处理这个SessionDisconnectEvent,事件中包含了所有的信息。

有人知道在Spring 5.0之前如何做到这一点吗? - David Bradley
1
不确定你的问题是关于什么的。API 真的存在于某个 4.x 版本中。所以,你要做的就是完全相同。如果有什么不起作用,最好提出一个新的 SO 线程。不知何故,这个上下文略有不同... - Artem Bilan
我在4.2.8中没有看到它,但也许我错过了某个依赖项或其他东西。 - David Bradley
1
你做错了什么。这确实是 4.2.8 版本:https://github.com/spring-projects/spring-framework/blob/v4.2.8.RELEASE/spring-websocket/src/main/java/org/springframework/web/socket/messaging/SessionDisconnectEvent.java - Artem Bilan
是的,它位于不同的库中,不是基本的网络依赖部分。由于某种原因,Eclipse 不知道那个其他库,所以它似乎不存在。通常它会提供添加依赖项的选项。 - David Bradley
你是一个英雄! - ata

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