upload file springboot Required request part '

2020-02-09 01:06发布

问题:

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",

回答1:

This is how your request in Postman should look like:

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>

//...


回答2:

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



回答3:

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>


回答4:

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