spring-integration - 从 Spring Integration 的 @Gateway 方法返回 ResponseEntity
问题描述
我有IntegrationFlow
我称之为 HTTP 端点的地方:
@Bean
public IntegrationFlow getInformationFlow(RestTemplate restTemplate) {
return IntegrationFlows.from(GET_RESPONSE_ENTITY)
.handle(Http
.outboundGateway(url + "/application/{code}", restTemplate)
.httpMethod(GET)
.uriVariable("code", "payload")
.expectedResponseType(new ParameterizedTypeReference<ResponseEntity<Information>>() {
})
).get();
}
此流程在getInformation
被调用时执行,这要归功于Gateway
@MessagingGateway
public interface MyGateway {
@Gateway(requestChannel = GET_RESPONSE_ENTITY)
ResponseEntity<Information> getInformation(String code);
}
上面的代码抛出以下异常:
Caused by: org.springframework.http.converter.HttpMessageConversionException:
Type definition error: [simple type, class org.springframework.http.ResponseEntity];
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `org.springframework.http.ResponseEntity`
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
杰克逊试图反序列化成ResponseEntity
而不是Information
类
我的目标是首先检查状态代码,并可选择检查Information
字段
是否可以从注释的方法返回 ResponseEntity @Gateway
?
解决方案
对您的问题的简短回答:这取决于该MyGateway
合同的实施。处理返回实际上不是网关(或任何接口 API)的责任。他们只定义合同。正确执行这样的合同已经是您的目标。
我的意思是 Spring Integration 及其 EIP 组件并没有比常规的 Java 程序设计和架构更进一步。这只是一个特例,这个合约是IntegrationFlow
一个实现。因此,问题不在于合同,而在于实施细节,在您的情况下这是一个 HTTP 调用。
所以,最好问这样的问题:
如何
ResponseEntity<Information>
从Http.outboundGateway()
带有杰克逊消息转换器的返回一个?
这就是为什么我在 Gitter 上问你这个 SO 线程以更好地了解发生了什么。您最初的问题具有误导性,并且与@MessagingGateway
. 我什至确信堆栈跟踪中有一些线索表明问题发生在RestTemplate
调用上,而不是在@MessagingGateway
.
现在试图帮助您解决您的明确问题。
有a时AbstractHttpRequestExecutingMessageHandler
不返回a :ResponseEntity
body
protected Object getReply(ResponseEntity<?> httpResponse) {
HttpHeaders httpHeaders = httpResponse.getHeaders();
Map<String, Object> headers = this.headerMapper.toHeaders(httpHeaders);
if (this.transferCookies) {
doConvertSetCookie(headers);
}
AbstractIntegrationMessageBuilder<?> replyBuilder;
MessageBuilderFactory messageBuilderFactory = getMessageBuilderFactory();
if (httpResponse.hasBody()) {
Object responseBody = httpResponse.getBody();
replyBuilder = (responseBody instanceof Message<?>)
? messageBuilderFactory.fromMessage((Message<?>) responseBody)
: messageBuilderFactory.withPayload(responseBody); // NOSONAR - hasBody()
}
else {
replyBuilder = messageBuilderFactory.withPayload(httpResponse);
}
replyBuilder.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE,
httpResponse.getStatusCode());
return replyBuilder.copyHeaders(headers);
}
只有在没有身体的情况下。在这种情况下,这意味着没有任何内容可以映射到payload
回复消息中,因此我们使用整个ResponseEntity
.
正如您在此代码片段中看到的,StatusCode
被映射到org.springframework.integration.http.HttpHeaders.STATUS_CODE
回复消息标头。
关于此事的文档中也有一些解释:https ://docs.spring.io/spring-integration/docs/current/reference/html/http.html#using-cookies 。
从这里开始,这意味着您expectedResponseType
只能作为一种Information
类型。RestTemplate
with HttpMessageConverts
it 确实不知道如何处理ResponseEntity
要映射的类型。
由于它可能Information
在响应中返回有效负载中的一个,或者可能返回ResponseEntity
一个空主体的整体,看起来您必须添加一些路由和转换逻辑,然后再返回一个ResponseEntity<Information>
作为对@MessagingGateway
调用的回复。或者您可以修改该网关合同并通过路由器或过滤器在集成流中真正实施状态代码检查 - 您的@MessagingGateway
消费者将摆脱 HTTP 的东西,如状态代码检查和标头转换。
尽管有一些选项AbstractHttpRequestExecutingMessageHandler
总是将整个ResponseEntity
作为有效负载返回可能没有什么坏处。随意提出一个 GH 问题,我们将考虑尽快实施它!
推荐阅读
- r - 计数观察之间的发生
- python - 无法在 Pycharm 中使用 Django 连接到 MongoDB
- php - 带有命名空间 PHP 的 SOAP Post 请求
- sql - 如何使用两个表进行 SQL 查询
- coordinates - xarray 获取非 NaN 变量值的最高坐标
- javascript - mongoose post init 挂钩中的并行保存错误。无法并行保存()同一个文档
- javascript - 代码错误-分割字符串并返回每个单词JS的长度
- docker - 在 Jenkinsfile 中运行 docker-compose up 会给我版本错误,而当我在服务器内部运行时它可以工作
- python - 根据时间戳小时删除 DataFrame 中的行
- android - 为什么 Android 设备上不显示 WeekDay 对象列表?Kotlin 列表视图