首页 > 解决方案 > spring websocket/stomp + rabbitmq - convertAndSend,队列的目标路径

问题描述

我正在学习为我未来的应用程序聊天。那是用户的私人聊天。我正在使用 Stomp,对于经纪人,我想使用 rabbitmq。当我使用 springs SimpleBroker 时一切都很好,但是当我尝试 rabbitmq 时它不起作用。只是rabbitmq代理不接受像spring代理这样的目标路径,带有很多斜杠/topic/user/number。所以我试着用点来解决问题,但我仍然无法让它工作。所以我有这样的事情:

 messagingTemplate.convertAndSend("/topic/push." + chatMessage.getRecipientId().toString(),
                new ChatNotification(
                        savedMessage.getId(),
                        savedMessage.getSenderId(),
                        savedMessage.getSenderName(),
                        savedMessage.getContent()
                ));

所以我认为这样的路径应该可行,但它没有。当我尝试不带点的“/topic/push”时,它也会失败。

配置如下所示:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOrigins("http://localhost:4200").withSockJS();

    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
        resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setObjectMapper(new ObjectMapper());
        converter.setContentTypeResolver(resolver);
        messageConverters.add(converter);
        return false;
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
//        registry.enableSimpleBroker("/topic");
        registry.setApplicationDestinationPrefixes("/app");
        registry.setUserDestinationPrefix("/topic");
        registry.enableStompBrokerRelay("/topic")
                .setRelayHost("localhost")
                .setRelayPort(61613)
                .setClientLogin("lukasz")
                .setClientPasscode("user")
                .setSystemLogin("lukasz")
                .setSystemPasscode("user");
    }
}

控制器方法:

 @MessageMapping("/chat")
    public void processMessage(@Payload ChatMessage chatMessage) {
        String chatId = chatRoomMessageService
                .getChatId(chatMessage.getSenderId(), chatMessage.getRecipientId(), true)
                .orElseThrow(() -> new RuntimeException("Nie ma takiego czatu. Tworzenie nowych kanałów wyłączone"));
        chatMessage.setChatId(chatId);

        ChatMessage savedMessage = chatMessageService.save(chatMessage);

        messagingTemplate.convertAndSend("/topic/push" + chatMessage.getRecipientId().toString(),
                new ChatNotification(
                        savedMessage.getId(),
                        savedMessage.getSenderId(),
                        savedMessage.getSenderName(),
                        savedMessage.getContent()
                ));
    }

还有一个例外:

org.springframework.messaging.MessageDeliveryException: Failed to handle GenericMessage [payload=byte[76], headers={simpMessageType=MESSAGE, contentType=application/json, simpDestination=/topic/push2}] to org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask@2486d6d8 in UserDestinationMessageHandler[DefaultUserDestinationResolver[prefix=/topic/]]; nested exception is java.lang.IllegalArgumentException: Expected destination pattern "/user/{userId}/**"
    at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:153) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.support.ExecutorSubscribableChannel.sendInternal(ExecutorSubscribableChannel.java:100) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:139) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:125) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.simp.SimpMessagingTemplate.sendInternal(SimpMessagingTemplate.java:187) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:162) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.simp.SimpMessagingTemplate.doSend(SimpMessagingTemplate.java:48) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:109) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:151) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:129) ~[spring-messaging-5.3.5.jar:5.3.5]
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.convertAndSend(AbstractMessageSendingTemplate.java:122) ~[spring-messaging-5.3.5.jar:5.3.5]
    at luke.socket2.controller.ChatController.processMessage(ChatController.java:42) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:564) ~[na:na]

它来自messagingTemplate.convertAndSend()。当我使用 /user 尝试预期的目的地时,它不起作用。Rabbitmq 不接受它。其他路径给了我“不是有效的主题目的地”例外。

所以请帮助我如何发送我的通知。:)

  1. 使用 rabbitmq 我可以使用 convertAndSendToUser() 方法吗?它看起来如何,与 convertAndSend() 有什么区别?

标签: springwebsocketrabbitmqchatstomp

解决方案


推荐阅读