使用 RestTemplate 请求将多部分文件作为 POST 参数发送
我正在使用 Spring 3 和 RestTemplate。我基本上有两个应用程序,其中一个必须将值发布到另一个应用程序。通过休息模板。
当要发布的值是字符串时,它工作得很好,但是当我必须发布混合和复杂的参数(如 MultipartFiles)时,我会收到转换器异常。
例如,我有这个:
App1 - PostController:
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute UploadDTO pUploadDTO,
BindingResult pResult) throws URISyntaxException, IOException {
URI uri = new URI("http://localhost:8080/app2/file/receiver");
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
mvm.add("param1", "TestParameter");
mvm.add("file", pUploadDTO.getFile()); // MultipartFile
Map result = restTemplate.postForObject(uri, mvm, Map.class);
return "redirect:postupload";
}
另一方面...我有另一个 Web 应用程序 (App2),它从 App1 接收参数。
App2 - ReceiverController
@RequestMapping(value = "/receiver", method = { RequestMethod.POST })
public String processUploadFile(
@RequestParam(value = "param1") String param1,
@RequestParam(value = "file") MultipartFile file) {
if (file == null) {
System.out.println("Shit!... is null");
} else {
System.out.println("Yes!... work done!");
}
return "redirect:postupload";
}
我的 application-context.xml:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
这是我在执行 RestTemplate 的 postForObject 时遇到的异常堆栈...
org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.web.multipart.commons.CommonsMultipartFile]
at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:292)
at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:252)
at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:242)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:194)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:415)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:294)
at com.yoostar.admintool.web.UploadTestController.create(UploadTestController.java:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:774)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:619)
所以我的问题是:
- 是否可以发送 MultipartFile通过 RestTemplate 使用 POST?
- 我必须使用一些特定的转换器来发送此类对象吗?我的意思是我的配置中是否有一些 MultipartFileHttpMessageConverter 可以使用?
I am working with Spring 3 and RestTemplate. I have basically, two applications and one of them have to post values to the other app. through rest template.
When the values to post are Strings, it's work perfect, but when i have to post mixed and complex params (like MultipartFiles) i get an converter exception.
As example, i have this:
App1 - PostController:
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute UploadDTO pUploadDTO,
BindingResult pResult) throws URISyntaxException, IOException {
URI uri = new URI("http://localhost:8080/app2/file/receiver");
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<String, Object>();
mvm.add("param1", "TestParameter");
mvm.add("file", pUploadDTO.getFile()); // MultipartFile
Map result = restTemplate.postForObject(uri, mvm, Map.class);
return "redirect:postupload";
}
On the other side... i have another web application (App2) that receives the parameters from the App1.
App2 - ReceiverController
@RequestMapping(value = "/receiver", method = { RequestMethod.POST })
public String processUploadFile(
@RequestParam(value = "param1") String param1,
@RequestParam(value = "file") MultipartFile file) {
if (file == null) {
System.out.println("Shit!... is null");
} else {
System.out.println("Yes!... work done!");
}
return "redirect:postupload";
}
My application-context.xml:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>104857600</value>
</property>
<property name="maxInMemorySize">
<value>4096</value>
</property>
</bean>
Here is the stack of the exception that i am getting when i do the postForObject of the RestTemplate...
org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.web.multipart.commons.CommonsMultipartFile]
at org.springframework.http.converter.FormHttpMessageConverter.writePart(FormHttpMessageConverter.java:292)
at org.springframework.http.converter.FormHttpMessageConverter.writeParts(FormHttpMessageConverter.java:252)
at org.springframework.http.converter.FormHttpMessageConverter.writeMultipart(FormHttpMessageConverter.java:242)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:194)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:415)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:294)
at com.yoostar.admintool.web.UploadTestController.create(UploadTestController.java:86)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:175)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:421)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:409)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:774)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:857)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:619)
So my questions are:
- Is it possible to send MultipartFile through RestTemplate using POST?
- Are there some specific converters that I have to use to send this type of objects? I mean is there some MultipartFileHttpMessageConverter to use in my configuration?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
解决此问题的一种方法是使用 ByteArrayResource,而无需使用需要磁盘上文件的 FileSystemResource,这样您就可以在帖子中发送字节数组(此代码适用于 Spring 3.2.3):
我重写 getFilename ByteArrayResource 的,因为如果我不这样做,我会得到一个空指针异常(显然这取决于java激活.jar是否在类路径上,如果是,它将使用文件名来尝试确定内容类型)
A way to solve this without needing to use a FileSystemResource that requires a file on disk, is to use a ByteArrayResource, that way you can send a byte array in your post (this code works with Spring 3.2.3):
I override the getFilename of the ByteArrayResource because if I don't I get a null pointer exception (apparently it depends on whether the java activation .jar is on the classpath, if it is, it will use the file name to try to determine the content type)
前几天我也遇到了同样的问题。谷歌搜索让我来到这里和其他几个地方,但没有一个给出这个问题的解决方案。我最终将上传的文件(MultiPartFile)保存为 tmp 文件,然后使用 FileSystemResource 通过 RestTemplate 上传它。这是我使用的代码,
我仍在寻找更优雅的解决方案来解决这个问题。
I also ran into the same issue the other day. Google search got me here and several other places, but none gave the solution to this issue. I ended up saving the uploaded file (MultiPartFile) as a tmp file, then use FileSystemResource to upload it via RestTemplate. Here's the code I use,
I am still looking for a more elegant solution to this problem.
我最近为这个问题苦苦挣扎了3天。客户端发送请求的方式可能不是原因,服务器可能未配置为处理多部分请求。这是我必须做的才能使其正常工作:
pom.xml - 添加了 commons-fileupload 依赖项(如果您不使用依赖项管理(例如 maven),则下载 jar 并将其添加到您的项目中)
web.xml - 添加多部分过滤器和映射
app-context.xml - 添加多部分解析器
您的控制器
您的客户端
这应该可以解决问题。我添加了尽可能多的信息,因为我花了几天时间将整个问题的零碎内容拼凑在一起,我希望这会有所帮助。
I recently struggled with this issue for 3 days. How the client is sending the request might not be the cause, the server might not be configured to handle multipart requests. This is what I had to do to get it working:
pom.xml - Added commons-fileupload dependency (download and add the jar to your project if you are not using dependency management such as maven)
web.xml - Add multipart filter and mapping
app-context.xml - Add multipart resolver
Your Controller
Your client
That should do the trick. I added as much information as possible because I spent days, piecing together bits and pieces of the full issue, I hope this will help.
我们的一个人对文件系统资源做了类似的事情。
尝试
假设您的 .getFile 的输出是一个 java File 对象,它应该与我们的一样工作,其中
只有一个 File 参数。
One of our guys does something similar with the filesystemresource.
try
assuming the output of your .getFile is a java File object, that should work the same as ours, which
just has a File parameter.
您可以简单地使用
MultipartHttpServletRequest
示例:
其中
request.getParameter()
中的参数名称必须与相应的前端名称相同。请注意,该文件是通过
getFile()
提取的,而其他附加参数是通过getParameter()
提取的You may simply use
MultipartHttpServletRequest
Example:
Where parameters names in
request.getParameter()
must be same with corresponding frontend names.Note, that file extracted via
getFile()
while other additional parameters extracted viagetParameter()
我必须做@Luxspes 上面做的同样的事情..并且我正在使用 Spring 4.2.6。花了相当多的时间弄清楚为什么 ByteArrayResource 从客户端传输到服务器,但服务器无法识别它。
I had to do the same thing that @Luxspes did above..and I am using Spring 4.2.6. Spent quite some time figuring why is ByteArrayResource getting transferred from client to server, but the server is not recognizing it.
如果您必须发送一个由需要使用特定 HttpMessageConverter 进行转换的对象组成的多部分文件,并且无论您尝试什么,您都会收到“没有合适的 HttpMessageConverter”错误,您可能需要尝试使用这:
这通过一个自定义对象解决了我的问题,该对象与文件(在我的例子中是 FileSystemResource 的实例)一起,是我需要发送的多部分文件的一部分。
我尝试使用 TrueGuidance 的解决方案(以及在网络上找到的许多其他解决方案)无济于事,然后我查看了 FormHttpMessageConverter 的源代码代码并尝试了这个。
If you have to send a multipart file that is composed, among other things, by an Object that needs to be converted with a specific HttpMessageConverter and you get the "no suitable HttpMessageConverter" error no matter what you try, you may want to try with this:
This solved the problem for me with a custom Object that, together with a file (instanceof FileSystemResource, in my case), was part of the multipart file I needed to send.
I tried with TrueGuidance's solution (and many others found around the web) to no avail, then I looked at FormHttpMessageConverter's source code and tried this.
您必须将 FormHttpMessageConverter 添加到 applicationContext.xml 才能发布多部分文件。
请参阅 http:// docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/FormHttpMessageConverter.html 例如。
You have to add the FormHttpMessageConverter to your applicationContext.xml to be able to post multipart files.
See http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/FormHttpMessageConverter.html for examples.
我遇到了这个问题,并找到了比使用 ByteArrayResource 更简单的解决方案。
只需执行
即可,无需搞乱文件系统或字节数组。
I had this issue and found a much simpler solution than using a ByteArrayResource.
Simply do
It works, and no messing around with the file system or byte arrays.