복붙노트

[SPRING] Spring @SubscribeMapping은 실제로 어떤 주제에 클라이언트를 구독합니까?

SPRING

Spring @SubscribeMapping은 실제로 어떤 주제에 클라이언트를 구독합니까?

Spring Websocket을 STOMP, Simple Message Broker와 함께 사용하고 있습니다. 내 @Controller에서는 메소드 레벨 @SubscribeMapping을 사용하는데, 이는 클라이언트가 주제에 메시지를 받아야 나중에 클라이언트가 그 주제의 메시지를 수신하게 할 수 있습니다. 고객이 "채팅"이라는 주제에 가입한다고 가정 해 보겠습니다.

stompClient.subscribe ( '/ app / chat', ...);

클라이언트가 "/ topic / chat"대신 "/ app / chat"을 구독하면이 구독은 @SubscribeMapping을 사용하여 매핑되는 메서드로 이동합니다.

@SubscribeMapping("/chat")
public List getChatInit() {
    return Chat.getUsers();
}

다음은 Spring ref. 말한다 :

좋아, 이것은 내가 원했던 것이지만, 부분적으로는 !! 가입 후 init-data를 보내면됩니다. 그러나 구독하는 것은 어떨까요? 여기서 일어난 일은 서비스와 같은 요청 - 응답 일뿐입니다. 구독이 막 사용됩니다. 이 경우에 나를 명확히하십시오.

여기에 고객이 어디서나 구독하지 않는다면 나는 이것을 "구독"이라고 부르는 이유를 궁금해합니다. 클라이언트는 하나의 메시지 만 수신하고 이후의 메시지는 수신하지 않기 때문입니다.

편집하다:

구독이 실현되었는지 확인하려면 다음과 같이 시도해보십시오.

서버 측:

구성 :

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

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

제어 장치:

@Controller
public class GreetingController {

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    public Greeting greeting(HelloMessage message) throws Exception {
        System.out.println("inside greeting");
        return new Greeting("Hello, " + message.getName() + "!");
    }

    @SubscribeMapping("/topic/greetings")
    public Greeting try1() {
        System.out.println("inside TRY 1");
        return new Greeting("Hello, " + "TRY 1" + "!");
    }
}

고객 입장에서:

...
    stompClient.subscribe('/topic/greetings', function(greeting){
                        console.log('RECEIVED !!!');
                    });
    stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
...

내가 무엇을하고 싶니?

결과 :

그래서 제가 가지고있는 것은 제가 원했던 것 중 1 개 또는 2 개입니다 만,이 2 개는 함께 아닙니다.

해결법

  1. ==============================

    1.(강조 광산)

    (강조 광산)

    여기서는 Spring 프레임 워크 문서가 들어오는 SUBSCRIBE 메시지가 아니라 응답 메시지에 어떤 일이 발생하는지 설명합니다.

    그래서 귀하의 질문에 대답 :

    SimpleMessageBroker를 사용하면 메시지 브로커 구현이 애플리케이션 인스턴스에 존재합니다. 구독 등록은 DefaultSubscriptionRegistry에 의해 관리됩니다. 메시지를받을 때 SimpleBrokerMessageHandler는 SUBSCRIPTION 메시지를 처리하고 구독을 등록합니다 (여기 구현 참조).

    RabbitMQ와 같은 "실제"메시지 브로커를 사용하면 메시지를 브로커에 전달하는 Stomp 브로커 릴레이를 구성했습니다. 이 경우 SUBSCRIBE 메시지는 브로커에게 전달되어 구독 관리를 담당합니다 (여기 구현 참조).

    STOMP 메시지 흐름에 대한 참조 문서를 살펴보면 다음과 같이 표시됩니다.

    그래서 여기 / topic / hello는 브로커 대상입니다. 거기서 보낸 메시지는 브로커로 직접 전달됩니다. / app / hello는 응용 프로그램 대상이지만 /SendTo가 그렇지 않으면 / topic / hello로 보낼 메시지를 생성해야합니다.

    이제 업데이트 된 질문은 어떻게 든 다른 것입니다. 더 정확한 사용 사례가 없으면이를 해결하는 데 가장 적합한 패턴을 말하기가 어렵습니다. 다음은 몇 가지 예입니다.

    좋은 예제가 필요하다면, 실제 사용 사례가있는 Spring websocket 기능의 로그를 보여주는이 채팅 애플리케이션을 확인하십시오.

  2. ==============================

    2.그래서 둘 다 갖는 :

    그래서 둘 다 갖는 :

    당신은 (뿐만 아니라) 경험으로 작동하지 않습니다.

    당신의 상황을 해결하는 방법은 (내가했던 것처럼) :

    구독 이벤트 처리기 :

    @Override
      public void onApplicationEvent(SessionSubscribeEvent event) {
          Message<byte[]> message = event.getMessage();
          StompHeaderAccessor accessor = StompHeaderAccessor.wrap(message);
          StompCommand command = accessor.getCommand();
          if (command.equals(StompCommand.SUBSCRIBE)) {
              String sessionId = accessor.getSessionId();
              String stompSubscriptionId = accessor.getSubscriptionId();
              String destination = accessor.getDestination();
              // Handle subscription event here
              // e.g. send welcome message to *destination*
           }
      }
    
  3. ==============================

    3.나는 같은 문제에 직면했고 마지막으로 해결책으로 바꿨다. 클라이언트에서 / topic과 / app을 구독했을 때 / app-bound에서 모든 채팅 기록을 다운로드 할 때까지 / topic 처리기에서받은 모든 것을 버퍼링했다. SubscribeMapping이 반환됩니다. 그런 다음 모든 최근 채팅 항목을 / topic에 수신 된 항목과 병합합니다. 제 경우에는 중복 될 수 있습니다.

    나는 같은 문제에 직면했고 마지막으로 해결책으로 바꿨다. 클라이언트에서 / topic과 / app을 구독했을 때 / app-bound에서 모든 채팅 기록을 다운로드 할 때까지 / topic 처리기에서받은 모든 것을 버퍼링했다. SubscribeMapping이 반환됩니다. 그런 다음 모든 최근 채팅 항목을 / topic에 수신 된 항목과 병합합니다. 제 경우에는 중복 될 수 있습니다.

    또 다른 작업 방식은

    registry.enableSimpleBroker("/app", "/topic");
    registry.setApplicationDestinationPrefixes("/app", "/topic");
    

    분명히, 완벽하지 않습니다. 그러나 일 :)

  4. from https://stackoverflow.com/questions/29085791/does-spring-subscribemapping-really-subscribe-the-client-to-some-topic by cc-by-sa and MIT license