#spring-boot #gson #activemq
#весенняя загрузка #gson #activemq
Вопрос:
Приложение Spring boot
В 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","action":"order_update","orderId":4,"createdAt":"2020-09-13T11:32:09.976 0300"}"
Как я могу избежать » в строке?
Мне нужно поставить в очередь следующую строку:
{"email":"someemail@email.com","action":"order_update","orderId":14}
Комментарии:
1. Что-то помещает строку в двойные кавычки, и для этого нужно экранировать двойные кавычки в строке, чтобы это сработало.
2. @Steve Почему в очереди отображается строка с » ?
3. Я предполагаю, это из-за кавычек в начале и конце строки. Какой бы механизм ни добавлял эти кавычки, он также экранирует кавычки в середине строки, ставя » перед каждой из них. Почему это происходит, я не знаю.
4. Что
MessageConverter
вы настроили для своегоJmsTemplate
? Используете ли вы значение по умолчанию,SimpleMessageConverter
которое преобразует aString
вjavax.jms.TextMessage
?5. @JustinBertram Я обновил свой пост
Ответ №1:
Попробуйте использовать значение по умолчанию 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);
}
Когда вы отправляете сообщение в виде a , byte[]
the SimpleMessageConverter
преобразует его в a 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[]
позволит избежать нежелательного экранирования.
Комментарии:
1. можно ли понять, что производитель отправляет через веб-консоль?
2. Я не уверен, что вы имеете в виду.
3. Я хочу увидеть некоторую информацию, например
{"email":"someemail@email.com","action":"order_update","orderId":14}
, с помощью инструментов пользовательского интерфейса4. Я не уверен, что веб-консоль ActiveMQ будет декодировать
byte[]
вString
для отображения. Имейте в виду, что сообщения (даже текстовые сообщения) могут быть закодированы многими различными способами, и у брокера не обязательно есть информация, необходимая для декодирования сообщения в формат, доступный для чтения человеком (при условии, что такой формат существует).5. Я считаю, что веб-консоль не может декодировать из byte[] в string, потому что byte [] может быть чем угодно. но order_id может быть частью очень полезной информации, которую следует воспринимать как человеческий язык
Ответ №2:
Я использую 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 сообщение выглядит так:
"{"email":"myemail@mail.com","action":"order_delete","orderId":6,"createdAt":"2020-09-19T12:20:57.844+0300"}"
И теперь в получателе сообщений я декодирую сообщение
@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);
И теперь все работает нормально. Больше никаких escape-символов, таких как «».
После декодирования URL я получаю чистый json:
"{"email":"myemail@mail.com","action":"order_delete","orderId":6,"createdAt":"2020-09-19T12:20:57.844 0300"}"