स्प्रिंग वेबसोकेट पर विशिष्ट उपयोगकर्ता को संदेश भेजना


85

केवल विशिष्ट उपयोगकर्ता के लिए सर्वर से वेबसैट संदेश कैसे भेजें?

मेरे वेबएप में स्प्रिंग सिक्योरिटी सेटअप है और वेबसोकेट का उपयोग करता है। मैं मुश्किल समस्या का सामना कर रहा हूँ सर्वर से विशिष्ट उपयोगकर्ता के लिए संदेश भेजने की कोशिश कर रहा है ।

मैनुअल पढ़ने से मेरी समझ उस सर्वर से है जिसे हम कर सकते हैं

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

और ग्राहक पक्ष पर:

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

लेकिन मुझे कभी भी सब्सक्रिप्शन कॉलबैक नहीं मिला। मैंने कई अलग-अलग रास्ते आजमाए लेकिन कोई किस्मत नहीं।

अगर मैं इसे / विषय / उत्तर पर भेजता हूं तो यह काम करता है लेकिन अन्य सभी जुड़े हुए उपयोगकर्ता इसे प्राप्त करेंगे।

समस्या को समझने के लिए मैंने इस छोटे से प्रोजेक्ट को github पर बनाया है: https://github.com/gerrytan/wsproblem

प्रजनन करने कि प्रक्रिया:

1) क्लोन और प्रोजेक्ट का निर्माण (सुनिश्चित करें कि आप jdk 1.7 और मावेन 3.1 का उपयोग कर रहे हैं)

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

2) नेविगेट करें http://localhost:8080, या तो बॉब / टेस्ट या jim / test का उपयोग करके लॉगिन करें

3) "अनुरोध उपयोगकर्ता विशिष्ट संदेश" पर क्लिक करें। अपेक्षित: केवल इस उपयोगकर्ता के लिए "प्राप्त संदेश केवल मेरे लिए" के बगल में एक संदेश "हैलो {उपयोगकर्ता नाम}" प्रदर्शित होता है, वास्तविक: कुछ भी प्राप्त नहीं होता है


क्या आप ConvertAndSendToUser (स्ट्रिंग उपयोगकर्ता, स्ट्रिंग गंतव्य, टी संदेश) देख रहे हैं? docs.spring.io/spring/docs/4.0.0.M3/javadoc-api/org/…
विक्टर के।

हाँ, वह भी कोशिश की लेकिन कोई भाग्य नहीं
गेरेटन

मैं निजी परियोजना पर काम कर रहा हूं और यह वह विधि है जिसका हम उपयोग करते हैं और यह हमारे लिए काम कर रही है। मुझे लगता है कि एक संभावित समस्या यह हो सकती है कि आप "/ उपयोगकर्ता / उत्तर" की सदस्यता लेते हैं और आप "/ उपयोगकर्ता / {उपयोगकर्ता नाम} / उत्तर" के लिए संदेश भेज रहे हैं। मुझे लगता है कि आपको {उपयोगकर्ता नाम} भाग को हटा देना चाहिए और ConvertAndSendToUser (स्ट्रिंग उपयोगकर्ता, स्ट्रिंग गंतव्य, टी संदेश) का उपयोग करना चाहिए।
विक्टर के।

धन्यवाद, लेकिन मैंने कोशिश की simpMessagingTemplate.convertAndSendToUser(principal.getName(), "/user/reply", reply);और जब संदेश सर्वर से भेजा जाता है तो वह इस अपवाद को फेंक देता हैjava.lang.IllegalArgumentException: Expected destination pattern "/principal/{userId}/**"
गेरेटन

@ViktorK। सही है, और आप सही समाधान के काफी करीब थे। क्लाइंट की ओर से आपकी सदस्यता सही थी, आपको बस कोशिश करनी थी:convertAndSendToUser(principal.getName(), "/reply", reply);
टिप-एसएआर

जवाबों:


81

ओह, client side no need to known about current userसर्वर, आपके लिए वही करेगा।

सर्वर की ओर, उपयोगकर्ता को संदेश भेजने के लिए निम्नलिखित तरीके का उपयोग कर:

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

नोट: उपयोग करना queue, नहीं topic, वसंत हमेशा उपयोग queueकरनाsendToUser

क्लाइंट की तरफ

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

समझाना

जब कोई वेबसैट कनेक्शन खुला होता है, तो स्प्रिंग इसे असाइन करेगा session id(नहीं HttpSession, प्रति कनेक्शन असाइन करें)। और जब आपका क्लाइंट किसी चैनल के साथ शुरुआत करता है /user/, जैसे:, /user/queue/replyतो आपके सर्वर का उदाहरण नामित कतार की सदस्यता लेगाqueue/reply-user[session id]

जब उपयोगकर्ता को संदेश भेजें का उपयोग करें, जैसे: उपयोगकर्ता नाम है admin आप लिखेंगेsimpMessagingTemplate.convertAndSendToUser("admin", "/queue/reply", message);

