Spring Boot multipartfile is always null

I am using Spring Boot version = '1.4.0.RC1' with Spring Boot Stormpath 1.0.2.

I am trying to use multi-page file upload, but MultipartFile is always null in the controller.

When I use @RequestPart ("file"), information: "status":400,"error":"Bad Request","exception":"org.springframework.web.multipart.support.MissingServletRequestPartException","message":"Required request part 'file' is not present"

When I use @RequestPart (name = "file", required = false), this part is always null.

However, if I add the HttpServletRequest argument to the controller, I can get part of the file directly from the request, so I know that it is actually present.

This is the controller and in the code below checkNotNull(part) always succeeds, and checkNotNull(imageFile) always fails:

 @PostMapping("{username}/profilePhoto") public ResponseEntity<?> saveProfilePhoto(@PathVariable("username") String username, @RequestPart(name = "file", required = false) MultipartFile imageFile, HttpServletRequest request) { try { Part part = request.getPart("file"); checkNotNull(part); checkNotNull(imageFile); } catch (IOException | ServletException ex) { throw InternalServerErrorException.create(); } // Transfer the multipart file to a temp file File tmpFile; try { tmpFile = File.createTempFile(TMP_FILE_PREFIX, null); imageFile.transferTo(tmpFile); } catch (IOException ex) { log.error("Failed to create temp file", ex); throw InternalServerErrorException.create(); } // Execute the use case updateUserProfilePhoto.execute(username, tmpFile); // Delete the temp file FileUtils.deleteQuietly(tmpFile); return ResponseEntity.status(HttpStatus.CREATED).build(); } 

My integration test uses a modification:

 @Multipart @POST("users/{username}/profilePhoto") Call<Void> uploadProfilePhoto(@Path("username") String username, @Part("file") RequestBody profilePhoto); ... @Test public void saveProfilePhoto_shouldSavePhoto() throws IOException { // Given String usernamme = usernames[0]; Resource testImageResource = context.getResource("classpath:images/test_image.jpg"); File imageFile = testImageResource.getFile(); RequestBody body = RequestBody.create(okhttp3.MediaType.parse("image/*"), imageFile); // When Response<Void> response = getTestApi().uploadProfilePhoto(usernamme, body).execute(); // Then assertThat(response.code()).isEqualTo(201); } 

I use auto-tuning, so my only custom configuration class configures the Stormpath:

 @Configuration public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.apply(stormpath()); } } 

UPDATE: This is an outgoing request. I'm not sure how to enable logging in the multiprocessor resolver itself.

 2016-08-18 14:44:14.714 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : --> POST http://localhost:8080/users/user1/profilePhoto http/1.1 2016-08-18 14:44:14.714 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : Content-Type: multipart/form-data; boundary=fe23ef21-3413-404c-a260-791c6921b2c6 2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : Content-Length: 181212 2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : Accept: application/json 2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : Authorization: Bearer [token] 2016-08-18 14:44:14.715 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : 2016-08-18 14:44:14.735 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : --fe23ef21-3413-404c-a260-791c6921b2c6 Content-Disposition: form-data; name="file" Content-Transfer-Encoding: binary Content-Type: image/* Content-Length: 180999 file data --fe23ef21-3413-404c-a260-791c6921b2c6-- 2016-08-18 14:44:14.762 DEBUG 13088 --- [ main] ctserver.web.testutil.TestConfig$1 : --> END POST (181212-byte body) 

Any ideas on what's going on?

+6
source share
4 answers

I found out that the problem was how I created my request using Retrofit.

Spring multipart resolver requires that the file name for the file be present in the content-disposition field of this part. Without this, it does not add the file to a multi-page request.

According to the information found here: https://futurestud.io/blog/retrofit-2-how-to-upload-files-to-server , my API should be:

 @Multipart @POST("users/{username}/profilePhoto") Call<Void> uploadProfilePhoto(@Path("username") String username, @Part MultipartBody.Part profilePhoto); 

And then when making a call in my test:

 // Given String usernamme = usernames[0]; Resource testImageResource = context.getResource("classpath:images/test_image.jpg"); File imageFile = testImageResource.getFile(); RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), imageFile); MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", imageFile.getName(), requestFile); // When Response<Void> response = testApi.uploadProfilePhoto(usernamme, filePart).execute(); 
+1
source

You need to enable Spring multi-user resolver , since by default Spring does not allow multi-user capability.

By default, Spring does not do multiprocessing, as some developers want to process multipartes themselves. Enable Spring multipart by adding a multi-threaded converter to the web application context.

In your configuration class, you would like to add the following bean:

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

* Update * Since my previous answer was incorrect based on comments. Here is an updated example that I was able to successfully execute.

 @SpringBootApplication public class StackoverflowWebmvcSandboxApplication { public static void main(String[] args) { SpringApplication.run(StackoverflowWebmvcSandboxApplication.class, args); } @Controller public class UploadPhoto { @PostMapping("{username}/profilePhoto") public ResponseEntity<String> saveProfilePhoto(@PathVariable("username") String username, @RequestPart(name = "file", required = false) MultipartFile imageFile, HttpServletRequest request) { String body = "MultipartFile"; if (imageFile == null) { body = "Null MultipartFile"; } return ResponseEntity.status(HttpStatus.CREATED).body(body); } } } 

This is a very simple test without special materials. Then I created a postman request, and here is an example of a bending call:

 curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 17e5e6ac-3762-7d45-bc99-8cfcb6dc8cb5" -H "Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW" -F " file=@ " "http://localhost:8080/test/profilePhoto" 

The answer was MultipartFile , meaning it was not null, and doing debugging on this line showed that the variable was filled with the image I was loading.

+2
source

You need to enable Spring multi-user resolver , since by default Spring does not allow multi-user capability.

By default, Spring does not do multiprocessing, as some developers want to process multipartes themselves. Enable Spring multipart by adding a multi-threaded converter to the web application context.

In your configuration class, you would like to add the following bean:

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

Since Spring boot 1.4+ uses servlet 3.0+, we can use StandardServletMultipartResolver instead of the classic CommonsMultipartResolver

0
source

Please refer to my answer at this url: Spring Downloading a multi-page download to get a null file object

Basically you need to avoid Spring's default configuration for multipart and avoid setting the content type or border in the request header.

0
source

All Articles