web-dev-qa-db-ja.com

SpringBootアプリケーションでSpring-rabbitを使用してJSONメッセージを処理する方法は?

これが私のコードスニペットです。

  • 構成用のMQConfigurationクラス

    _@Configuration
    public class MQConfiguration {
        @Bean
        public Receiver receiver() {
            return new Receiver();
        }
    }
    _
  • Receiverメッセージの受信を処理するためのクラス

    _@RabbitListener(queues = "testMQ")
    public class Receiver {
    
        @RabbitHandler
        public void receive(Message msg){
            System.out.println(msg.toString());
        }
    }
    _
  • そして、これが私がRabbitMQに送信したJSONメッセージです。

    _{
        "id": 1,
        "name": "My Name",
        "description": "This is description about me"
    }
    _

ただし、アプリケーションを実行すると、次のエラーメッセージが表示されました。

_2017-02-28 17:16:35.931  WARN 11828 --- [cTaskExecutor-1] s.a.r.l.ConditionalRejectingErrorHandler : Execution of Rabbit message listener failed.

org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Listener threw exception
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.wrapToListenerExecutionFailedExceptionIfNeeded(AbstractMessageListenerContainer.Java:872) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.Java:782) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.Java:702) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.Java:95) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.Java:186) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.Java:1227) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.Java:683) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.Java:1181) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.Java:1165) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1500(SimpleMessageListenerContainer.Java:95) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.Java:1367) [spring-rabbit-1.7.0.RELEASE.jar:na]
    at Java.lang.Thread.run(Thread.Java:745) [na:1.8.0_60]
Caused by: org.springframework.amqp.AmqpException: No method found for class [B
    at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getHandlerForPayload(DelegatingInvocableHandler.Java:127) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getMethodNameFor(DelegatingInvocableHandler.Java:224) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.getMethodAsString(HandlerAdapter.Java:61) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.Java:140) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.Java:106) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.Java:779) ~[spring-rabbit-1.7.0.RELEASE.jar:na]
    ... 10 common frames omitted
_

では、JSONメッセージをreceive()メソッドで出力するだけの場合はどうすればよいですか?誰もがこれに光を当てることができることを本当に感謝しています。 :)

8
kenshinji

Spring Bootを使用する場合は、以下を構成する必要があります。

@Bean
public MessageConverter jsonMessageConverter() {
    return new Jackson2JsonMessageConverter();
}

それ以外の場合は、以下を構成する必要があります。

@Bean
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
    SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
...
    factory.setMessageConverter(new Jackson2JsonMessageConverter());
...
    return factory;
}

http://docs.spring.io/spring-amqp/docs/1.7.0.RELEASE/reference/html/_reference.html#async-annotation-driven

4
Artem Bilan

JSONをRabbitMQに送信し、Spring Bootで使用するには、content_typeを設定する必要があります。

PythonプロデューサーとJavaコンシューマー(Python RabbitMQとSpringBootへJavaはJSONタスクを受け取ることになっていた)。

2つの解決策があります:

解決策1:JSON文字列として送信し、JaksonまたはGSONを使用して手動で変換します

Content_type = "text/plain"を設定し、JSONを文字列に変換する必要があります。次に、Spring側で、リスナーとして入力として文字列を使用する関数を使用し、オブジェクトを手動で変換します。

RabbitHandler:

@RabbitHandler
public void receive(String inputString) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    SimStatusReport theResult = objectMapper.readValue(inputString, SimStatusReport.class);

    System.out.println("String instance "  + theResult.toString() +
            " [x] Received");
}

SimStatusReportオブジェクト:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SimStatusReport {
    private String id;
    private int t;
}

これが私のPythonコード:

import pika
import json
import uuid


connectionResult = pika.BlockingConnection(pika.ConnectionParameters(Host='localhost'))
channelResult = connectionResult.channel()
routing_key_result = 'sim_results'
channelResult.queue_declare(queue=routing_key_result, durable=True)

def publish_result(sim_status):
    message =json.dumps(sim_status)
    channelResult.basic_publish(exchange='',
                                routing_key=routing_key_result,
                                body=message,
                                properties=pika.BasicProperties(
                                    content_type="text/plain",
                                    content_encoding= 'UTF-8',
                                    delivery_mode=2,  # make message persistent
                          ))
    print("Sent ", message)


newsim_status = {'id': str(uuid.uuid4()), 't': 0}
publish_result(newsim_status)

解決策2:JSON文字列を送信し、Jackson2JsonMessageConverterに自動的に変換を実行させます。

Content_type = "application/json"を設定する必要があります。次に、RabbitMQリクエストのヘッダーの__TypeId__に適切なヘッダーを追加する必要があります。ジャクソンが変換を理解できないように、オブジェクトの正確な名前空間を含める必要があります。

Python(publish_result関数のみ)を使用した私の例を次に示します。

def publish_result(sim_status):
    message =json.dumps(sim_status)
    channelResult.basic_publish(exchange='',
                                routing_key=routing_key_result,
                                body=message,
                                properties=pika.BasicProperties(
                                    content_type="application/json"
                                    headers={'__TypeId__': 'com.zarinbal.simtest.run.model.SimStatusReport'},
                                    content_encoding= 'UTF-8',
                                    delivery_mode=2,  # make message persistent
                          ))
    print("Sent ", message)

次に、Jackson2JsonMessageConverterを使用するようにJavaを構成する必要があります:

@Configuration
    public class RabbitConfiguration {
        @Bean
        public MessageConverter jsonMessageConverter() {
            return new Jackson2JsonMessageConverter();
        }
    }

これがあなたのリスナーです:

@RabbitListener(queues = "sim_results")
public class TaskReceiver {
    @RabbitHandler
    public void receive(SimStatusReport in) {
        System.out.println("Object instance "  + in +
                " [x] Received");
    }
}

注:すべてのオブジェクトにすべてのプロパティとすべての引数コンストラクターのセッターとゲッターがあることを確認してください。 lombokの@ Data、@ NoArgsConstructor、@ AllArgsConstructorを使用して、自動的に生成します

2
Amir

簡単な方法で、この関数を使用できますnew String(Messages)

@RabbitListener(queues = "testMQ")
public class Receiver {

    @RabbitHandler
    public void receive(Message msg){
String MQMessage = new String(msg.getBody());
        System.out.println(MQMessage);
    }
}
0