【问题标题】:Spring Boot WebSocket - how to get notified on client subscriptionsSpring Boot WebSocket - 如何获得有关客户端订阅的通知
【发布时间】:2019-06-17 06:00:02
【问题描述】:

我有一个包含大量组的应用程序,其中我的服务器使用消息队列 (RabbitMQ) 来观察组并在 WebSocket 发生更改时向用户发布通知。我正在使用 Spring boot 及其受本指南启发的 WebSocket 实现:https://spring.io/guides/gs/messaging-stomp-websocket/

以下是 JavaScript 客户端订阅频道的示例:

var socket = new SockJS('http://localhost/ws');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
    console.log('Connected: ' + frame);
    stompClient.subscribe('/topic/group/1/notification', function (message) {
        // to something..
    });
});

我的 Java Spring WebSocket 控制器有这个 broadcastNotification 方法将消息发送到 /topic/group/{groupId}/notification 通道。

@Controller
public class GroupController {
    private SimpMessagingTemplate template;

    @Autowired
    public GroupController(SimpMessagingTemplate template) {
        this.template = template;
    }

    public void broadcastNotification(int groupId, Notification notification) {
        this.template.convertAndSend("/topic/group/." + tenantId + "/notification", Notification);
    }
}

这很好,但考虑到性能,我希望我的业务逻辑只观察当前在 WebSocket 上订阅的组。

当客户订阅/topic/group/1/notification/topic/group/1/* 频道时,如何在我的服务器上收到通知?网络用户在浏览网页时会订阅和退订。

【问题讨论】:

    标签: java spring spring-boot websocket


    【解决方案1】:

    你可以像这样收听SessionSubscribeEvent的事件:

    @Component
    public class WebSocketEventListener {
    
      @EventListener
      public void handleSessionSubscribeEvent(SessionSubscribeEvent event) {
          GenericMessage message = (GenericMessage) event.getMessage();
          String simpDestination = (String) message.getHeaders().get("simpDestination");
    
          if (simpDestination.startsWith("/topic/group/1")) {
            // do stuff
          }
      }
    }
    

    【讨论】:

      【解决方案2】:

      您可以使用注解驱动的事件监听器(Kotlin 代码):

      @EventListener
      private fun onSubscribeEvent(event: SessionSubscribeEvent) {
          // do stuff...
      }
      

      此类事件监听器可以通过@EventListener 注解注册到托管 bean 的任何公共方法上。

      【讨论】:

        【解决方案3】:

        您可以使用WebSocketConfig 类中的interceptors 检测客户端何时订阅主题:

        import org.springframework.context.annotation.Configuration;
        import org.springframework.messaging.Message;
        import org.springframework.messaging.MessageChannel;
        import org.springframework.messaging.simp.config.ChannelRegistration;
        import org.springframework.messaging.simp.config.MessageBrokerRegistry;
        import org.springframework.messaging.simp.stomp.StompCommand;
        import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
        import org.springframework.messaging.support.ChannelInterceptor;
        import org.springframework.messaging.support.MessageHeaderAccessor;
        import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
        import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
        import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
        
        @Configuration
        @EnableWebSocketMessageBroker
        public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
            
            @Override
            public void configureMessageBroker(MessageBrokerRegistry config) {
              config.enableSimpleBroker("/topic");
              config.setApplicationDestinationPrefixes("/app");
            }
        
            @Override
            public void registerStompEndpoints(StompEndpointRegistry registry) {
              registry.addEndpoint("/gs-guide-websocket").withSockJS();
            }
          
            @Override
            public void configureClientInboundChannel(ChannelRegistration registration){
                registration.interceptors(new ChannelInterceptor() {
                    @Override
                    public Message<?> preSend(Message<?> message, MessageChannel channel) {
                        StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
        
                        if(StompCommand.CONNECT.equals(accessor.getCommand())){
                            System.out.println("Connect ");
                        } else if(StompCommand.SUBSCRIBE.equals(accessor.getCommand())){
                            System.out.println("Subscribe ");
                        } else if(StompCommand.SEND.equals(accessor.getCommand())){
                            System.out.println("Send message " );
                        } else if(StompCommand.DISCONNECT.equals(accessor.getCommand())){
                            System.out.println("Exit ");
                        } else {
                        }
                        return message;
                    }
                });
            }
        }
        
        

        accessor 对象包含从客户端发送的所有信息。

        【讨论】:

          猜你喜欢
          • 2021-01-16
          • 2019-07-23
          • 2023-01-31
          • 2023-04-03
          • 1970-01-01
          • 1970-01-01
          • 2016-05-19
          • 1970-01-01
          • 2018-09-16
          相关资源
          最近更新 更多