Spring boot stomp 多次发送 RECEIPT 帧
Spring boot stomp sends RECEIPT frame multiple times
我正在 Spring Boot 上使用 Stomp 和 Rabbitmq 开发一个聊天应用程序。
当客户端向服务器发送消息时(Spring 启动),服务器将消息保存到数据库,然后将消息发送给它的接收者。
我想做的是在客户发送消息时发送一个 RECEIPT
帧 message-id
给他们,让他们知道他们的消息已保存到数据库中。
我可以从 ExecutorChannelInterceptor
class 的 afterMessageHandled()
发送 RECEIPT
帧。但它会多次发送相同的 RECEIPT
帧,例如三次。
因此,对于一条消息,客户端会收到 3 次相同的 RECEIPT
帧。
这是我的 ChannelInterceptor
,它将消息保存到 presend()
中的数据库
public class StompChannelInterceptor implements ChannelInterceptor {
@Autowired
private ChatService chatService;
@Autowired
private CompositeMessageConverter compositeMessageConverter;
@Override
public Message<?> preSend(Message<?> message, @NonNull MessageChannel channel) {
MessageHeaders messageHeaders = message.getHeaders();
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
StompCommand stompCommand = stompHeaderAccessor.getCommand();
if (StompCommand.SUBSCRIBE.equals(stompCommand)) {
//validate subscribe
} else if (StompCommand.SEND.equals(stompCommand)) {
System.out.println("presend!!!!!!!!!!!!!!!!!!!");
ChatMessageDTO chatMessageDTO =
(ChatMessageDTO) compositeMessageConverter.fromMessage(message, ChatMessageDTO.class);
chatService.validateAndSaveMessage(chatMessageDTO);
}
return message;
}
}
这是我的 MessageMapping
处理传入消息的函数
@MessageMapping("/chat/send")
public void send(@Payload ChatMessageDTO chatMessageDTO, MessageHeaders messageHeaders) {
System.out.println("send!!!!!!!!!!!!!!!!!!!!!!!!!");
simpMessagingTemplate.convertAndSend(queue, chatMessageDTO);
}
最后,这是我的 ExecutorChannelInterceptor
,它在 afterMessageHandled()
中发送 RECEIPT
帧
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(chatChannelInterceptor());
registration.interceptors(new ExecutorChannelInterceptor() {
@Override
public void afterMessageHandled(Message<?> inMessage,
MessageChannel inChannel, MessageHandler handler, Exception ex) {
StompHeaderAccessor inAccessor = StompHeaderAccessor.wrap(inMessage);
if (StompCommand.SEND.equals(inAccessor.getCommand())) {
System.out.println("afterMessageHandled");
if (outChannel != null) {
StompHeaderAccessor outAccessor = StompHeaderAccessor.create(StompCommand.RECEIPT);
outAccessor.setSessionId(inAccessor.getSessionId());
outAccessor.setReceiptId(receipt);
outAccessor.setLeaveMutable(true);
outAccessor.setMessageId(inAccessor.getMessageId());
Message<byte[]> outMessage =
MessageBuilder.createMessage(new byte[0], outAccessor.getMessageHeaders());
outChannel.send(outMessage);
}
}
}
});
}
如果我运行这段代码,我得到了这个日志,表明afterMessageHandled()
被调用了3次
presend!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
send!!!!!!!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
所以,问题是
有什么方法可以在 presend()
之后 只向客户发送一次 RECEIPT 帧,因为我想发送 RECEIPT确认消息已保存到数据库后的帧,发生在 presend()
?
是否可以在 presend()
中更改负载或 headers?
我发现每次调用 afterHanldedMessage() 都带有不同的处理程序。所以你可以根据不同的处理程序做你想做的事。你可能想做 If(handler instanceof SomeHandlerClass).
我正在 Spring Boot 上使用 Stomp 和 Rabbitmq 开发一个聊天应用程序。
当客户端向服务器发送消息时(Spring 启动),服务器将消息保存到数据库,然后将消息发送给它的接收者。
我想做的是在客户发送消息时发送一个 RECEIPT
帧 message-id
给他们,让他们知道他们的消息已保存到数据库中。
我可以从 ExecutorChannelInterceptor
class 的 afterMessageHandled()
发送 RECEIPT
帧。但它会多次发送相同的 RECEIPT
帧,例如三次。
因此,对于一条消息,客户端会收到 3 次相同的 RECEIPT
帧。
这是我的 ChannelInterceptor
,它将消息保存到 presend()
public class StompChannelInterceptor implements ChannelInterceptor {
@Autowired
private ChatService chatService;
@Autowired
private CompositeMessageConverter compositeMessageConverter;
@Override
public Message<?> preSend(Message<?> message, @NonNull MessageChannel channel) {
MessageHeaders messageHeaders = message.getHeaders();
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
StompCommand stompCommand = stompHeaderAccessor.getCommand();
if (StompCommand.SUBSCRIBE.equals(stompCommand)) {
//validate subscribe
} else if (StompCommand.SEND.equals(stompCommand)) {
System.out.println("presend!!!!!!!!!!!!!!!!!!!");
ChatMessageDTO chatMessageDTO =
(ChatMessageDTO) compositeMessageConverter.fromMessage(message, ChatMessageDTO.class);
chatService.validateAndSaveMessage(chatMessageDTO);
}
return message;
}
}
这是我的 MessageMapping
处理传入消息的函数
@MessageMapping("/chat/send")
public void send(@Payload ChatMessageDTO chatMessageDTO, MessageHeaders messageHeaders) {
System.out.println("send!!!!!!!!!!!!!!!!!!!!!!!!!");
simpMessagingTemplate.convertAndSend(queue, chatMessageDTO);
}
最后,这是我的 ExecutorChannelInterceptor
,它在 afterMessageHandled()
RECEIPT
帧
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(chatChannelInterceptor());
registration.interceptors(new ExecutorChannelInterceptor() {
@Override
public void afterMessageHandled(Message<?> inMessage,
MessageChannel inChannel, MessageHandler handler, Exception ex) {
StompHeaderAccessor inAccessor = StompHeaderAccessor.wrap(inMessage);
if (StompCommand.SEND.equals(inAccessor.getCommand())) {
System.out.println("afterMessageHandled");
if (outChannel != null) {
StompHeaderAccessor outAccessor = StompHeaderAccessor.create(StompCommand.RECEIPT);
outAccessor.setSessionId(inAccessor.getSessionId());
outAccessor.setReceiptId(receipt);
outAccessor.setLeaveMutable(true);
outAccessor.setMessageId(inAccessor.getMessageId());
Message<byte[]> outMessage =
MessageBuilder.createMessage(new byte[0], outAccessor.getMessageHeaders());
outChannel.send(outMessage);
}
}
}
});
}
如果我运行这段代码,我得到了这个日志,表明afterMessageHandled()
被调用了3次
presend!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
send!!!!!!!!!!!!!!!!!!!!!!!!!
afterMessageHandled!!!!!!!!!!!!!!!!!!!!!
所以,问题是
有什么方法可以在
presend()
之后 只向客户发送一次 RECEIPT 帧,因为我想发送 RECEIPT确认消息已保存到数据库后的帧,发生在presend()
?是否可以在
presend()
中更改负载或 headers?
我发现每次调用 afterHanldedMessage() 都带有不同的处理程序。所以你可以根据不同的处理程序做你想做的事。你可能想做 If(handler instanceof SomeHandlerClass).