У меня есть простое приложение spring с функциональностью websocket, и все работает до сих пор. Теперь я хочу отправить сообщение с моего сервера на конкретный клиент, используя аннотацию @SendToUser. Это дает мне ошибку "Игнорирование сообщения, доступной информации о принципе недоступности". Я понимаю, что у меня нет логина на моем сервере, поэтому каждый пользователь "анонимный" и не имеет принципала (на данный момент я не использую spring). Но каждый пользователь имеет идентификатор сеанса. Невозможно ли использовать идентификатор сеанса, чтобы различать пользователей? Как я могу достичь этого, чтобы мои пользователи получили принципал, который соответствует идентификатору сеанса?
Spring Веб-узлы @SendToUser без входа?
Ответ 1
Я думаю, что решение может состоять в том, чтобы избежать использования @SendToUser
и использовать raw SimpMessagingTemplate
и отправлять сообщения адресату, который вы контролируете для открытых сеансов.
Например, предполагая, что у вас есть определенный идентификатор для нового сеанса websocket, вы можете подписаться на очередь с этим идентификатором в имени очереди:
stomp.subscribe("/queue/chats" + "-" + mycustomidentifier, onmessage);
Теперь, на стороне слушателя Spring, вы можете направить свои ответы с помощью SimpMessagingTemplate
:
@Controller
public class MyController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@MessageMapping("/chats")
public void handleChat(@Payload ChatMessage message) {
this.simpMessagingTemplate.convertAndSend("/queue/chats-" + "mycustomidentifier", "[" + getTimestamp() + "]:" + message.getMessage());
}
....
Ответ 2
Используйте @SendToUser
и добавьте "/user/" перед очередью при подписке (только абонентская сторона). Мастер отдыха работает: -)
Вместо
Java Server: @SendTo("/topic/showResult")
и
JS Client: stompClient.subscribe('/topic/showResult', function(calResult){ ....
использовать:
Java Server: @SentToUser("/topic/showResult")
и
JS Client: stompClient.subscribe('/user/topic/showResult', function(calResult){ ....
Ответ 3
Основываясь на ответе Biju и используя сгенерированный идентификатор сеанса (спасибо, mariusz2108 в его ответ на аналогичный вопрос), вот что сработало для меня (на основе канонический пример из Spring)
Клиент SpringFramework:
private SimpMessagingTemplate template;
@Autowired
public GreetingController(SimpMessagingTemplate template) {
this.template = template;
}
@MessageMapping("/hello")
public void greeting(HelloMessage message, @Header("simpSessionId") String sessionId) throws Exception {
template.convertAndSend("/queue/greeting-"+sessionId, new Greeting("Hello, " + message.getName()));
}
Клиент JavaScript:
function connect() {
var socket = new SockJS('/gs-guide-websocket');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
var sessionId = /\/([^\/]+)\/websocket/.exec(socket._transport.url)[1];
console.log("connected, session id: " + sessionId);
stompClient.subscribe('/queue/greeting-'+sessionId, function (greeting) {
showGreeting(JSON.parse(greeting.body).content);
});
});
}
Вместо идентификатора сеанса Stomp вы можете использовать идентификатор сеанса веб-контейнера (например, JSESSIONID), но теперь этот файл cookie не доступен по умолчанию из JavaScript (для Tomcat) это более сложная перспектива.