Spring Integration Multipart form使用JSON响应上传路由不起作用

时间:2015-09-01 20:46:57

标签: spring spring-integration

我在xml中有一个spring集成路由,它将进行Web服务调用(multipart / formdata)并需要以JSON格式返回响应。问题是我没有找到任何带有响应的多部分请求的良好样本SI路由。任何帮助都非常感谢。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
    http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">

<bean id="byteArrayHttpMessageConverter"
    class="org.springframework.http.converter.ByteArrayHttpMessageConverter">
</bean>

<bean id="formHttpMessageConverter"
    class="org.springframework.http.converter.FormHttpMessageConverter">
</bean>

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

<bean id="headerMapper"
    class="org.springframework.integration.http.support.DefaultHttpHeaderMapper">
    <property name="inboundHeaderNames" value="*" />
    <property name="outboundHeaderNames" value="*" />
    <property name="userDefinedHeaderPrefix" value="" />
</bean>


<int:channel id="http.request.submit.withfiles" />
<int:channel id="http.response.submit.withfiles" />

<int:channel id="http.router.route1.process.submit.withfiles" />
<int:channel id="http.router.route2.process.submit.withfiles" />

<int-http:inbound-gateway id="http.gateway.inbound.submit.withfiles"
    supported-methods="POST" header-mapper="headerMapper" 
    request-channel="http.request.submit.withfiles"
    reply-channel="http.response.submit.withfiles" path="/v1.0/file">
    <int-http:request-mapping consumes="multipart/form-data"
        produces="application/json" />
    <int-http:header name="routingCode" expression="headers['routingCode']" />

</int-http:inbound-gateway>

<int:header-value-router input-channel="http.request.submit.withfiles"
    header-name="routingCode" default-output-channel="http.router.route2.process.submit.withfiles">
    <int:mapping value="AB"
        channel="http.router.route1.process.submit.withfiles" />
    <int:mapping value="AC"
        channel="http.router.route2.process.submit.withfiles" />
    <int:mapping value="AD"
        channel="http.router.route2.process.submit.withfiles" />
    <int:mapping value="AE"
        channel="http.router.route2.process.submit.withfiles" />
    <int:mapping value="AF"
        channel="http.router.route2.process.submit.withfiles" />
</int:header-value-router>

<int-http:outbound-gateway
    id="http.gateway.outbound.route1.submit.withfiles" header-mapper="headerMapper"
    request-channel="http.router.route1.process.submit.withfiles"
    reply-channel="http.response.submit.withfiles"
    url="http://localhost:8080/myapplication1/file"
    http-method-expression="headers.http_requestMethod"
    expected-response-type="java.lang.String" charset="UTF-8" 
    reply-timeout="50000" />

<int-http:outbound-gateway
    id="http.gateway.outbound.route2.submit.withfiles" header-mapper="headerMapper"
    request-channel="http.router.route2.process.submit.withfiles"
    reply-channel="http.response.submit.withfiles" 
    url="http://localhost:8081/myapplication2/file"
    http-method="POST" charset="UTF-8" expected-response-type="java.lang.String"
    reply-timeout="50000">
</int-http:outbound-gateway>

错误讯息:

