2014-03-13 73 views
42

如何從服務器向特定用戶發送websocket消息?在Spring上發送消息給特定用戶Websocket

我的web應用程序有彈簧安全設置並使用websocket。我遇到了棘手的問題,試圖從服務器發送消息到特定用戶只有

我從閱讀理解the manual從服務器我們可以做

simpMessagingTemplate.convertAndSend("/user/{username}/reply", reply); 

而且在客戶端:

stompClient.subscribe('/user/reply', handler); 

但我永遠無法獲得訂閱調用的回調。我嘗試了很多不同的道路,但沒有運氣。

如果我把它發送到/topic/reply它可以工作,但所有其他連接的用戶也會收到它。

爲了說明問題,我創建了在github上這個小項目:https://github.com/gerrytan/wsproblem

重現步驟:

1)克隆和構建項目(請確保您使用JDK 1.7和Maven的3.1)

$ git clone https://github.com/gerrytan/wsproblem.git 
$ cd wsproblem 
$ mvn jetty:run 

2)導航至http://localhost:8080,登錄使用任一擺錘/試驗或吉姆/測試

3)點擊「請求用戶特定的信息」。預期:僅顯示此用戶的「收到的郵件給我」旁邊顯示「hello {用戶名}」消息,實際:沒有收到任何郵件

+0

工作你一直在尋找convertAndSendToUser(用戶字符串,字符串目的地,T消息)?http://docs.spring.io/spring/docs/4.0.0.M3/javadoc-api /組織/春天框架/消息/ simp/SimpMessagingTemplate.html#convertAndSendToUser%28java.lang.String,%20java.lang.String,%20T%29 –

+0

是試過,但也沒有運氣 – gerrytan

+0

我一直在私人項目工作,這是我們使用的方法,它正在爲我們工作。我認爲一個潛在的問題可能是您訂閱了「/ user/reply」,並且您正在向「/ user/{username}/reply」發送消息。我認爲你應該刪除{username}部分並使用convertAndSendToUser(String user,String destination,T message)。 –

回答

23

啊我發現我的問題是什麼。首先,我沒有發送時的簡單代理註冊/user前綴

<websocket:simple-broker prefix="/topic,/user" /> 

然後我不需要額外的/user前綴:

convertAndSendToUser(principal.getName(), "/reply", reply); 

,Spring將自動預先準備"/user/" + principal.getName()到目的地,因此,它解析爲「/ user/bob/reply」。

這也意味着在JavaScript中,我不得不訂閱不同的地址,每個用戶

stompClient.subscribe('/user/' + userName + '/reply,...) 
+3

嗯......有沒有辦法避免設置userName客戶端?通過更改該值(例如通過使用其他用戶名),您將能夠看到其他用戶的消息。 – vdenotaris

+1

請參閱我的解決方案:http://stackoverflow.com/questions/25646671/check-auth-while-sending-a-message-to-a-specific-user-by-using-stomp-and-websock/25647822#25647822 – vdenotaris

+0

如何**訂閱**從用@ RequestMapping註解的方法回覆用戶,還有'@ MessageMapping'請參閱這裏[如何使用特定用戶名(userId)上的Sping Websocket集成進行訂閱+從方法中通過@請求映射?](https://stackoverflow.com/q/47628608/3425489) –

39

哦,client side no need to known about current user,服務器會爲你做的。

在服務器端,使用下面的方法來發送消息到用戶:

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

注意:使用queue,不topic,春天總是使用queuesendToUser

在客戶端

stompClient.subscribe("/user/queue/reply", handler); 

Exp lain

當任何websocket連接打開時,Spring會爲其分配一個session id(不是HttpSession,按連接分配)。當你的客戶端訂閱的頻道開始/user/,例如:/user/queue/reply,服務器實例將訂閱一個名爲queue/reply-user[session id]

隊列使用時發送消息給用戶,例如:用戶名是admin 你會寫simpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

Spring將確定哪個session id映射到用戶admin。例如:它發現兩個會話wsxedc123thnujm456,Spring會將其翻譯爲2個目的地queue/reply-userwsxedc123queue/reply-userthnujm456,並且它將帶有2個目的地的消息發送到您的消息代理。

消息代理接收消息並將其提供回服務器實例,該實例擁有與每個會話相對應的會話(WebSocket會話可由一個或多個服務器保存)。 Spring會將消息翻譯爲destination(例如:user/queue/reply)和session id(例如:wsxedc123)。然後,將消息發送到相應的Websocket session

+5

你能解釋你如何知道用戶名嗎?在你的例子中你說用戶名是'admin',你收到用戶名? – Jorj

+1

用戶名是在發起websocket連接 –

+0

時從'HttpSession'獲得的,請您提供更多關於如何設置用戶名的信息。無論如何,我可以發送用戶名上的提示信息? – Andres

2

我的,基於清阮文的最好解釋的解決方案,但除了我已經配置MessageBrokerRegistry:

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/queue/", "/topic/"); 
     ... 
    } 
    ... 
} 
2

我使用STOMP以及創建了一個示例的WebSocket項目。 我所注意到的是,

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

@Override 
public void configureMessageBroker(MessageBrokerRegistry config) { 
    config.enableSimpleBroker("/topic", "/queue");// including /user also works 
    config.setApplicationDestinationPrefixes("/app"); 
} 

@Override 
public void registerStompEndpoints(StompEndpointRegistry registry) { 
    registry.addEndpoint("/getfeeds").withSockJS(); 
} 

}

它的作品是否「/用戶」被包括在config.enableSimpleBroker(...

2

正是我做同樣的,它是不使用用戶

@Configuration 
@EnableWebSocketMessageBroker 
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 

    @Override 
    public void registerStompEndpoints(StompEndpointRegistry registry) { 
     registry.addEndpoint("/gs-guide-websocket").withSockJS(); 
    } 

    @Override 
    public void configureMessageBroker(MessageBrokerRegistry config) { 
     config.enableSimpleBroker("/topic" , "/queue"); 
     config.setApplicationDestinationPrefixes("/app"); 
    } 
} 
相關問題