[英]Spring Websocket STOMP: send RECEIPT frames
我有一個基於Spring的Websocket-stomp服務器及其SimpleBroker實現(不使用外部代理)。
我想啟用STOMP RECEIPT消息。
如何配置我的代碼自動發送這些?
在針對STOMP協議的Spring Integration測試中,我們有以下代碼:
//SimpleBrokerMessageHandler doesn't support RECEIPT frame, hence we emulate it this way
@Bean
public ApplicationListener<SessionSubscribeEvent> webSocketEventListener(
final AbstractSubscribableChannel clientOutboundChannel) {
return event -> {
Message<byte[]> message = event.getMessage();
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
if (stompHeaderAccessor.getReceipt() != null) {
stompHeaderAccessor.setHeader("stompCommand", StompCommand.RECEIPT);
stompHeaderAccessor.setReceiptId(stompHeaderAccessor.getReceipt());
clientOutboundChannel.send(
MessageBuilder.createMessage(new byte[0], stompHeaderAccessor.getMessageHeaders()));
}
};
}
類似於Artem Bilan的帖子的解決方案,使用分離的類來實現監聽器。
@Component
public class SubscribeListener implements ApplicationListener<SessionSubscribeEvent> {
@Autowired
AbstractSubscribableChannel clientOutboundChannel;
@Override
public void onApplicationEvent(SessionSubscribeEvent event) {
Message<byte[]> message = event.getMessage();
StompHeaderAccessor stompHeaderAccessor = StompHeaderAccessor.wrap(message);
if (stompHeaderAccessor.getReceipt() != null) {
StompHeaderAccessor receipt = StompHeaderAccessor.create(StompCommand.RECEIPT);
receipt.setReceiptId(stompHeaderAccessor.getReceipt());
receipt.setSessionId(stompHeaderAccessor.getSessionId());
clientOutboundChannel.send(MessageBuilder.createMessage(new byte[0], receipt.getMessageHeaders()));
}
}
}
Artem Bilan提供的答案僅適用於SUBSCRIBE幀。 這是另一個用收據標題捕獲任何傳入幀。 只需要擴展帶有@EnableWebSocketMessageBroker注釋的類,其他類(如帶有@Controller注釋的類)保持不變。
import java.util.logging.Level; import java.util.logging.Logger; import java.util.Map; import java.util.List; import java.util.HashMap; import java.util.ArrayList; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.messaging.simp.config.SimpleBrokerRegistration; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.ChannelInterceptorAdapter; import org.springframework.messaging.support.GenericMessage; import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.SimpMessageType; import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.MessageChannel; import org.springframework.beans.factory.annotation.Autowired; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { private static final Logger LOGGER = Logger.getLogger( WebSocketConfig.class.getName() ); private MessageChannel outChannel; @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors( new InboundMessageInterceptor() ); } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { registration.interceptors( new OutboundMessageInterceptor() ); } @Override public void configureMessageBroker(MessageBrokerRegistry config) { // prefixes are application-dependent config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/note"); } class InboundMessageInterceptor extends ChannelInterceptorAdapter { @SuppressWarnings("unchecked") public Message preSend(Message message, MessageChannel channel) { LOGGER.log( Level.SEVERE, "preSend: "+message ); GenericMessage genericMessage = (GenericMessage)message; MessageHeaders headers = genericMessage.getHeaders(); String simpSessionId = (String)headers.get( "simpSessionId" ); if( ( SimpMessageType.MESSAGE.equals( headers.get( "simpMessageType" ) ) && StompCommand.SEND.equals( headers.get( "stompCommand" ) ) ) || ( SimpMessageType.SUBSCRIBE.equals( headers.get( "simpMessageType" ) ) && StompCommand.SUBSCRIBE.equals( headers.get( "stompCommand" ) ) ) && ( simpSessionId != null ) ) { Map<String,List<String>> nativeHeaders = (Map<String,List<String>>)headers.get( "nativeHeaders" ); if( nativeHeaders != null ) { List<String> receiptList = nativeHeaders.get( "receipt" ); if( receiptList != null ) { String rid = (String)receiptList.get(0); LOGGER.log( Level.SEVERE, "receipt requested: "+rid ); sendReceipt( rid, simpSessionId ); } } } return message; } private void sendReceipt( String rid, String simpSessionId ) { if( outChannel != null ) { HashMap<String,Object> rcptHeaders = new HashMap<String,Object>(); rcptHeaders.put( "simpMessageType", SimpMessageType.OTHER ); rcptHeaders.put( "stompCommand", StompCommand.RECEIPT ); rcptHeaders.put( "simpSessionId", simpSessionId ); HashMap<String,List<String>> nativeHeaders = new HashMap<String,List<String>>(); ArrayList<String> receiptElements = new ArrayList<String>(); receiptElements.add( rid ); nativeHeaders.put( "receipt-id", receiptElements ); rcptHeaders.put( "nativeHeaders",nativeHeaders ); GenericMessage<byte[]> rcptMsg = new GenericMessage<byte[]>( new byte[0],new MessageHeaders( rcptHeaders ) ); outChannel.send( rcptMsg ); } else LOGGER.log( Level.SEVERE, "receipt NOT sent" ); } } class OutboundMessageInterceptor extends ChannelInterceptorAdapter { public void postSend(Message message, MessageChannel channel, boolean sent) { LOGGER.log( Level.SEVERE, "postSend: "+message ); outChannel = channel; } } }
實際上,它要比它應該復雜得多,並且獲得outChannel不是很優雅。 但它的確有效。 :-)
所有上述過早發送收據框架。 以下內容可以滿足您的需求。
ref: https : //github.com/spring-projects/spring-framework/issues/21848
@Configuration
static class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
private MessageChannel outChannel;
@Autowired
public WebSocketConfig(MessageChannel clientOutboundChannel) {
this.outChannel = clientOutboundChannel;
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ExecutorChannelInterceptor() {
@Override
public void afterMessageHandled(Message<?> inMessage,
MessageChannel inChannel, MessageHandler handler, Exception ex) {
StompHeaderAccessor inAccessor = StompHeaderAccessor.wrap(inMessage);
String receipt = inAccessor.getReceipt();
if (StringUtils.isEmpty(receipt)) {
return;
}
StompHeaderAccessor outAccessor = StompHeaderAccessor.create(StompCommand.RECEIPT);
outAccessor.setSessionId(inAccessor.getSessionId());
outAccessor.setReceiptId(receipt);
outAccessor.setLeaveMutable(true);
Message<byte[]> outMessage =
MessageBuilder.createMessage(new byte[0], outAccessor.getMessageHeaders());
outChannel.send(outMessage);
}
});
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.