问题描述
春季启动应用
在build.gradle中:
implementation 'com.google.code.gson:gson:2.7'
此处JMSConfiguration:
import org.springframework.boot.autoconfigure.jms.DefaultJmsListenerContainerFactoryConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
import org.springframework.jms.config.JmsListenerContainerFactory;
import org.springframework.jms.support.converter.MappingJackson2MessageConverter;
import org.springframework.jms.support.converter.MessageConverter;
import org.springframework.jms.support.converter.MessageType;
@Configuration
@ComponentScan(basePackages = "ru.otus.software_architect.eshop")
public class JMSConfiguration {
@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory,including the message converter
configurer.configure(factory,connectionFactory);
// You Could still override some of Boot's default if necessary.
return factory;
}
@Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.settargettype(MessageType.TEXT);
converter.setTypeIdPropertyName("_type");
return converter;
}
}
这是我向ActiviveMQ发送消息的方式:
private void sendMessagetoMessagebroker(NotifyActionEnum action,int orderId) {
JsonObject json = new JsonObject();
json.addProperty("email",UserService.getCurrentUserName());
json.addProperty("action",action.name().toLowerCase());
json.addProperty("orderId",orderId);
jmstemplate jmstemplate = context.getBean(jmstemplate.class);
String message = json.toString();
jmstemplate.convertAndSend(ESHOP_QUEUE,message);
logger.info("sendMessagetoMessagebroker: success_sent_message_to_MB: " + message);
}
在日志中:
success_sent_message_to_MB
:
{"email":"someemail@email.com","action":"order_update","orderId":14}
很好。
但是在我的队列中的ActiveMQ上,消息看起来像这样:
"{\"email\":\"a_subscriber@mail.ru\",\"action\":\"order_update\",\"orderId\":4,\"createdAt\":\"2020-09-13T11:32:09.976+0300\"}"
以下屏幕截图:
然后我启动另一个应用程序(消费者)。当尝试从json获取日期时,它就坏了:
JsonElement messageJson = GsonUtil.parser.parse(message);
String action = messageJson.getAsJsonObject().get("action").getAsstring(); // here broken
我收到错误消息:
Caused by: java.lang.IllegalStateException: Not a JSON Object: "{\"email\":\"a_subscriber@mail.ru\",\"createdAt\":\"2020-09-13T11:32:09.976+0300\"}"
如何避免在字符串中使用\“?
我需要排队成为下一个字符串:
{"email":"someemail@email.com","orderId":14}
解决方法
尝试使用默认的MessageConverter
(即SimpleMessageConverter
)并以byte[]
的形式发送消息,例如:
private void sendMessageToMessageBroker(NotifyActionEnum action,int orderId) {
JsonObject json = new JsonObject();
json.addProperty("email",UserService.getCurrentUserName());
json.addProperty("action",action.name().toLowerCase());
json.addProperty("orderId",orderId);
JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);
String message = json.toString();
jmsTemplate.convertAndSend(ESHOP_QUEUE,message.getBytes());
logger.info("sendMessageToMessageBroker: success_sent_message_to_MB: " + message);
}
当您以byte[]
的形式发送消息时,SimpleMessageConverter
会将其转换为javax.jms.BytesMessage
。消费者收到消息后,可以将byte[]
转换为String
,如下所示:
String messageAsString;
if (message instanceof BytesMessage) {
BytesMessage bytesMessage = (BytesMessage) message;
byte[] buffer = new byte[(int) bytesMessage.getBodyLength()];
bytesMessage.readBytes(buffer);
messageAsString = new String(buffer);
}
JsonElement messageJson = GsonUtil.parser.parse(messageAsString);
String action = messageJson.getAsJsonObject().get("action").getAsString();
我相信以byte[]
的形式发送邮件会避免不必要的转义。
我使用urlEncode/decode
向ActiveMQ发送消息
在我的控制器中:
private String publishToMessageBroker(NotifyActionEnum action,int orderId) {
logger.info("publishToMessageBroker:");
JsonObject json = new JsonObject();
json.addProperty("email",UserService.getCurrentUserName());
json.addProperty("action",action.name().toLowerCase());
json.addProperty("orderId",orderId);
json.addProperty("createdAt",DateUtil.date2String(new Date(),DateUtil.JSON_DATE_FORMAT));
String message = json.toString();
String urlEncodeMessage = StringUtll.urlEncode(message);
jmsTemplate.convertAndSend(ESHOP_QUEUE,urlEncodeMessage);
logger.info("publishToMessageBroker: success_sent_message_to_MB: " + message);
return "Message was success published on Message Broker!"; // can use as response
}
现在在ActiveMQ中,消息看起来像这样:
"%7B%22email%22%3A%22myemail%40mail.com%22%2C%22action%22%3A%22order_delete%22%2C%22orderId%22%3A6%2C%22createdAt%22%3A%222020-09-19T12%3A20%3A57.844%2B0300%22%7D"
现在我在消息接收器中解码消息
@JmsListener(destination = ESHOP_QUEUE)
public void receiveMessage(String urlEncodeMessage) {
try {
String urlDecodeMessage = StringUtil.urlDecode(urlEncodeMessage);
String pureDecodeMessage = StringUtil.removeFirstAndLastQuotes(urlDecodeMessage);
JsonElement messageJson = GsonUtil.parser.parse(pureDecodeMessage);
现在工作正常。没有
经过url解码后,我得到了纯json:
"{"email":"myemail@mail.com","action":"order_delete","orderId":6,"createdAt":"2020-09-19T12:20:57.844+0300"}"
,
转换为字符串时的问题
String message = json.toString();
jmsTemplate.convertAndSend(ESHOP_QUEUE,message);
您可以定义一个对象,该对象将被发送到队列中,例如由我们自己管理
class OrderMessage {
private String email;
private String action;
private String orderId;
//...
}
jmsTemplate.convertAndSend("mailbox",new OrderMessage(email,action,orderId));
然后Consumer
@JmsListener(.... you queue)
public void receiveMessage(OrderMessage message) {
System.out.println(message);
}