当前位置: 首页 > 知识库问答 >
问题:

Spring集成多部分表单上载JSON响应不工作的路由

裴焱
2023-03-14

我有一个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出站网关将调用上述webservice,并执行postpload并返回json响应。

共有2个答案

湛鸿
2023-03-14

谢谢Gary。

到目前为止,我解决了这个问题,将“http出站网关方式”替换为“service activator”,并通过service activator中引用的类内的REST模板调用webservice。

<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>
郭璞
2023-03-14

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

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

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

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

我们看到越来越多的HTTP“代理”场景,所以请打开一个“新功能”JIRA问题。

更好的是,考虑贡献一个解决方案!

编辑:

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

下面是如何做到这一点。。。

删除多部分解析器bean

向入站网关添加自定义“直通”多部分转换器...

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" />
 类似资料:
  • 通常,我需要通过JSOUP将数据以响应multipart/form-data的形式发送到站点 作为一个示例,使用一个简单的窗体来sgeniriruet您的查询。 <表单操作=«localhost:8000»方法=«post»enctype=»多部分/表单数据» <输入类型=»文本»名称=»文本»值=»文本默认值» <输入类型=»文件»名称=»文件1» <输入类型=»文件»名称=»文件2» 提交 通

  • 我想知道是否可以有一个postendpoint来接受包含multipartfile和其他数据的json负载。例如,我的身体对象看起来像: 另一个相关的问题是,在用于上传文件https://spring.io/guides/gs/uploading-files/的springboot文档示例中,文件是请求路径的一部分,而不是有效负载。这对我来说似乎很奇怪,那么有没有一种方法可以将文件绑定到请求体?

  • 此函数工作正常。当当前工作表不是Google表单响应工作表时。我正在使用(每分钟)触发器 图像:沙子数据(主数据)表至(共享数据1)表 我正在寻找一个,当用户提交的谷歌表格的状态是(支付),数据应该在第二页,这是(shareData1) 这里的问题是,当我使用谷歌表单响应表时,这个函数将不再工作。它显示了一个错误。错误图像 在降级的错误图像中,我手动运行此函数,相同的错误显示在AppScript面

  • 如果我从application.properties中删除server.context-path=/api/v1。然后,对http://localhost:8080/test的HEAD请求按预期工作。 谢谢你的帮助,马丁

  • 位卡在这个上,需要上传图像和json一起使用多部分形式...不知道如何发送内容类型标头或上传图像...认为我需要转换为blob...目前我只是发送我从文件输入字段中获得的数据。 任何建议都很好谢谢

  • 我无法编写将文件上载到控制器的测试。 在这一问题发生的所有事件中,我没有看到任何事情对我有效。 我可以从我的webapp上传和存储文件,但是当我运行测试时,控制器中的文件总是空的 应用程序 控制器 测验