如何在 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。 然后我通过覆盖WebSocketMessageBrokerConfigurerconfigureMessageConverters 注册了我的自定义转换器,并从方法中返回false 以不添加默认转换器。 只要我的控制器返回值,我就会在SendToMethodReturnValueHandlerpostProcessMessage 中获得 NPE。发生这种情况是因为CompositeMessageConverter 仅包含一个转换器 - 我的自定义转换器。但我的转换器失败AbstractMessageConvertersupportsMimeType 检查和AbstractMessageConvertertoMessage 返回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 中指定订单验证

如何在 Spring Security 中指定 Open ID Realm?

如何在spring data mongoDB中指定数据库名称