02-Sep-2015 13:36:07.300 SEVERE [http-nio-8080-exec-13] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [springServlet] in context with path [/my-switcher] threw exception [Request processing failed; nested exception is org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [http://localhost:8081/myapplication2/file]; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.integration.http.multipart.UploadedMultipartFile["inputStream"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.integration.http.multipart.UploadedMultipartFile["inputStream"])] with root cause
 com.fasterxml.jackson.databind.JsonMappingException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: org.springframework.integration.http.multipart.UploadedMultipartFile["inputStream"])
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.failForEmpty(UnknownSerializer.java:59)
    at com.fasterxml.jackson.databind.ser.impl.UnknownSerializer.serialize(UnknownSerializer.java:26)
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:575)
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:666)
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:156)
    at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:129)
    at com.fasterxml.jackson.databind.ObjectMapper.writeValue(ObjectMapper.java:2240)
    at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:231)
    at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:208)
    at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:331)
    at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:311)
    at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:301)
    at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:240)
    at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:87)
    at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:774)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:567)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:466)
    at org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandler.handleRequestMessage(HttpRequestExecutingMessageHandler.java:422)
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:286)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:245)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessageSendingTemplate.send(AbstractMessageSendingTemplate.java:95)
    at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:188)
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78)
    at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101)
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:97)
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77)
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:286)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:115)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:150)
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:45)
    at org.springframework.messaging.core.AbstractMessagingTemplate.sendAndReceive(AbstractMessagingTemplate.java:42)
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:331)
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:302)
    at org.springframework.integration.http.inbound.HttpRequestHandlingEndpointSupport.actualDoHandleRequest(HttpRequestHandlingEndpointSupport.java:492)
    at org.springframework.integration.http.inbound.HttpRequestHandlingEndpointSupport.doHandleRequest(HttpRequestHandlingEndpointSupport.java:389)
    at org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway.handleRequest(HttpRequestHandlingMessagingGateway.java:103)
    at org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter.handle(HttpRequestHandlerAdapter.java:51)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:610)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
    at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1517)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1474)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

更多详情:

实际的webservice(http://localhost:8081/myapplication2/file)执行多部分表单上载并将json消息返回给调用应用程序。所以我期望从这个SI路由是http-outbound网关将调用上面的webservice并做一个postupload并返回一个json响应。

我也是这样通过邮递员传递请求的。 enter image description here

2 个答案:

答案 0 :(得分:2)

目前不支持代理这样的multipart/form-data请求。

问题是Spring MVC已将原始表单数据转换为MultipartHttpInputMessage;它由入站网关进一步转换为MultiValueMap,其中文件部分是UploadedMultipartFile个实例。

出站网关不知道如何处理此对象;它不是转换器。

您可以尝试添加转换器,将有效负载中的UploadedMultiPartFile元素转换为Resource(s),或者编写自定义MessageConverter并将其注入出站网关。

我们看到越来越多的HTTP&#34;代理&#34;方案,所以请打开一个新功能&#39; JIRA issue

更好的是,考虑contributing解决方案!

修改

这是另一项工作 - 它更有效率。实际上,我们希望在入站网关中禁用多部分解码,并将多部分请求不变地传递给出站。

以下是如何做到的......

删除多部分解析器bean

添加自定义&#34; pass-thru&#34;多部分转换器到入站网关......

public class PassThroughMultiPartConverter implements HttpMessageConverter<byte[]> {

    @Override
    public boolean canRead(Class<?> clazz, MediaType mediaType) {
        if (!(byte[].class.isAssignableFrom(clazz))) {
            return false;
        }
        if (mediaType != null) {
            return MediaType.APPLICATION_FORM_URLENCODED.includes(mediaType)
                    || MediaType.MULTIPART_FORM_DATA.includes(mediaType);
        }
        else {
            return false;
        }
    }

    @Override
    public boolean canWrite(Class<?> clazz, MediaType mediaType) {
        return false;
    }

    @Override
    public List<MediaType> getSupportedMediaTypes() {
        return Collections.singletonList(MediaType.MULTIPART_FORM_DATA);
    }

    @Override
    public byte[] read(Class<? extends byte[]> clazz, HttpInputMessage inputMessage)
            throws IOException, HttpMessageNotReadableException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        FileCopyUtils.copy(inputMessage.getBody(), baos);
        return baos.toByteArray();
    }

    @Override
    public void write(byte[] t, MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {
        throw new UnsupportedOperationException();
    }

}

<int-http:inbound-gateway 
    ...
                                  request-payload-type="byte[]"
                                  message-converters="converter"
                                  merge-with-default-converters="false" />

<bean id="converter" class="foo.PassThroughMultiPartConverter" />

答案 1 :(得分:0)

谢谢Gary。

到目前为止,我通过更换&#39; http出站网关方式解决了这个问题。与服务激活者&#39;并通过服务激活器中引用的类中的REST模板调用Web服务。

<int:service-activator id="serviceactivator"        
    input-channel="http.router.process.submit.withfiles" 
    output-channel="http.response.submit.withfiles"     
    ref="multipartReceiver" method="receive"
    requires-reply="true" >
</int:service-activator>