41

I want to add an upload function to my spring boot application; this is my upload Rest Controller

package org.sid.web;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.sid.entities.FileInfo;

@RestController
public class UploadController {
  @Autowired
  ServletContext context;

  @RequestMapping(value = "/fileupload/file", headers = ("content-type=multipart/*"), method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
  public ResponseEntity<FileInfo> upload(@RequestParam("file") MultipartFile inputFile) {
    FileInfo fileInfo = new FileInfo();
    HttpHeaders headers = new HttpHeaders();
    if (!inputFile.isEmpty()) {
      try {
        String originalFilename = inputFile.getOriginalFilename();
        File destinationFile = new File(
            context.getRealPath("C:/Users/kamel/workspace/credit_app/uploaded") + File.separator + originalFilename);
        inputFile.transferTo(destinationFile);
        fileInfo.setFileName(destinationFile.getPath());
        fileInfo.setFileSize(inputFile.getSize());
        headers.add("File Uploaded Successfully - ", originalFilename);
        return new ResponseEntity<FileInfo>(fileInfo, headers, HttpStatus.OK);
      } catch (Exception e) {
        return new ResponseEntity<FileInfo>(HttpStatus.BAD_REQUEST);
      }
    } else {
      return new ResponseEntity<FileInfo>(HttpStatus.BAD_REQUEST);
    }
  }
}

but when testing this in postman with inserting http://localhost:8082/fileupload/file and adding a file to the body i got this error: "exception": org.springframework.web.multipart.support.MissingServletRequestPartException", "message": "Required request part 'file' is not present,

dariosicily
  • 4,239
  • 2
  • 11
  • 17
Wintern
  • 413
  • 1
  • 4
  • 5

8 Answers8

36

This is how your request in Postman should look like:

enter image description here

My sample code:

application.properties

#max file and request size 
spring.http.multipart.max-file-size=10MB
spring.http.multipart.max-request-size=11MB

Main Application Class:

Application.java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Rest controller class:

import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;


    @Controller
    @RequestMapping("/fileupload")
    public class MyRestController {

    @RequestMapping(value = "/file", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
        public @ResponseBody String myService(@RequestParam("file") MultipartFile file,
                @RequestParam("id") String id) throws Exception {

    if (!file.isEmpty()) { 

           //your logic
                        }
return "some json";

                }
    }

pom.xml

//...

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

....



<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>

//...
Tanmay Delhikar
  • 1,275
  • 11
  • 16
  • I'm trying the same test but i pass file as key and choose a file but the error is still there. That why i'm so confused – Wintern May 13 '17 at 15:51
  • 6
    I've added this to my app file : `@Bean public CommonsMultipartResolver multipartResolver() { CommonsMultipartResolver multipart = new CommonsMultipartResolver(); multipart.setMaxUploadSize(3 * 1024 * 1024); return multipart;} @Bean @Order(0) public MultipartFilter multipartFilter() { MultipartFilter multipartFilter = new MultipartFilter(); multipartFilter.setMultipartResolverBeanName("multipartReso‌​lver"); return multipartFilter; } ` – Wintern May 16 '17 at 12:19
  • 1
    Yes it did, because I have worked on this before using spring boot. – Tanmay Delhikar May 17 '17 at 14:11
  • @TanmayPlease can you show me your code because really i dont get this error. I've been blockin' on this for two weeks and i need this rest controller for my angular2 frontend part – Wintern May 17 '17 at 14:29
  • Thanks @Tanmay i'm waiting – Wintern May 17 '17 at 21:06
  • 1
    It's working now i just changed the head of the function, really i'm so grateful for your help. thanks – Wintern May 20 '17 at 16:28
  • 1
    @Tanmay Delhikar I have more or less your same sample client, and I am trying to write an integration test, unsuccessfully, since I have the same exception posted in this question: "org.springframework.web.multipart.support.MissingServletRequestPartException", "message": "Required request part 'file' is not present" Can you kindly write a simple example on how to invoke that WS? – marco Sep 29 '17 at 10:36
  • In my case it was the @Bean of MultipartResolver. Simply removed it and that did the work. – João Rodrigues Jul 20 '18 at 15:38
  • Thank you very much. It worked and seems like I wasn't giving the key name in RequestParam. It should be like this: @RequestParam("file") DataType variable – Raihanul Alam Hridoy Sep 27 '21 at 10:41
  • @marco in my case it works in mvc test if I don't specify any explicit bean for `MultipartResolver` and if I use `file` as name for the multipart data in test: `final var file = new MockMultipartFile("file", "filename.exe", "application/vnd.microsoft.portable-executable", "not suspicious".getBytes());` See: https://stackoverflow.com/a/21805186/2138953 – PAX Jun 16 '22 at 06:33
15

In your method you have specified like this
@RequestParam("file"). Hence it is expecting the key to be file. It is quite evident in the exception message. Use this name in the Key field in Postman when you upload file.
More information here integration test case and file upload

Community
  • 1
  • 1
pvpkiran
  • 25,582
  • 8
  • 87
  • 134
  • 5
    thanks for your help, but unfortunely thats what i was doing. I passed file as a key and upload the file and it's not working. – Wintern May 13 '17 at 15:51
11

I also had similar issue and was getting the error request part file not present. But I later realized that I have this code in my application which was causing problem:

@Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new 
        CommonsMultipartResolver();
        multipartResolver.setMaxUploadSize(1000000000);
        return multipartResolver;
      }

I removed this and it started working for both RequestPart and RequestParam. See the related issue below:

https://forum.predix.io/questions/22163/multipartfile-parameter-is-not-present-error.html

8

Except for other posted answers, the problem might be realated to missing multipart support for the servlet handling the request (spring's DispatcherServlet in case of Spring's app).

This can be fixed by adding multipart support to dispatcher servlet in web.xml declaration or during initialization (in case of annotation-based config)

a) web-xml based config

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          version="3.0">

 <servlet>
   <servlet-name>dispatcher</servlet-name>
   <servlet-class>
     org.springframework.web.servlet.DispatcherServlet
   </servlet-class>
   <init-param>
     <param-name>contextConfigLocation</param-name>
     <param-value>/WEB-INF/spring/dispatcher-config.xml</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
   <multipart-config>
        <max-file-size>10485760</max-file-size>
        <max-request-size>20971520</max-request-size>
        <file-size-threshold>5242880</file-size-threshold>
    </multipart-config>
 </servlet>

