Spring Stomp @SubscribeMapping для пункта назначения пользователя

Я пытаюсь получить уведомление, когда пользователь подписывается на пункт назначения пользователя stomp, используя аннотацию @SubscribeMapping. Моя идея состоит в том, чтобы отправить некоторые данные инициализации, когда они присоединятся.

Хотя я не могу заставить это работать:

Javascript:

stompClient.subscribe('/user/monitor', function(msg) {
            console.log(msg);    
        });

Сторона Java:

@SubscribeMapping("/monitor-user{clientId}")
public void init(@DestinationVariable("clientId") String clientId) {
    messagingTemplate.convertAndSend("/user/" + clientId + "/monitor", getOps());
}

Я пробовал много комбинаций сопоставления, таких как «/user/monitor-{clientId}», «/user/monitor» (удаление clientId), безуспешно.

Каково ожидаемое значение отображения, чтобы это вызывалось?

Благодарю вас!


person Luciano Greiner    schedule 22.07.2014    source источник
comment
Не могли бы вы перефразировать свой вопрос, пожалуйста? Какой вариант использования вы пытаетесь реализовать? Вариант использования 1: когда пользователь Алиса подписывается на пункт назначения /foobar, вы хотите, чтобы сообщение было отправлено в тему /monitor, специальную тему для целей мониторинга, которая получает сообщение каждый раз, когда пользователь подписывается на /foobar. Вариант использования 2: вы хотите сразу отправить данные инициализации Алисе, когда она подпишется на /foobar.   -  person Brian Clozel    schedule 23.07.2014


Ответы (1)


Поскольку клиент подписывается на очередь «/user/monitor», аннотация сервера @SubscribeMapping должна быть «/user/monitor», а не «/user/monitor{something}».

Сервер может понять, что такое клиент, в зависимости от вашей схемы аутентификации. Если вы используете веб-сокет sockjs, вы можете использовать HTTP-аутентификацию и, следовательно, использовать Spring Security и добавить параметр «Principal» в свою функцию, которая будет содержать информацию о пользователе:

@SubscribeMapping("/monitor")
public void init(Principal p) {
    String user = p.getName();
    messagingTemplate.convertAndSendToUser(user, "/monitor", getOps());
}

Если вы не используете HTTP-аутентификацию, вы можете отправить серверу информацию о пользователе, например, добавив собственный заголовок STOMP, к которому можно получить доступ с сервера с помощью SimpMessageHeaderAccessor:

@SubscribeMapping("/monitor")
public void init(SimpMessageHeaderAccessor accessor) {
    String user = accessor.getFirstNativeHeader("userid");
    messagingTemplate.convertAndSendToUser(user, "/monitor", getOps());
}

Другим способом может быть подписка на другое имя очереди, которое содержит информацию о пользователе (и это, возможно, было вашим предложением). Клиент должен использовать код, похожий на:

stompClient.subscribe('/topic/byUser/'+userId, function(msg) {
    console.log(msg);    
});

чтобы сервер мог получить к нему доступ следующим образом:

@SubscribeMapping("/byUser/{userId}")
public void init(@DestinationVariable String userId) {
    messagingTemplate.convertAndSendToUser(userId, "/monitor", getOps());
}

но в этом случае имейте в виду, что эта очередь является общедоступной, и, следовательно, другие клиенты могут получить доступ к своим сообщениям, если они знают имена других клиентов.

person Alessandro Polverini    schedule 28.07.2014
comment
Во втором примере кода метод convertAndSendToUser() преобразует вызов в /user/{userId}/monitor. Spring знает, как найти соединение по имени участника, но как он найдет соединение из пользовательского заголовка, о котором он никогда не знал? - person Joffrey; 20.12.2016