Spring boot 如何根据条件限制Spring中订阅特定主题的stomp客户端的数量?

Spring boot 如何根据条件限制Spring中订阅特定主题的stomp客户端的数量?,spring-boot,websocket,spring-websocket,stomp,Spring Boot,Websocket,Spring Websocket,Stomp,我一直在研究一种方法,以限制可以订阅特定stomp主题但尚未理解的客户数量,这可能是根据我的需要采取的正确方法 我的用例是一个游戏,我正在Angular(ng2 stompjs stomp客户端)和Spring Boot Websockets(目前正在使用Spring内存消息代理)中开发它 其想法是,用户可以连接并订阅“/大厅”跺脚主题,在那里他可以看到打开的游戏室,这些游戏室可能处于不同的状态。例如,由于加入的玩家数量较少,正在比赛或尚未开始。 我想截取并以编程方式将客户端的可能订阅限制为特定

我一直在研究一种方法,以限制可以订阅特定stomp主题但尚未理解的客户数量,这可能是根据我的需要采取的正确方法

我的用例是一个游戏,我正在Angular(ng2 stompjs stomp客户端)和Spring Boot Websockets(目前正在使用Spring内存消息代理)中开发它

其想法是,用户可以连接并订阅“/大厅”跺脚主题,在那里他可以看到打开的游戏室,这些游戏室可能处于不同的状态。例如,由于加入的玩家数量较少,正在比赛或尚未开始。 我想截取并以编程方式将客户端的可能订阅限制为特定的“/room/{roomId}”主题,如果已达到最大玩家数,例如4。也可能有一些简单的客户端验证来限制这一点,但我认为只有客户端验证是不够的

因此,我的主要问题是: 如何在春季拦截特定的stomp主题订阅? 是否可以向客户端请求者返回某种无法完成订阅的错误消息


我非常感谢你的帮助,提前谢谢你

您可以实现一个侦听订阅的StompEventListener,在这里,我们可以将目的地(房间号)与该特定房间中的玩家数量进行映射。如果计数已达到最大值,则拒绝订阅

@Service
class StompEventListener() {
   private Map<String, int> roomIdVsPlayerCount = new HashMap<>();
   
   @EventListener
   public void handleSubscription(SessionSubscribe event) {
     StompHeaderAccessor accessor = StompHeaderAccessor.wrap(event.getMessage());
     String destination = accessor.getDestination();

     String roomId = destination.substring(...); //Parsed RoomID
     if(roomIdVsPlayerCount.get(roomId) == MAX_ALLOWED_PLAYERS) {
       //Throw exception which will terminate that client connection 
         or, send an error message like so:
       simpMessagingTemplate.convertAndSend(<some_error_message>);
       return;
     }
     //So it is not at maximum do further logic to actually subscribe 
       user and
     roomIdVsPlayerCount.get(roomId) += 1; 
   }

   @EventListener
   public void handleUnsubscription(SessionUnsubscribe event) {
    ...
   }
}


实现
TopicSubscriptionInterceptor的有用参考资料

您可以提供代码片段、配置或您迄今为止尝试过的内容。看起来是一个很好的建议。虽然我似乎无法阻止实际订阅。尝试抛出异常,甚至使用SimpMessageTemplate发回消息,实际订阅发生,客户端继续接收messages@Luis如果您已经添加了一个修复程序,请在实现拦截器之后进行检查。拥有一个自定义的ChannelInterceptor必须是正确的方法。现在,我将在返回null之前向客户机发送一条自定义消息,而不是抛出异常。如果我们查看ChannelInterceptor#preSend,它会在消息发送到通道或消息代理之前被调用,但是如果返回null,则不会发生send-因此代理中的实际订阅不会发生。抛出异常将关闭连接并发送错误帧,这在我的情况下不是很有用。不过,谢谢你的帮助:)
@Component
class TopicSubscriptionInterceptor implements ChannelInterceptor {
    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel){
      StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
      String destination = accessor.getDestination();

      String roomId = destination.substring(...); //Parsed RoomID
      if(roomIdVsPlayerCount.get(roomId) == MAX_ALLOWED_PLAYERS) {
        //Throw exception which will terminate that client connection 
      }
     
     //Since it is not at limit continue 
    
    }
}