</web-app>

b) for annotation-based configuration this would be following:

public class AppInitializer implements WebApplicationInitializer { 

@Override 
public void onStartup(ServletContext servletContext) { 
    final AnnotationConfigWebApplicationContext appContext = new AnnotationConfigWebApplicationContext(); 

    final ServletRegistration.Dynamic registration = servletContext.addServlet("dispatcher", new DispatcherServlet(appContext)); 
    registration.setLoadOnStartup(1); 
    registration.addMapping("/"); 

    File uploadDirectory = new File(System.getProperty("java.io.tmpdir"));                  
    MultipartConfigElement multipartConfigElement = new  MultipartConfigElement(uploadDirectory.getAbsolutePath(), 100000, 100000 * 2, 100000 / 2); 

    registration.setMultipartConfig(multipartConfigElement);
} }

Then we need to provide multipart resolver which can resolve files sent as multipart-request. For annotation config this can be done in following way:

@Configuration
public class MyConfig {

@Bean
public MultipartResolver multipartResolver() {
    return new StandardServletMultipartResolver();
}
}

For xml-based spring configuration you need to add this bean to the context via tag declaration declaration:

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" /> 

Alternatively to spring's standard multipart resolver you can use implementation from commons. This way however extra dependency is required:

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.3</version>
</dependency>

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000"/>
</bean>
Community
  • 1
  • 1
walkeros
  • 4,736
  • 4
  • 35
  • 47
0

I had similar issue with error Could not resolve parameter [0] in public org.springframework.http.ResponseEntity... Required request part 'file' is not present and tried many things but one change resolved this issue.

Had to update

// old
@RequestParam("file") MultipartFile inputFile


// new
@RequestParam(value = "file") MultipartFile inputFile
Laurel
  • 5,965
  • 14
  • 31
  • 57
0

In my case, i have multi module project as;

core > api > admin

Admin and api are parent of core module.

Core/ImageController:

@RequestMapping(value = "/upload/image", method = RequestMethod.POST)
    public ResponseEntity uploadBanner(@RequestParam(value = "file", required = 
 false) MultipartFile bannerFile){...}

AdminApplicationInitializer:

@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
    return application.sources(AdminApplicationInitializer.class);
}

@Bean
public MultipartResolver multipartResolver() {
    CommonsMultipartResolver resolver = new CommonsMultipartResolver();
    //100MB
    resolver.setMaxUploadSize(100 * (long) 1024 * 1024);
    return resolver;
}

@Bean
public MultipartConfigElement multipartConfigElement() {
    MultipartConfigFactory factory = new MultipartConfigFactory();
    factory.setMaxFileSize(DataSize.ofMegabytes(200L));
    factory.setMaxRequestSize(DataSize.ofMegabytes(200L));
    return factory.createMultipartConfig();
}

When i tried to upload file from api module with core service "/upload/image". I had get an error : "Required request part 'file' is not present". Cause of ApiInitializer had not configuration like AdminInitializer.

The Solution : i added multipartResolver() and multipartConfigElement() method to ApiApplicationInitializer.Then it worked.

fatih yavuz
  • 89
  • 10
0

Use @RequestPart("file") instead of @RequestParam("file").

Eyoab
  • 725
  • 9
  • 10
0

Thanks, @Eyoab, it works for me.

I had the same problem with feign client. I have one endpoint to upload a file that accepts the Multipart file.

Main upload endpoint

I was calling the above endpoint using feign client. (feign client method)

feign client caller method

Now, you can see in the first image, the endpoint accepts the file as a @RequestParam. and in the second image I use @RequestPart in my feign client call. I helps me to resolve the issue.