57

I have a Controller like this and I want to submit a form with file uploading as well as some form data like label as shown below. Also, I want to do that using @RequestBody so I can use the @Valid annotation on the wrapper as more variables will be added.

public @ResponseBody WebResponse<Boolean> updateEUSettings(
    final Locale locale,
    @Validated @ModelAttribute final EUPSettingsWrapper endUserPortalSettingsWrapper) {
}

And my wrapper is:

public class EUPSettingsWrapper {

    private String label;
    private MultipartFile logo;
// getter , setters..etc...
}

But I would like to convert it into a @RequestBody from ModelAttributes.

The way I'm trying is by having the file upload separated as request parameter like this:

public @ResponseBody WebResponse<Boolean> updateEUSettings(
    final Locale locale,
    @Validated @RequestBody final EUPSettingsWrapper endUserPortalSettingsWrapper, 
    @RequestParam(value = "file1", required = true) final MultipartFile logo) {

    endUserPortalSettingsWrapper.setLogo(logo);

    // ...
}

In my mock MVC, I am setting:

getMockMvc().perform(fileUpload(uri).file(logo)
                        .accept(MediaType.APPLICATION_JSON)
                        .content(JSONUtils.toJSON(wrapper))
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                        .andExpect(status().isOk());

But I'm getting an error like this which says:

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data' not supported

Does anyone have a good idea of how Multipart file uploads can be used with @RequestBody? Anything I am doing wrong above?

1

5 Answers 5

55

You can actually simplify your life here since all you are doing is submitting a form that contains some fields and file. You don't need @RequestBody for what you are trying to do. You can use regular Spring MVC features, so your controller method would look like:

@ResponseBody
public WebResponse<Boolean> updateEUSettings(
     Locale locale, 
     @Valid EUPSettingsWrapper endUserPortalSettingsWrapper, 
     @RequestParam(value = "file1", required = true) MultipartFile logo
) {


}

The client that submits the request to this controller will need to have a form with enctype="multipart/form-data".

In your Spring MVC test you would write something like this:

getMockMvc().perform(fileUpload(uri).file("file1", "some-content".getBytes()) 
                        .param("someEuSettingsProperty", "someValue")
                        .param("someOtherEuSettingsProperty", "someOtherValue")
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.MULTIPART_FORM_DATA))
                        .andExpect(status().isOk());
Sign up to request clarification or add additional context in comments.

3 Comments

Very interesting, but how does the data looks in the Ajax POST request? Do you create a Object to represent EUPSettingsWrapper and a FormData to represent the MultipartFile and then you assign the FormData to, let's say, obj.logo ? Also do you JSON.stringify() that obj or not?
Unfortunately I don't really remember since the answer is pretty old :)
Another way is encode your file bytes into base64 and then generated string can be use in request json, generally this patten is not recommended but for special schenarios: {"name":"aa","logo":encodeBase64(fileByteArray)} for encoding follow given url: stackoverflow.com/questions/22172604/…
13

I couldn't find a way to use @RequestBody.

However, you can do something like this:

@RequestMapping(value = "/uploadStuff", method = RequestMethod.POST)
public MyViewDto doStuff(@RequestPart("json") @Valid MyDto dto,
                         @RequestPart("file") MultipartFile file) { ... }

You can test it like this:

MockMultipartFile jsonFile = new MockMultipartFile("json", "",
            "application/json", "{}".getBytes());
MockMultipartFile dataFile = new MockMultipartFile("file", "foo.zip", "application/octet-stream", bytes);

mockMvc.perform(fileUpload("/uploadStuff")
            .file(dataFile)
            .file(jsonFile))
            .andExpect(status().isOk());

1 Comment

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
12

Please add the following bean in your spring-servlet.xml to add the support for multipart request.

<bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

Also don't forget to add the dependency for commons-fileupload jar

1 Comment

Also see this answer for how to set it up in a Java-based configuration: stackoverflow.com/a/29883166/3960852
-1

I struggled a little with this and ended up passing as simple parameters. Fine if you don't have lots to pass in your request:

myMethod(@RequestParam("file") MultipartFile myFile,
        @RequestParam("param1") Float param1, @RequestParam("param2") String param2 {}

Comments

-2

For Spring 4 and later you can do the following to get the full object:

public ResponseEntity<Object> upload(@Payload EUPSettingsWrapper wrapper) {

}

Note: Also should work without the tag

public ResponseEntity<Object> upload(EUPSettingsWrapper wrapper) {

}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.