gpt4 book ai didi

java - Spring WebSocket @SendToSession : send message to specific session

转载 作者:IT老高 更新时间:2023-10-28 13:05:37 26 4
gpt4 key购买 nike

是否可以向特定 session 发送消息?

我在客户端和 Spring servlet 之间有一个未经身份验证的 websocket。当异步作业结束时,我需要向特定连接发送未经请求的消息。

@Controller
public class WebsocketTest {


@Autowired
public SimpMessageSendingOperations messagingTemplate;

ExecutorService executor = Executors.newSingleThreadExecutor();

@MessageMapping("/start")
public void start(SimpMessageHeaderAccessor accessor) throws Exception {
String applicantId=accessor.getSessionId();
executor.submit(() -> {
//... slow job
jobEnd(applicantId);
});
}

public void jobEnd(String sessionId){
messagingTemplate.convertAndSend("/queue/jobend"); //how to send only to that session?
}
}

正如您在这段代码中看到的,客户端可以启动一个异步作业,当它完成时,它需要结束消息。显然,我只需要向申请人发送消息,而不是向所有人广播。最好有一个 @SendToSession 注释或 messagingTemplate.convertAndSendToSession 方法。

更新

我试过了:

messagingTemplate.convertAndSend("/queue/jobend", true, Collections.singletonMap(SimpMessageHeaderAccessor.SESSION_ID_HEADER, sessionId));

但这会广播到所有 session ,而不仅仅是指定的 session 。

更新 2

使用 convertAndSendToUser() 方法进行测试。这个测试是官方 Spring 教程的 hack:https://spring.io/guides/gs/messaging-stomp-websocket/

这是服务器代码:

@Controller
public class WebsocketTest {

@PostConstruct
public void init(){
ScheduledExecutorService statusTimerExecutor=Executors.newSingleThreadScheduledExecutor();
statusTimerExecutor.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"));
}
}, 5000,5000, TimeUnit.MILLISECONDS);
}

@Autowired
public SimpMessageSendingOperations messagingTemplate;
}

这是客户端代码:

function connect() {
var socket = new WebSocket('ws://localhost:8080/hello');
stompClient = Stomp.over(socket);
stompClient.connect({}, function(frame) {
setConnected(true);
console.log('Connected: ' + frame);
stompClient.subscribe('/user/queue/test', function(greeting){
console.log(JSON.parse(greeting.body));
});
});
}

不幸的是,客户端没有像预期的那样每 5000 毫秒收到一次 session 回复。我确定“1”是连接的第二个客户端的有效 sessionId,因为我在 Debug模式下看到它 SimpMessageHeaderAccessor.getSessionId()

背景场景

我想为远程作业创建一个进度条,客户端向服务器请求异步作业,它通过从服务器发送的 websocket 消息检查其进度。这不是文件上传,而是远程计算,因此只有服务器知道每个作业的进度。我需要向特定 session 发送消息,因为每个作业都是由 session 启动的。客户要求进行远程计算服务器启动此工作,并针对每个工作步骤向申请人客户端回复其工作进度状态。客户端获取有关其工作的消息并建立一个进度/状态栏。这就是我需要每个 session 消息的原因。我也可以使用每个用户的消息,但是 Spring 不提供每个用户主动提供的消息。 (Cannot send user message with Spring Websocket)

工作解决方案

 __      __ ___   ___  _  __ ___  _  _   ___      ___   ___   _    _   _  _____  ___  ___   _  _ 
\ \ / // _ \ | _ \| |/ /|_ _|| \| | / __| / __| / _ \ | | | | | ||_ _||_ _|/ _ \ | \| |
\ \/\/ /| (_) || /| ' < | | | .` || (_ | \__ \| (_) || |__| |_| | | | | || (_) || .` |
\_/\_/ \___/ |_|_\|_|\_\|___||_|\_| \___| |___/ \___/ |____|\___/ |_| |___|\___/ |_|\_|

从 UPDATE2 解决方案开始,我必须使用最后一个参数 (MessageHeaders) 完成 convertAndSendToUser 方法:

messagingTemplate.convertAndSendToUser("1","/queue/test", new Return("test"), createHeaders("1"));

其中 createHeaders() 是这个方法:

private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);
return headerAccessor.getMessageHeaders();
}

最佳答案

无需创建特定的目的地,从 Spring 4.1 开始,它已经开箱即用(参见 SPR-11309)。

鉴于用户订阅了 /user/queue/something 队列,您可以通过以下方式向单个 session 发送消息:

作为 stated in the SimpMessageSendingOperations Javadoc ,因为您的用户名实际上是一个 sessionId,所以您也必须将其设置为 header ,否则 DefaultUserDestinationResolver 将无法路由消息并将其丢弃。

SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor
.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
headerAccessor.setLeaveMutable(true);

messagingTemplate.convertAndSendToUser(sessionId,"/queue/something", payload,
headerAccessor.getMessageHeaders());

您不需要为此对用户进行身份验证。

关于java - Spring WebSocket @SendToSession : send message to specific session,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34929578/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com