如何在 Spring Messaging 中指定处理程序生成的内容类型?
Posted
技术标签:
【中文标题】如何在 Spring Messaging 中指定处理程序生成的内容类型?【英文标题】:How to specify content type produced by a handler in Spring Messaging? 【发布时间】:2014-01-27 20:15:44 【问题描述】:我正在试验 Spring 4 WebSocket STOMP 应用程序。有没有办法明确指定处理程序产生的返回消息的内容类型?默认情况下,下面的处理程序会生成application/json
并由相应的消息转换器处理。
@Controller
public class ProductController
@MessageMapping("/products/id")
public String getProduct(@DestinationVariable int id)
return getProductById(id);
我在 Spring MVC 中寻找类似 @987654324@ 的东西。
更新(回复Rossen's answer):
理想情况下,我希望能够根据用户的要求返回两种格式。但是如果我必须选择,我会说 XML 而几乎从不说 JSON(XML 只是一个例子,我们使用二进制格式)。我采用了您建议的第二种方式 - 配置自定义转换器而不是默认转换器。
-
我已经实现了自定义
MessageConverter
扩展AbstractMessageConverter
。在构造函数中,我注册了适当的受支持的 MimeType。
然后我通过覆盖WebSocketMessageBrokerConfigurer
的configureMessageConverters
注册了我的自定义转换器,并从方法中返回false
以不添加默认转换器。
只要我的控制器返回值,我就会在SendToMethodReturnValueHandler
的postProcessMessage
中获得 NPE。发生这种情况是因为CompositeMessageConverter
仅包含一个转换器 - 我的自定义转换器。但我的转换器失败AbstractMessageConverter
的supportsMimeType
检查和AbstractMessageConverter
的toMessage
返回null
。这个null
导致postProcessMessage
中的异常。
作为解决方法,我可以为我的自定义转换器注册额外的默认 MimeType application/json
。但我觉得它太脏了。
【问题讨论】:
【参考方案1】:没有什么比产生条件。现在唯一的方法是注入SimpMessagingTemplate
,然后使用带有MessagePostProcessor
的convertAndSend 方法变体。它可以变得更简单。你的用例是什么?您是否主要使用 JSON 并且需要在少数地方使用 XML?还是您需要主要使用 XML?如果是后者,您可以简单地配置转换器以使用而不是默认转换器。
【讨论】:
请看我上面的回复。 听起来像是一个可能的错误。你能在 JIRA 中打开一张带有堆栈跟踪详细信息的票吗?为什么supportsMimeType会返回false,因为您已经配置了支持的mime类型,如果没有找到content-type header,它会返回true。那么是否没有匹配项,如果是,是否应该注册另一个转换器? 将提出问题。supportsMimeType
返回 false
,因为 getMimeType(headers)
返回 "application/json"
,即使 headers == null
。但它与我的转换器注册的任何 MimeType 都不匹配。不知道为什么getMimeType(headers)
会为null
返回 JSON,今天晚些时候可以检查。
我想我明白为什么会这样了:AbstractMessageBrokerConfiguration
在类路径中找到com.fasterxml.jackson.databind.ObjectMapper
并将jackson2Present
设置为true
。它使getContentTypeResolver()
方法将"application/json"
设置为默认MimeType。反过来 DefaultContentTypeResolver#resolve
如果 headers==null
则返回此默认 MimeType
谢谢我已经更新了这个问题。在修复之前可能一个更好的解决方案是将默认内容类型设置为 application/json 以外的其他内容(或根本不设置)。在提交的问题下查看我的 cmets。让我们继续。【参考方案2】:
我看到您可以更改标题以更改消息转换器。 例如:
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,则不会添加content-type header。
这是你想做什么的线索?
检查这个问题,我放了一些可以帮助你的代码:
How configure the Spring Sockjs Java Client message converters
【讨论】:
以上是关于如何在 Spring Messaging 中指定处理程序生成的内容类型?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 spring 的 jdbcTemplate 在 SQL 查询中指定参数
如何在 Spring/Spring Boot pom.xml 中指定 Java 版本?
如何在spring data jpa查询中指定@lock超时?
如何在请求正文 Spring Boot Rest Controller 中指定订单验证