[英]How to deal with JSON message with spring-rabbit in spring boot application?
Here are my code snippets.这是我的代码片段。
MQConfiguration
class for configuration用于配置的MQConfiguration
类
@Configuration public class MQConfiguration { @Bean public Receiver receiver() { return new Receiver(); } }
Receiver
class for dealing with receiving messages Receiver
类,用于处理接收消息
@RabbitListener(queues = "testMQ") public class Receiver { @RabbitHandler public void receive(Message msg){ System.out.println(msg.toString()); } }
And here is the JSON message I sent to the RabbitMQ这是我发送给RabbitMQ的 JSON 消息
{ "id": 1, "name": "My Name", "description": "This is description about me" }
However I got following error message when I ran my application.但是,当我运行我的应用程序时,我收到了以下错误消息。
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
So what should I do if all I want is to print the JSON message in receive()
method?那么如果我只想在receive()
方法中打印 JSON 消息,我该怎么办? I'd really appreciate that anyone can shed a light on this.我真的很感激任何人都可以对此有所了解。 :) :)
If you use Spring Boot, you just need to configure:如果使用Spring Boot,只需要配置:
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
Otherwise you have to configure:否则你必须配置:
@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 http://docs.spring.io/spring-amqp/docs/1.7.0.RELEASE/reference/html/_reference.html#async-annotation-driven
In order to send JSON to RabbitMQ and consume it by Spring Boot we need to set content_type
.为了将 JSON 发送到 RabbitMQ 并由 Spring Boot 使用它,我们需要设置content_type
。
Let me describe with an example where I had a Python Producer and Java consumer (I was sending the JSON from Python to RabbitMQ and Spring Boot Java was supposed to receive the JSON task).让我用一个例子来描述我有一个 Python 生产者和 Java 消费者(我将 JSON 从 Python 发送到 RabbitMQ 并且 Spring Boot Java 应该接收 JSON 任务)。
There are two solutions:有两种解决方案:
Solution 1: Sending as JSON string and convert it manually using Jakson or GSON解决方案 1:作为 JSON 字符串发送并使用 Jakson 或 GSON 手动转换
You need to set the content_type="text/plain" and convert the JSON to a string.Then in the Spring side, use a fuction with a string as the input as the listener and manually convert the object.需要设置 content_type="text/plain" 并将 JSON 转换为字符串。然后在 Spring 端,使用一个以字符串作为输入的函数作为侦听器并手动转换对象。
RabbitHandler: 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 Object: SimStatusReport 对象:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SimStatusReport {
private String id;
private int t;
}
Here is my Python Code:这是我的 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)
Solution 2: Sending JSON string and let the Jackson2JsonMessageConverter do the conversion for you automatically.解决方案 2:发送 JSON 字符串并让 Jackson2JsonMessageConverter 自动为您进行转换。
You need to set the content_type="application/json".您需要设置 content_type="application/json"。 Then you need to add the appropriate header to __TypeId__
in the header of the RabbitMQ request.然后需要在RabbitMQ请求的header中的__TypeId__
中添加相应的header。 You need to include the exact name space of the object so the Jackson undestand the the conversion.您需要包含对象的确切名称空间,以便 Jackson 理解转换。
Here is my example using Python (just the publish_result fuction):这是我使用 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)
Then you need to configure the Java to use Jackson2JsonMessageConverter:然后你需要配置Java来使用Jackson2JsonMessageConverter:
@Configuration
public class RabbitConfiguration {
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
}
Here would be your listener:这是你的听众:
@RabbitListener(queues = "sim_results")
public class TaskReceiver {
@RabbitHandler
public void receive(SimStatusReport in) {
System.out.println("Object instance " + in +
" [x] Received");
}
}
Note: Make sure all you objects has setter and getters for all properties and all argument constructor.注意:确保所有对象都具有所有属性和所有参数构造函数的 setter 和 getter。 I use @Data, @NoArgsConstructor and @AllArgsConstructor from lombok to automatically generate it我使用 lombok 的 @Data、@NoArgsConstructor 和 @AllArgsConstructor 来自动生成它
I know its been awhile since the last response, but I'd want to add my answer.我知道自上次回复以来已经有一段时间了,但我想添加我的答案。 Just in case someone else is having the same issues.以防万一其他人遇到同样的问题。
When I set up a receiver like yours, I experienced the similar problem where I couldn't convert JSON in the body of the RabbitMQ Message to my object.当我设置像你这样的接收器时,我遇到了类似的问题,我无法将 RabbitMQ 消息正文中的 JSON 转换为我的对象。 It simply returns an error message like this.它只是返回这样的错误消息。
org.springframework.amqp.rabbit.support.ListenerExecutionFailedException: Failed to convert message
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:146) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:1654) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.actualInvokeListener(AbstractMessageListenerContainer.java:1573) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:1561) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:1552) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:1496) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:968) [spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:914) [spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1600(SimpleMessageListenerContainer.java:83) [spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.mainLoop(SimpleMessageListenerContainer.java:1289) [spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1195) [spring-rabbit-2.3.9.jar:2.3.9]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_271]
Caused by: org.springframework.amqp.AmqpException: No method found for class java.util.LinkedHashMap
at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getHandlerForPayload(DelegatingInvocableHandler.java:185) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.adapter.DelegatingInvocableHandler.getMethodFor(DelegatingInvocableHandler.java:317) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.adapter.HandlerAdapter.getMethodFor(HandlerAdapter.java:110) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.invokeHandlerAndProcessResult(MessagingMessageListenerAdapter.java:192) ~[spring-rabbit-2.3.9.jar:2.3.9]
at org.springframework.amqp.rabbit.listener.adapter.MessagingMessageListenerAdapter.onMessage(MessagingMessageListenerAdapter.java:137) ~[spring-rabbit-2.3.9.jar:2.3.9]
... 11 common frames omitted
After hours of searching through different websites without any good answer, I finally found out that @RabbitListener won't work at the class level.经过数小时在不同网站上搜索但没有任何好的答案,我终于发现@RabbitListener 在课堂级别不起作用。 When you move it to the method level, though, it works fine.但是,当您将其移动到方法级别时,它可以正常工作。
So, I remove @RabbitHandler and move @RabbitListener to the receive method.所以,我删除了@RabbitHandler 并将@RabbitListener 移到了接收方法中。
Your receiver code should look like this after editing.编辑后,您的接收器代码应如下所示。
public class Receiver {
@RabbitListener(queues = "testMQ")
public void receive(Message msg){
System.out.println(msg.toString());
}
}
I still don't fully understand why it is not working at the class level.我仍然不完全理解为什么它在课堂上不起作用。 If anyone has a good explanation, please share it in the comments section.如果有人有好的解释,请在评论部分分享。 Thank you very much.非常感谢。
Source: https://titanwolf.org/Network/Articles/Article?AID=0f214d79-10f0-4b4c-9478-607428770256#gsc.tab=0来源: https : //titanwolf.org/Network/Articles/Article?AID=0f214d79-10f0-4b4c-9478-607428770256#gsc.tab=0
in Simple way you can use this function new String(Messages)
以简单的方式,您可以使用此函数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);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.