복붙노트

[SPRING] Spring Rest Template + Spring Web MVC를 이용한 다중 파일 업로드

SPRING

Spring Rest Template + Spring Web MVC를 이용한 다중 파일 업로드

다음 코드를 사용하여 RestTemplate을 사용하여 File을 업로드하려고합니다.

   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]

해결법

  1. ==============================

    1.Multipart File Upload는 코드 수정 후 RestTemplate을 사용하여 업로드하는 데 성공했습니다.

    Multipart File Upload는 코드 수정 후 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>
    
  2. ==============================

    2.여기에 제 작업 예제가 있습니다.

    여기에 제 작업 예제가 있습니다.

    @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);
    }
    
  3. ==============================

    3.오류가 발생하는 경우 다음과 같이 오류가 발생합니다.

    오류가 발생하는 경우 다음과 같이 오류가 발생합니다.

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

    파일이 클래스 경로에 없으면 절대 경로가 필요합니다.

  4. ==============================

    4.대부분의 경우, Spring MVC는 이미 다중 요청을 처리하기 때문에 web.xml에 MultipartFilter를 등록하는 것은 올바르지 않습니다. 그것은 심지어 필터의 javadoc로 작성되었습니다.

    대부분의 경우, 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 헤더를 제공하고 이름 및 파일 이름 지정자를 추가하는 것입니다. 그렇지 않으면 파트가 multipart 확인자에 의해 무시됩니다.

    그런 다음 컨트롤러 메서드는 다음 인수를 사용하여 업로드 된 파일을 처리 할 수 ​​있습니다.

    @RequestParam("filex") MultipartFile file
    

    희망이 도움이됩니다.

  5. ==============================

    5.컨텍스트 구성에서 빈을 선언하지 못한 경우 얻을 수있는 오류이므로 느낌을 기반으로 추가하십시오.

    컨텍스트 구성에서 빈을 선언하지 못한 경우 얻을 수있는 오류이므로 느낌을 기반으로 추가하십시오.

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="10000000"/>
    </bean>
    
  6. from https://stackoverflow.com/questions/26964688/multipart-file-upload-using-spring-rest-template-spring-web-mvc by cc-by-sa and MIT license