Как указать тип контента, созданный обработчиком в Spring Messaging?

Я экспериментирую с приложением Spring 4 WebSocket STOMP. Есть ли способ явно указать тип содержимого возвращаемого сообщения, созданного обработчиком? По умолчанию обработчик ниже производит application/json и обрабатывается соответствующим преобразователем сообщений.

@Controller
public class ProductController {

    @MessageMapping("/products/{id}")
    public String getProduct(@DestinationVariable int id) {
        return getProductById(id);
    }

}

Я ищу что-то вроде @RequestMapping(produces = "text/xml") в Spring MVC.

ОБНОВЛЕНИЕ (ответ на ответ Россена):

В идеале я хотел бы иметь возможность возвращать оба формата в зависимости от того, что запрашивает пользователь. Но если бы мне пришлось выбирать, я бы сказал XML и почти никогда JSON (XML — это просто пример, мы используем двоичный формат). Я пошел по второму предложенному вами пути - настроил пользовательские конвертеры вместо стандартных.

  1. Я реализовал пользовательский MessageConverter, расширяющий AbstractMessageConverter. В конструкторе я зарегистрировал соответствующий поддерживаемый MimeType.
  2. Затем я зарегистрировал свой собственный преобразователь, переопределив WebSocketMessageBrokerConfigurer configureMessageConverters, и вернул false из метода, чтобы не добавлять преобразователи по умолчанию.
  3. Как только мой контроллер возвращает значение, я получаю NPE в SendToMethodReturnValueHandler postProcessMessage. Это происходит потому, что CompositeMessageConverter содержит только один конвертер - мой пользовательский. Но мой преобразователь не проходит проверку supportsMimeType AbstractMessageConverter, а toMessage AbstractMessageConverter возвращает null. Это null вызывает исключение в postProcessMessage.

В качестве обходного пути я могу зарегистрировать дополнительный MimeType по умолчанию application/json для своего пользовательского конвертера. Но мне он кажется слишком грязным.


person Anton Moiseev    schedule 27.01.2014    source источник


Ответы (2)


Нет ничего лучше условий производства. Единственный способ сделать это прямо сейчас — внедрить SimpMessagingTemplate, а затем использовать вариант метода convertAndSend, который принимает MessagePostProcessor. Можно было сделать проще. Каков ваш вариант использования? Вы в основном используете JSON и вам нужно использовать XML в нескольких местах? Или вам нужно в первую очередь использовать XML? Если это последнее, вы можете просто настроить конвертеры для использования вместо стандартных.

person Rossen Stoyanchev    schedule 28.01.2014
comment
Пожалуйста, смотрите мой ответ выше. - person Anton Moiseev; 29.01.2014
comment
Похоже на возможную ошибку. Не могли бы вы открыть тикет в JIRA с подробностями трассировки стека? Почему supportsMimeType возвращает false, учитывая, что вы настроили поддерживаемые типы mime, и возвращает true, если заголовок типа контента не найден. Тогда нет ли для него соответствия, и если да, то, возможно, должен быть зарегистрирован другой конвертер? - person Rossen Stoyanchev; 29.01.2014
comment
Зарегистрирует проблему. supportsMimeType возвращает false, потому что getMimeType(headers) возвращает "application/json", даже если headers == null. Но он не соответствует ни одному из зарегистрированных MimeTypes моего конвертера. Не знаю, почему getMimeType(headers) возвращает JSON для null, смогу проверить сегодня позже. - person Anton Moiseev; 29.01.2014
comment
Думаю, я понимаю, почему это происходит: AbstractMessageBrokerConfiguration находит com.fasterxml.jackson.databind.ObjectMapper в пути к классам и устанавливает jackson2Present в true. Это делает метод getContentTypeResolver() для установки "application/json" в качестве MimeType по умолчанию. В свою очередь DefaultContentTypeResolver#resolve возвращает этот MimeType по умолчанию, если headers==null - person Anton Moiseev; 30.01.2014
comment
Спасибо, я обновил тему. Вероятно, лучшее решение до того, как оно будет исправлено, — установить тип контента по умолчанию на что-то, отличное от application/json (или не устанавливать его вообще). Смотрите мои комментарии под поданной проблемой. Продолжим там. - person Rossen Stoyanchev; 30.01.2014

Я вижу, что вы можете изменить заголовки, изменив конвертер сообщений. Например:

SockJsClient sockJsClient = new SockJsClient(transports);
WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
..
stompClient.setMessageConverter(new StringMessageConverter());
or
stompClient.setMessageConverter(new SimpleMessageConverter());

когда вы используете StringMessageConverter, клиент Java добавляет заголовок типа содержимого.

GenericMessage [payload=byte[33], headers={simpMessageType=MESSAGE, stompCommand=SEND, nativeHeaders={destination=[/app/chatchannel], content-type=[text/plain;charset=UTF-8], content-length=[33]}, simpSessionAttributes={ip=/127.0.0.1:59629}, simpHeartbeat=[J@147a2bf, contentType=text/plain;charset=UTF-8, lookupDestination=/chatchannel, simpSessionId=79431feb8b5f4a9497492ccc64f8965f, simpDestination=/app/chatchannel}]

Но если вы используете SimpleMessageConverter, заголовок типа содержимого не добавляется.

это подсказка о том, что вы хотите сделать?

Проверьте этот вопрос, я добавил код, который может вам помочь:

Как настроить преобразователи сообщений Spring Sockjs Java Client

person Sergio    schedule 18.08.2016