स्प्रिंग यह निर्धारित करेगा कि session idउपयोगकर्ता को कौन सा मैप किया गया है admin। उदा: यह दो सत्रों में पाया गया wsxedc123और thnujm456, स्प्रिंग इसे 2 गंतव्य पर अनुवाद करेगा queue/reply-userwsxedc123और queue/reply-userthnujm456, यह आपके संदेश दलाल को आपके गंतव्य तक 2 संदेश भेजेगा।

संदेश ब्रोकर संदेशों को प्राप्त करता है और इसे आपके सर्वर उदाहरण पर वापस प्रदान करता है जो प्रत्येक सत्र के अनुरूप सत्र (WebSocket सत्रों को एक या अधिक सर्वर द्वारा पकड़ सकता है)। वसंत संदेश को destination(जैसे:) user/queue/replyऔर session id(जैसे :) अनुवाद करेगा wsxedc123। फिर, यह संदेश को संबंधित पर भेजता हैWebsocket session


7
क्या आप कृपया बता सकते हैं कि आप उपयोगकर्ता नाम कैसे जानते हैं? आपके उदाहरण में आपने कहा कि उपयोगकर्ता नाम 'व्यवस्थापक' है, आप उपयोगकर्ता से उपयोगकर्ता नाम प्राप्त करते हैं?
जोर्ज

1
उपयोगकर्ता नाम HttpSessionवेबस्केट कनेक्शन आरंभ करने से प्राप्त किया गया था
थान गुयेन वान

1
कृपया आप उपयोगकर्ता नाम सेट करने के बारे में अधिक जानकारी दे सकते हैं? वैसे भी मैं उपयोगकर्ता नाम संदेश भेज सकते हैं?
एंड्रेस

1
@ भंडार: आप विस्तार कर सकते हैं DefaultHandshakeHandlerऔर विधि को ओवरराइड कर सकते हैंdetermineUser
थान गुयेन वान

1
आपकी व्याख्या महान काम करती है। हालाँकि queue/reply-user[session id]आधिकारिक दस्तावेज़ में हिस्सा कहाँ है ?
hbrls

35

आह मैंने पाया कि मेरी समस्या क्या थी। पहले मैंने /userसाधारण दलाल पर उपसर्ग रजिस्टर नहीं किया था

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

/userभेजने के दौरान मुझे अतिरिक्त उपसर्ग की आवश्यकता नहीं है :

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

स्प्रिंग स्वचालित रूप "/user/" + principal.getName()से गंतव्य तक पहुंच जाएगा , इसलिए यह "/ उपयोगकर्ता / बॉब / उत्तर" में हल हो जाता है।

यह भी जावास्क्रिप्ट में इसका मतलब है कि मुझे प्रति उपयोगकर्ता अलग-अलग पते की सदस्यता लेनी थी

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

3
मम्म ... क्या उपयोगकर्ता नाम क्लाइंट-साइड सेटअप करने से बचने का कोई तरीका है? उस मान को बदलकर (उदाहरण के लिए किसी अन्य उपयोगकर्ता नाम का उपयोग करके), आप दूसरों के संदेश देख पाएंगे।
vdenotaris

2
मेरा समाधान देखें: stackoverflow.com/questions/25646671/…
vdenotaris

के साथ एनोटेट किए गए तरीकों से उपयोगकर्ता को जवाब देने के लिए सदस्यता लें@RequestMapping और @MessageMappingयहां यह भी देखें कि विशिष्ट उपयोगकर्तानाम (userId) पर स्पिंग वेबसोकेट एकीकरण का उपयोग करके सदस्यता कैसे लें + विधि से सूचनाएं प्राप्त करें @RequestMapping?
शांताराम तुपे

अरे मेरे दोस्त क्या आप मुझे यह बता सकते हैं? वैसे भी यह "उपयोगकर्ता" क्या है? मैं स्प्रिंग सिक्योरिटी का उपयोग कर रहा हूं और मेरे उपयोगकर्ता (उपयोगकर्ता नाम) ईमेल पते हैं। जब प्रत्येक उपयोगकर्ता लॉग इन करता है तो वह स्प्रिंग सुरक्षा पर अपना JWT टोकन प्राप्त करता है।
फ्रांसिस्को सूजा

मुझे आपके सवालों के जवाब में आने से घंटों पहले, समान समस्याओं का सामना करना पड़ा। केवल आपकी खोज से मुझे मदद मिली। बहुत बहुत धन्यवाद!!
नवनीत

3

मैंने STOMP के साथ ही एक नमूना वेबसोकेट प्रोजेक्ट बनाया। मैं जो देख रहा हूं वह यह है

@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

थान गुयेन वान की सबसे अच्छी व्याख्या के आधार पर मेरा समाधान, लेकिन इसके अलावा मैंने MessageBrokerRegistry को कॉन्फ़िगर किया है:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

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");
    }
}

अरे, आप कभी इसका उपयोग कहां करते हैं /app? कौनसे मामलेमें?
फ्रांसिस्को सूजा
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.