当前位置: 首页 > 面试题库 >

在SockJS + Spring Websocket中,convertAndSendToUser中的“用户”来自哪里?

巴英韶
2023-03-14
问题内容

我想了解convertAndSendToUser如何在Spring SockJS + Websocket框架中工作。

在客户端,我们将连接为

stompClient.connect(login, password, callback())

这将导致使用登录名和密码的“ Stomp凭据”进行连接请求,例如,如果我们处理SessionConnectEvent
http://www.sergialmar.com/2014/03/detect-websocket-connects-and-disconnects-
in
,就会看到该请求-spring-4
/

但是我仍然不清楚这是否是服务器端发送到队列的“用户”:

 simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message);

我能得到的最接近的是在SpringWebsocket上阅读此线程正在向特定用户发送消息,作者是Thanh Nguyen Van,但仍不清楚。

基本上,我需要做的是使一些客户端订阅同一主题,但是在服务器上,向他们发送不同的数据。客户可以提供用户标识符。


问题答案:

我们知道我们可以使用他订阅的主题前缀从单足服务器向客户端发送消息/topic/hello。我们也知道我们可以将消息发送给特定的用户,因为spring提供了convertAndSendToUser(username, destination, message)API。它接受一个字符串用户名,这意味着如果我们为每个连接都拥有唯一的用户名,则我们应该能够向订阅主题的特定用户发送消息。

鲜为人知的是,该用户名来自何处?

该用户名是java.security.Principal界面的一部分。每个StompHeaderAccessorWebSocketSession对象有此主体的情况下,你可以从它那里得到的用户名。但是,根据我的实验,它不是自动生成的。
它必须由服务器为每个会话手动生成。

要首先使用此接口,您需要实现它。

class StompPrincipal implements Principal {
    String name

    StompPrincipal(String name) {
        this.name = name
    }

    @Override
    String getName() {
        return name
    }
}

然后,可以StompPrincipal通过覆盖DefaultHandshakeHandler为每个连接生成唯一的。您可以使用任何逻辑来生成用户名。这是一种使用UUID的潜在逻辑:

class CustomHandshakeHandler extends DefaultHandshakeHandler {
    // Custom class for storing principal
    @Override
    protected Principal determineUser(
        ServerHttpRequest request,
        WebSocketHandler wsHandler,
        Map<String, Object> attributes
    ) {
        // Generate principal with UUID as name
        return new StompPrincipal(UUID.randomUUID().toString())
    }
}

最后,您需要配置websocket以使用自定义的握手处理程序。

@Override
void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
    stompEndpointRegistry
         .addEndpoint("/stomp") // Set websocket endpoint to connect to
         .setHandshakeHandler(new CustomHandshakeHandler()) // Set custom handshake handler
         .withSockJS() // Add Sock JS support
}

而已。现在,您的服务器已配置为为每个连接生成唯一的主体名称。它将把该主体作为StompHeaderAccessor您可以通过连接事件侦听器,MessageMapping函数等访问的对象的一部分进行传递。

来自事件监听器:

@EventListener
void handleSessionConnectedEvent(SessionConnectedEvent event) {
    // Get Accessor
    StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage())
}

从消息映射的API

@MessageMapping('/hello')
protected void hello(SimpMessageHeaderAccessor sha, Map message) {
    // sha available in params
}

关于使用的最后一点说明convertAndSendToUser(...)。向用户发送消息时,您将使用类似这样的内容

convertAndSendToUser(sha.session.principal.name, '/topic/hello', message)

但是,要订阅客户端,您将使用

client.subscribe('/user/topic/hello', callback)

如果您订阅客户端,/topic/hello您将只收到广播的消息。



 类似资料:
  • 我正在尝试使用Springframework SimpMessageTemplate(默认Stomp实现)来流式传输时间序列数据,以将消息广播到SockJS客户端订阅的主题。但是,这些消息是按顺序接收的。服务器是单线程的,消息按时间戳升序发送。客户端以某种方式接收到了顺序错误的消息。 我使用的是stompjs和springframework的最新版本(4.1.6版本)。

  • 我试着把这个角色的激动人心的部分 我尝试过XPath,但它不起作用,因为在将所有内容输出为XML之前,我必须生成DigestValue

  • 我想了解convertAndSendToUser如何在SpringSockJSWebSocket框架中工作。 在客户端中,我们将作为 这将导致连接请求与"跺脚凭据"的登录名和密码,这可以看到,例如,如果我们处理SessionConnect事件http://www.sergialmar.com/2014/03/detect-websocket-connects-and-disconnects-in-

  • 一、STOMP协议介绍 STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。 STOMP协议的前身是TTMP协

  • Spring WebSocket的留档状态为: 应用程序可以发送针对特定用户的消息,为此,Spring的STOMP支持识别前缀为“/user/”的目的地。例如,客户端可能订阅目的地"/user/队列/位置更新"。该目的地将由UserDestinationMessageHandler处理,并转换为用户会话独有的目的地,例如"/队列/位置-更新-用户123"。这提供了订阅通用命名目的地的便利,同时确保

  • 问题内容: 我有一个线程类“ MyThread”和主应用程序,简称为“ Gui”。我想从线程类创建一些对象,但在本示例中,我仅创建了一个对象。线程类完成一些工作,然后向Gui类发出信号,指示需要用户输入(此指示目前仅是更改按钮的文本)。然后,线程应等待用户输入(在这种情况下为单击按钮),然后继续执行其操作… 如何在(多个)线程中等待用户输入? 问题答案: 默认情况下,具有事件循环,可以处理信号和插