当前位置: 首页 > 知识库问答 >
问题:

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

戚永福
2023-03-14

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

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

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

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

我真的很感激你的帮助,提前谢谢你!

共有1个答案

商迪
2023-03-14

您可以实现一个侦听订阅的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) {
    ...
   }
}

有用的参考资料:

  1. SessionSubscribeeEvent(用于处理订阅)

编辑

请尝试从通道侦听器发送异常,因为上面没有发送异常,所以它会传播到客户端。我们前面定义的映射可以定义为一个单独类中的bean,该类可以访问(使用@Autowired)事件处理程序(用于递增和递减)和TopicSubscriptionInterceptor(用于验证)。

@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 
    
    }
}

实现TopicSubcriptionInterceptor的有用参考:TopicSubcriptionInterceptor

 类似资料:
  • 我正在使用spring Websocket与STOMP,简单的消息代理。在我的中,我使用方法级的,它应该为客户端订阅一个主题,以便客户端在之后接收该主题的消息。假设客户端订阅主题“聊天”: 当客户端订阅了“/app/chat”而不是“/topic/chat”时,此订阅将转到使用映射的方法: 这是spring裁判。说道: 默认情况下,来自@SubscribeMapping方法的返回值作为消息直接发送

  • 我有一个websocket服务器和一个websocket客户端,都是Java的。websocket服务器具有以下功能: 在 Java 网页滑板客户端中,我在我的踩踏会话处理程序中提供了以下内容: 然后,我能够通过客户端向服务器路径“hello”发送消息来在两者之间进行通信,然后由于客户端订阅了“topic/greetings”,所以我也要用我的stompFrameHandler来处理响应。 但是我

  • 我正在寻找使用Azure服务总线主题发布一些消息到我的服务。我已经为我的服务创建了一个订阅,并得到了连接字符串。我的服务(WebApi)正在大量实例(1000s)上运行。我正在考虑在应用程序启动我的服务时使用连接字符串在所有实例中启动Azure Service Bus的监听器。在一个Azure服务总线订阅下运行大量的侦听器(我的服务实例)是否有问题。我很好,只有一个实例接收到消息(这实际上是我更喜

  • 客户对主题的订阅(即订阅者)的寿命是多少? 我之所以这么担心,是因为我认为服务总线的一个特点--持久的信息。因此,我认为在连接不稳定的情况下,可以保证提供持久的消息。 那么,当一个应用程序(多个应用程序中的一个)失去与服务总线的连接一天,然后第二天重新启动应用程序并实例化一个新的订阅客户端实例时,会发生什么呢?当其他应用程序由于自己的订阅已经处理了这些相同的消息时,应用程序是否会继续接收等待传递的

  • 语境: 给定一个WooCommerce和WooCommerce订阅的WordPress网站,我试图获取特定用户订阅的列表。在最近的更新之前,这一行代码已经为我解决了这个问题。以下是我一直在使用的代码: 其中$user\u id是WordPress中的有效用户id。 问题: 自上次更新以来,我们经常看到以下错误: 致命错误:在/home/warfarep/public_html/wp content

  • 我用的是带Spring靴的网靴。是否有可能向特定订阅发送消息?根据STOMP文档,我使用包含id字段的STOMP头订阅STOMPendpoint,我希望使用此id确定应该接收消息的客户端,但是spring似乎没有使用这个id。我不能只使用sendToUser,因为两个客户端可以具有相同的用户id,例如,如果一个用户有两个打开的浏览器窗口。只有一个特定窗口应接收该消息。 在下面的示例中,我有两个连接