web-dev-qa-db-fra.com

Téléchargement de fichier en plusieurs parties à l'aide du modèle Spring Rest + Spring Web MVC

J'essaye de télécharger un fichier en utilisant RestTemplate avec le code suivant.

   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);

J'ai le bean MultipartResolver et le code du contrôleur est

@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
}

Et j'obtiens l'exception suivante

 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]
33
shazin

Le téléchargement de fichier en plusieurs parties a fonctionné après la modification du code suivant en téléchargement à l'aide de 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);

Et ajouter MultipartFilter à web.xml

    <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>
46
shazin

Voici mon exemple de travail

@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);
}
15

Dans la plupart des cas d'utilisation, enregistrer MultipartFilter dans le fichier web.xml n'est pas correct, car Spring MVC effectue déjà le travail de traitement de votre demande multipart. C'est même écrit dans le javadoc du filtre.

Sur le serveur, définissez un bean multipartResolver dans le contexte de votre application:

@Bean
public CommonsMultipartResolver multipartResolver(){
    CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
    commonsMultipartResolver.setDefaultEncoding("utf-8");
    commonsMultipartResolver.setMaxUploadSize(50000000);
    return commonsMultipartResolver;
}

Côté client, voici comment préparer la demande pour une utilisation avec l'API Spring RestTemplate:

    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);

L'important est en réalité de fournir un en-tête Content-disposition en utilisant la casse exacte et en ajoutant des spécificateurs de nom et de nom de fichier, sinon votre partie sera ignorée par le résolveur en plusieurs parties.

Ensuite, votre méthode de contrôleur peut gérer le fichier téléchargé avec l'argument suivant:

@RequestParam("filex") MultipartFile file

J'espère que cela t'aides.

10
PA Lemire

Pour ceux qui obtiennent l'erreur en tant que:

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.

Il peut être résolu en utilisant le

LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("file", new FileSystemResource(file));

Si le fichier n'est pas présent dans le chemin d'accès aux classes, un chemin absolu est requis.

6
RAX

Plus basé sur le sentiment, mais c'est l'erreur que vous obtiendriez si vous manquiez pour déclarer un bean dans la configuration du contexte, alors essayez d'ajouter

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="10000000"/>
</bean>
1
Master Slave