[java] Spring Websocket에서 특정 사용자에게 메시지 보내기

서버에서 특정 사용자에게만 웹 소켓 메시지를 보내는 방법은 무엇입니까?

내 webapp에는 스프링 보안 설정이 있으며 websocket을 사용합니다. 서버에서 특정 사용자에게만 메시지를 보내려고하는 까다로운 문제가 발생했습니다 .

매뉴얼 을 읽은 나의 이해는 우리가 할 수있는 서버에서 나온 것입니다.

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:8080bob / test 또는 jim / test를 사용하여 로그인합니다.

3) “사용자 별 메시지 요청”을 클릭합니다. 예상 : “안녕하세요 {username}”메시지가이 사용자에 대해서만 “나에게만 수신 됨”옆에 표시됨, 실제 : 아무것도 수신되지 않음



답변

아, client side no need to known about current user서버가 대신 해줄 것입니다.

서버 측에서 다음 방법을 사용하여 사용자에게 메시지를 보냅니다.

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

참고 : 사용 queue하지 않고 topic항상 사용 queue하는 SpringsendToUser

클라이언트 측

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

설명

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입니다. 예 : 그것은 두 개의 세션을 발견 wsxedc123하고 thnujm456봄이 목적지로 변환합니다, queue/reply-userwsxedc123그리고 queue/reply-userthnujm456, 그것은 당신의 메시지 브로커 2 개 목적지로 메시지를 보낼 수 있습니다.

메시지 브로커는 메시지를 수신하고 각 세션에 해당하는 세션을 보유하는 서버 인스턴스에 다시 제공합니다 (WebSocket 세션은 하나 이상의 서버에서 보유 할 수 있음). Spring은 메시지를 destination(예 🙂 user/queue/replysession id(예 :)로 번역합니다 wsxedc123. 그런 다음 해당 메시지를Websocket session


답변

아 내 문제가 뭔지 찾았 어. 먼저 /user간단한 브로커에 접두사를 등록하지 않았습니다.

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

그러면 /user보낼 때 추가 접두사 가 필요하지 않습니다 .

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

Spring은 자동으로 "/user/" + principal.getName()목적지 앞에 추가 되므로 “/ user / bob / reply”로 해석됩니다.

이것은 또한 자바 스크립트에서 사용자마다 다른 주소를 구독해야 함을 의미합니다.

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


답변

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

}

“/ user”가 config.enableSimpleBroker (…


답변

Thanh Nguyen Van의 최선의 설명을 기반으로 한 내 솔루션이지만 MessageBrokerRegistry를 구성했습니다.

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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


답변

정확히 나는 똑같이했고 사용자를 사용하지 않고 작동합니다.

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


답변