我正在建立一个小型Web聊天,以了解Spring和Spring WebSocket。您可以创建不同的房间,每个房间在/topic/room/{id}
都有自己的频道。
我的目标是检测用户何时加入和离开聊天室,我认为我可以为此使用Spring WebSocket的SessionSubscribeEvent
和SessionUnsubscribeEvent
。
从SessionSubscribeEvent
获取目的地很简单:
@EventListener
public void handleSubscribe(final SessionSubscribeEvent event) {
final String destination =
SimpMessageHeaderAccessor.wrap(event.getMessage()).getDestination();
//...
}
但是,在以下代码段中,SessionUnsubscribeEvent
似乎没有传送目标频道,destination
是null
:
@EventListener
public void handleUnsubscribe(final SessionUnsubscribeEvent event) {
final String destination =
SimpMessageHeaderAccessor.wrap(event.getMessage()).getDestination();
//...
}
是否有更好的方法来监视订阅/取消订阅事件,我是否应该将其用作用户“登录”聊天室的方式,还是应该使用单独的渠道发送单独的“登录“ /”注销“消息并使用这些消息?
我认为使用订阅/取消订阅会很方便,但是显然Spring使它变得非常困难,所以我觉得必须有更好的方法。
答案 0 :(得分:0)
我认为使用SessionSubscribeEvent和SessionUnsubscribeEvent是个好主意。如果您跟踪SessionID,就可以得到目的地:
private Map<String, String> destinationTracker = new HashMap<>();
@EventListener
public void handleSubscribe(final SessionSubscribeEvent event) {
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(event.getMessage());
destinationTracker.put(headers.getSessionId(), headers.getDestination());
//...
}
@EventListener
public void handleUnsubscribe(final SessionUnsubscribeEvent event) {
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(event.getMessage());
final String destination = destinationTracker.get(headers.getSessionId());
//...
}
答案 1 :(得分:0)
STOMP标头仅出现在与您的问题相关的框中,如此处https://stomp.github.io/stomp-specification-1.2.html#SUBSCRIBE和此处:https://stomp.github.io/stomp-specification-1.2.html#UNSUBSCRIBE
所述只有SUBSCRIBE
框架同时具有目的地和ID,UNSUBSCRIBE
框架仅具有ID。
这意味着您必须记住带有目标的订阅ID,以供将来查找。必须注意,因为不同的Websocket连接通常使用/分配相同的订阅ID,因此,为了可靠地保存目标,必须在存储密钥中包含Websocket会话ID。
我编写了以下方法来获取它:
protected String getWebsocketSessionId(StompHeaderAccessor headerAccessor)
{
// SimpMessageHeaderAccessor.SESSION_ID_HEADER seems to be set in StompSubProtocolHandler.java:261 ("headerAccessor.setSessionId(session.getId());")
return headerAccessor.getHeader(SimpMessageHeaderAccessor.SESSION_ID_HEADER).toString();
}
StompHeaderAccessor
的创建方式如下:
StompHeaderAccessor headerAccessor=StompHeaderAccessor.wrap(((SessionSubscribeEvent)event).getMessage());
StompHeaderAccessor headerAccessor=StompHeaderAccessor.wrap(((SessionUnsubscribeEvent)event).getMessage());
然后可以使用它创建唯一的订阅ID,该ID可以用作地图的键,以保存有关订阅的数据,包括目的地:
protected String getUniqueSubscriptionId(StompHeaderAccessor headerAccessor)
{
return getWebsocketSessionId(headerAccessor)+"--"+headerAccessor.getSubscriptionId();
}
赞:
Map<String, String> destinationLookupTable=...;
// on subscribe:
destinationLookupTable.put(getUniqueSubscriptionId(headerAccessor), destination);
// on other occasions, including unsubscribe:
destination=destinationLookupTable.get(getUniqueSubscriptionId(headerAccessor));