我希望你们一切都好。我正在学习在 Spring boot 中使用来自 Nodejs 中的 SocketIo 的 Websockets。我正在使用
Stomp client
和 SimpMessageSendingOperations messagingTemplate
来回发送消息。
问题是,对于某些代码段,我想排除发送者接收消息。
@SendTo
可以很好地向所有订阅者(包括发件人)发送消息。
经过一番谷歌搜索后,我找到了
messagingTemplate
并尝试使用它但没有成功。
后端发送消息,前端却始终没有收到。
下面是我的代码。我已经尽可能简化了,但我仍然无法使用
messagingTemplate.convertAndSendToUser
接收任何消息。
这是 Web 配置文件:
package com.example.demo.SocketClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer {
SimpUserRegistry simpUserRegistry;
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
registry.setUserDestinationPrefix("/user");
}
这是前端:
let sessionId;
let getRandom = integer => Math.floor(Math.random()*integer)
let socket = new SockJS('http://localhost:8080/ws',[],{sessionId:8})
var stompClient = Stomp.over(socket)
let username = "john"
stompClient.connect({},stompClientOnConnected, onError)
function stompClientOnConnected(frame){
stompClient.subscribe(`user/john/topic/ConnectionTest`, onUserMoved)
sessionId = getRandom(10000000).toString()
setTimeout( () => stompClient.send("/app/draw.ConnectionTest",{},JSON.stringify({ username: 'john' })), 3000)
function onUserMoved (data){ console.log("Data after user moved: ",data) }
}
function onError(err){
console.log("thats an error :", err)
}
这是控制器:
package com.example.demo.SocketClass;
import com.example.demo.DrawAppUser.DrawAppSession;
import com.example.demo.SocketData.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.messaging.simp.SimpMessageType;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.stereotype.Controller;
import java.util.ArrayList;
import java.util.Map;
@Controller
public class SocketController {
private final SimpMessageSendingOperations messagingTemplate;
@Autowired
public SocketController(SimpMessageSendingOperations messagingTemplate){
this.messagingTemplate= messagingTemplate;
}
@MessageMapping("/draw.ConnectionTest")
public void userConnectedEvent(SimpMessageHeaderAccessor accessor, @Payload String load) {
String simpSessionId = accessor.getSessionId();
System.out.println("Received userConnectedEvent. Session ID: " + simpSessionId);
String message = "Your session ID is: " + simpSessionId;
SimpMessageHeaderAccessor responseAccessor = StompHeaderAccessor.create(SimpMessageType.MESSAGE);
responseAccessor.setSessionId(simpSessionId);
System.out.println("Sending message: " + message);
messagingTemplate.convertAndSendToUser("john", "/topic/ConnectionTest", message, responseAccessor.getMessageHeaders());
}
我尝试使用 sessionId 但没有运气
@MessageMapping("/draw.ConnectionTest")
public void userConnectedEvent(SimpMessageHeaderAccessor accessor, @Payload String load) {
String simpSessionId = accessor.getSessionId();
System.out.println("Received userConnectedEvent. Session ID: " + simpSessionId);
String message = "Your session ID is: " + simpSessionId;
SimpMessageHeaderAccessor responseAccessor = StompHeaderAccessor.create(SimpMessageType.MESSAGE);
responseAccessor.setSessionId(simpSessionId);
System.out.println("Sending message: " + message);
//
messagingTemplate.convertAndSendToUser(simpSessionId, "/topic/ConnectionTest", message, responseAccessor.getMessageHeaders());
}
我尝试在函数的开头和结尾处打印。两者都运行正常,但前端没有收到消息。
这是我刷新页面后从浏览器控制台当前获得的信息:
Opening Web Socket...
stomp.min.js:8 Web Socket Opened...
stomp.min.js:8 >>> CONNECT
accept-version:1.1,1.0
heart-beat:10000,10000
<<< CONNECTED
version:1.1
heart-beat:0,0
connected to server undefined
>>> SUBSCRIBE
id:sub-0
destination:user/john/topic/ConnectionTest
connected!!
mytest.js:16 this is frame:
n {command: 'CONNECTED', headers: {…}, body: ''}
>>> SEND
destination:/app/draw.ConnectionTest
content-length:19
{"username":"john"}
我与chatgbt3.5进行了长时间的对话,它基本上放弃了,并告诉我代码应该可以工作,并且我应该检查我的防火墙。
有什么想法吗?
在脚本中使用正斜杠 (
/
) 为目的地添加前缀。在你的情况下,它必须是stompClient.subscribe('/user/john/topic/ConnectionTest", onUserMoved)
并在您的 spring-boot WebSocket 配置文件中,还将
/user
注册为 simpleBroker,如下所示
registry.enableSimpleBroker("/topic", "/user");
SimpMessagingTemplate#convertAndSendToUser
将按如下方式构造目的地 userDestinationPrefix + user + destination
就您而言,您已将 userDestinationPrefix 注册为“/user”。所以convertAndSendToUser会将消息发送到目的地/user/<username>/destination