Spring Controller @RequestBody with file upload is it possible?

88,762

Solution 1

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

Solution 2

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

Solution 3

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());
Share:
88,762

Related videos on Youtube

Yatin
Author by

Yatin

Updated on July 09, 2022

Comments

  • Yatin
    Yatin almost 2 years

    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?

  • Kenny Worden
    Kenny Worden almost 6 years
    Also see this answer for how to set it up in a Java-based configuration: stackoverflow.com/a/29883166/3960852
  • Christos Karapapas
    Christos Karapapas about 5 years
    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?
  • geoand
    geoand about 5 years
    Unfortunately I don't really remember since the answer is pretty old :)
  • Akshay Naik
    Akshay Naik about 4 years
    org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/octet-stream' not supported
  • Dharmendrasinh Chudasama
    Dharmendrasinh Chudasama over 3 years
    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/…