Spring Boot WebSocket-如何获得客户端订阅通知

时间:2019-01-23 15:37:11

标签: java spring spring-boot websocket

我有一个具有大量组的应用程序,其中我的服务器正在使用消息队列(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/*频道时,如何在服务器上收到通知?网络用户在浏览网页时将进行订阅和取消订阅。

3 个答案:

答案 0 :(得分:1)

您可以使用注释驱动的事件侦听器(科特琳代码):

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

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

答案 1 :(得分:0)

您可以像这样监听事件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 :(得分:0)

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

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 对象包含从客户端发送的所有信息。