[英]Spring Boot RabbitMQ Receiver Jackson Deserialize to POJO
我有一個 spring boot 項目,我試圖在其中與 rabbitmq 服務器集成,以便我可以向/從隊列發布和讀取消息。
這是我的 rabbitmq 配置(已編輯為僅顯示相關詳細信息):
@Configuration
@ConfigurationProperties(prefix="rabbit")
public class RabbitConfig {
private String queue;
@Bean
Queue queue() {
return new Queue(queue, durable);
}
@Bean
public MessageConverter jsonMessageConverter(){
return new Jackson2JsonMessageConverter();
}
@Bean
SimpleMessageListenerContainer container(ConnectionFactory connectionFactory, Queue queue,
MessageListenerAdapter listenerAdapter, MessageConverter messageConverter) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
container.setQueues(queue);
container.setMessageListener(listenerAdapter);
container.setMessageConverter(messageConverter);
return container;
}
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver);
}
public void setQueue(String queue) {
this.queue = queue;
}
}
這是我的接收器類:
public interface Receiver {
void handleMessage(FooA message);
}
@Component
public class RabbitReceiver implements Receiver {
@Override
public void handleMessage(FooA message) {
System.out.println(message);
}
}
還有我的 pojo:
public class FooA {}
private double num;
private Map<String, String> map = new HashMap();
public FooA() {
}
public FooA(double num, Map<String, String> map) {
this.num = num;
this.map = map;
}
public int getnum() {
return num;
}
public Map<String, String> getMap() {
return map;
}
}
我能夠成功地將FooA
消息對象發布到隊列。 這是隊列中的樣子:
[
{
"payload_bytes": 41,
"redelivered": false,
"exchange": "amq.fanout",
"routing_key": "",
"message_count": 0,
"properties": {
"priority": 0,
"delivery_mode": 2,
"headers": {
"__TypeId__": "com.test.FooA"
},
"content_encoding": "UTF-8",
"content_type": "application/json"
},
"payload": "{\"num\":1.2,\"map\":{}}",
"payload_encoding": "string"
}
]
但是當我嘗試從隊列中讀取時,出現此錯誤:
org.springframework.amqp.rabbit.listener.exception.ListenerExecutionFailedException: Failed to invoke target method 'handleMessage' with argument type = [class [B], value = [{[B@75a7bfc9}]
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:408) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.onMessage(MessageListenerAdapter.java:298) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:822) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:745) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$001(SimpleMessageListenerContainer.java:97) [spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$1.invokeListener(SimpleMessageListenerContainer.java:189) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.invokeListener(SimpleMessageListenerContainer.java:1276) [spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer.executeListener(AbstractMessageListenerContainer.java:726) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.doReceiveAndExecute(SimpleMessageListenerContainer.java:1219) [spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.receiveAndExecute(SimpleMessageListenerContainer.java:1189) [spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer.access$1500(SimpleMessageListenerContainer.java:97) [spring-rabbit-1.7.3.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1421) [spring-rabbit-1.7.3.RELEASE.jar:na]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_121]
Caused by: java.lang.NoSuchMethodException: com.test.RabbitReceiver.handleMessage([B)
at java.lang.Class.getMethod(Class.java:1786) ~[na:1.8.0_121]
at org.springframework.util.MethodInvoker.prepare(MethodInvoker.java:174) ~[spring-core-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter.invokeListenerMethod(MessageListenerAdapter.java:386) ~[spring-rabbit-1.7.3.RELEASE.jar:na]
... 12 common frames omitted
我做錯了什么?
編輯1 :我將方法更改為:
@Override
public void handleMessage(byte[] message) {
System.out.println(message);
}
哪個有效,但完全無法使用。 它只是這樣顯示:
我如何FooA
映射到我的 pojo FooA
我只是讓實現Serializable
接口的類刪除了 JsonMessageConverter。 Json 和 Serializable 是沖突的,所以它不起作用。
將 bytearray 轉換為字符串並使用 jackson mapper (ObjectMapper) 映射到您的 pojo。 您的映射器上有配置:例如
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
this.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
this.registerModule(new JavaTimeModule())
看起來消息是作為字符串而不是 JSON 發布的。 那就是你看到的
"payload_encoding": "string"
Spring 可以自動將此字符串轉換為 byte[],如截圖所示。
您還需要在 RabbitTemplate 上設置消息轉換器,如下所示:
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,MessageConverter rabbitJsonMessageConverter) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(rabbitJsonMessageConverter);
return template;
}
這應該正確地將消息發布為 JSON。
你做的一切都是正確的。 但是您沒有向MessageListenerAdapter
提供任何方法來接收和處理您的消息。 這就是您收到ListenerExecutionFailedException: Failed to invoke target method 'handleMessage' 的原因。
要修復此更改,請更改以下代碼:
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver);
}
到:
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver) {
return new MessageListenerAdapter(receiver, "handleMessage");
}
本文展示了如何以更簡單的方式解決這個問題: https : //thepracticaldeveloper.com/produce-and-consume-json-messages-with-spring-boot-amqp/
配置:
@Bean
public RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory) {
final var rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(producerJackson2MessageConverter());
return rabbitTemplate;
}
@Bean
public Jackson2JsonMessageConverter producerJackson2MessageConverter() {
return new Jackson2JsonMessageConverter();
}
聽眾:
@RabbitListener(queues = MessagingApplication.QUEUE_SPECIFIC_NAME)
public void receiveMessage(final CustomMessage customMessage) {
log.info("Received message and deserialized to 'CustomMessage': {}", customMessage.toString());
}
POJO:
public record CustomMessage(@JsonProperty("text") String text,
@JsonProperty("priority") int priority,
@JsonProperty("secret") boolean secret)
implements Serializable {
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.