次のコードでRestTemplateを使用してファイルをアップロードしようとしています。
MultiValueMap<String, Object> multipartMap = new LinkedMultiValueMap<>();
multipartMap.add("file", new ClassPathResource(file));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("multipart", "form-data"));
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<MultiValueMap<String, Object>>(multipartMap, headers);
System.out.println("Request for File Upload : " + request);
ResponseEntity<byte[]> result = template.get().exchange(
contextPath.get() + path, HttpMethod.POST, request,
byte[].class);
MultipartResolver
Beanがあり、コントローラーコードは
@RequestMapping(value = "/{id}/image", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
@Transactional(rollbackFor = Exception.class)
public byte[] setImage(@PathVariable("id") Long userId,
@RequestParam("file") MultipartFile file) throws IOException {
// Upload logic
}
そして、私は次の例外を取得します
org.springframework.web.bind.MissingServletRequestParameterException: Required MultipartFile parameter 'file' is not present
at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.Java:255) ~[spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.Java:95) ~[spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.Java:79) ~[spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.Java:157) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.Java:124) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.Java:104) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.Java:749) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.Java:689) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.Java:83) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.Java:938) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.Java:870) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.Java:961) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.Java:863) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:646) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.Java:837) [spring-webmvc-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.Java:727) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:303) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.springframework.web.filter.ShallowEtagHeaderFilter.doFilterInternal(ShallowEtagHeaderFilter.Java:80) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:241) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.Java:77) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:241) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.Java:67) [log4j-web-2.0.2.jar:2.0.2]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:241) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:330) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.Java:118) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.Java:84) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.Java:113) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.Java:103) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.Java:113) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.Java:154) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.Java:45) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at m.m.m.AbstractPreAuthenticatedProcessingFilter.doFilter(UapAbstractPreAuthenticatedProcessingFilter.Java:109) [classes/:?]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.Java:50) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.Java:107) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.Java:87) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.Java:342) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.Java:192) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.Java:160) [spring-security-web-3.2.5.RELEASE.jar:3.2.5.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.Java:344) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.Java:261) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.Apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.Java:241) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.Java:208) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.Java:220) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.StandardContextValve.invoke(StandardContextValve.Java:122) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.StandardHostValve.invoke(StandardHostValve.Java:171) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.Java:102) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.Java:950) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.Java:116) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.Java:408) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.Java:1040) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.Java:607) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at org.Apache.Tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.Java:314) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1145) [?:1.7.0_67]
at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:615) [?:1.7.0_67]
at org.Apache.Tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.Java:61) [Tomcat-embed-core-7.0.54.jar:7.0.54]
at Java.lang.Thread.run(Thread.Java:745) [?:1.7.0_67]
マルチパートファイルアップロードは、RestTemplateを使用してアップロードするようにコードを変更した後に機能しました
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", new ClassPathResource(file));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<LinkedMultiValueMap<String, Object>>(
map, headers);
ResponseEntity<String> result = template.get().exchange(
contextPath.get() + path, HttpMethod.POST, requestEntity,
String.class);
そして、web.xmlにMultipartFilterを追加します
<filter>
<filter-name>multipartFilter</filter-name>
<filter-class>org.springframework.web.multipart.support.MultipartFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>multipartFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
ここに私の実例があります
@RequestMapping(value = "/api/v1/files/upload", method =RequestMethod.POST)
public ResponseEntity<?> upload(@RequestParam("files") MultipartFile[] files) {
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<String> tempFileNames = new ArrayList<>();
String tempFileName;
FileOutputStream fo;
try {
for (MultipartFile file : files) {
tempFileName = "/tmp/" + file.getOriginalFilename();
tempFileNames.add(tempFileName);
fo = new FileOutputStream(tempFileName);
fo.write(file.getBytes());
fo.close();
map.add("files", new FileSystemResource(tempFileName));
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);
String response = restTemplate.postForObject(uploadFilesUrl, requestEntity, String.class);
} catch (IOException e) {
e.printStackTrace();
}
for (String fileName : tempFileNames) {
File f = new File(fileName);
f.delete();
}
return new ResponseEntity<Object>(HttpStatus.OK);
}
ほとんどのユースケースでは、Spring MVCはすでにマルチパートリクエストの処理を行っているため、web.xmlにMultipartFilterを登録するのは正しくありません。フィルターのjavadocにも記述されています。
サーバー側で、アプリコンテキストでmultipartResolver Beanを定義します。
@Bean
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
クライアント側で、Spring RestTemplate APIで使用するリクエストを準備する方法は次のとおりです。
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
LinkedMultiValueMap<String, String> pdfHeaderMap = new LinkedMultiValueMap<>();
pdfHeaderMap.add("Content-disposition", "form-data; name=filex; filename=" + file.getOriginalFilename());
pdfHeaderMap.add("Content-type", "application/pdf");
HttpEntity<byte[]> doc = new HttpEntity<byte[]>(file.getBytes(), pdfHeaderMap);
LinkedMultiValueMap<String, Object> multipartReqMap = new LinkedMultiValueMap<>();
multipartReqMap.add("filex", doc);
HttpEntity<LinkedMultiValueMap<String, Object>> reqEntity = new HttpEntity<>(multipartReqMap, headers);
ResponseEntity<MyResponse> resE = restTemplate.exchange(uri, HttpMethod.POST, reqEntity, MyResponse.class);
重要なことは、正確な大文字小文字を使用してContent-dispositionヘッダーを提供し、名前とファイル名の指定子を追加することです。そうしないと、マルチパートリゾルバーによってパーツが破棄されます。
その後、コントローラーメソッドは、アップロードされたファイルを次の引数で処理できます。
@RequestParam("filex") MultipartFile file
お役に立てれば。
次のようなエラーが発生している場合:
I/O error on POST request for "anothermachine:31112/url/path";: class path
resource [fileName.csv] cannot be resolved to URL because it does not exist.
を使用して解決できます
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", new FileSystemResource(file));
ファイルがクラスパスに存在せず、絶対パスが必要な場合。
もっと感じに基づいていますが、これはコンテキスト設定でBeanを宣言するのを忘れた場合に取得するエラーですので、追加してみてください
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000"/>
</bean>