R K Punjal
R K Punjal

Reputation: 1475

Use Jquery and FormData to submit form fields and uploaded File to Spring MVC Controller in Spring Boot App

I am unable to use Jquery and FormData to submit form fields and uploaded File to Spring MVC Controller in Spring Boot App.

I keep getting this exception "The current request is not a multipart request" on the controller side.

My Setup.

I have a regular Spring Boot Webapp

This is my spring boot version :

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.7.RELEASE</version>
</parent>

My Ajax form submit looks like this :

var entityJson = form2js("my-form-id",null,false); // js library to get json from form
var entityJsonStr = JSON.stringify(entityJson);

var formData = new FormData();
formData.append("data", entityJsonStr); // the entered data as JSON


// append files, if there are any
$.each($("#my-form-id").find("input[type='file']"), function(i, tag) {
    $.each($(tag)[0].files, function(i, file) {
       formData.append(tag.name, file);
    });
});

$.ajax({
    url:     theUrl,
    type:    'POST',
    headers: {'Content-Type': undefined},
    cache: false,
    processData: false,
    data:    formData,
    error: function(xhr,status,err){
        // failure handling
    },
    success: function(response){
        // success handling
    }
});

Only json submission works absolutely fine, (when I submit only entityJsonStr instead of FormData instance)

On Server-side my Controller looks like this:

@RequestMapping(value="/save", method= RequestMethod.POST, produces=APPLICATION_JSON_UTF_8)
public @ResponseBody WebResponse<MyEntity> save(
        @Valid @RequestPart(value="data") MyEntity myEntity
        ,@RequestPart(value = "image", required = false) MultipartFile image
) throws Exception {
    try {

        validateImage(image);
        saveImage(myEntity.getName() + ".jpg", image);

        shoppingCenterService.save(myEntity);
        MyEntity shoppingCenterWithOnlyId = getEmptyShoppingCenterWithId(myEntity.getId());

        return new WebResponse(true, SHOPPINGCENTER_SAVE_SUCCESS);
    } catch (DuplicacyException de) {
        return getDuplicacyResponse(de, myEntity);
    } catch(Exception e) {
        LOGGER.error("MyEntity Controller[save]", e);
        return new WebResponse(false, MYENTITY_SAVE_FAILED); // custom response
    }
}

when I not use @RequestPart and simply use @Valid @RequestBody MyEntity myEntity and don't use FormData object in javascript, i get the right json which translates to an object of MyEntity ...

I keep getting this exception :

org.springframework.web.multipart.MultipartException: The current request is not a multipart request   

I have tried all following combinations, nothing works

// dataType: 'json',
// contentType: 'application/json',

headers: {'Content-Type': undefined},
cache: false,
//  contentType: null,
//  processData: false,
// enctype: 'multipart/form-data',
processData: false,
//contentType: false,
//cache: false,

// async:   true,
// cache:   false,
// global:  false,

but nothing is submitting the formdata + file properly.

I have been trying to get this to work for a couple of days now ... I don't see what I am doing wrong.

If anybody has got this to work, please share a solution.

Update:

After Jny's reply, I tried with

headers: {'Content-Type': 'multipart/form-data'}

and

contentType:  'multipart/form-data'

Now I get :(

org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found

My Request Payload looks like this :

------WebKitFormBoundaryPG92Ng6h630YkJKN
Content-Disposition: form-data; name="form_data"

{"id":"","name":"s","code":"s" 
  // ... more json
}
------WebKitFormBoundaryPG92Ng6h630YkJKN
Content-Disposition: form-data; name="image"; filename="ThumbsUp.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryPG92Ng6h630YkJKN--

Upvotes: 1

Views: 4876

Answers (1)

R K Punjal
R K Punjal

Reputation: 1475

Found the Solution !! and it works now Yippee :)

What we need to do is when we are setting the Json-string in the FormData, we need to specify the content-type that this part is json .... so the solution looks like this now :

var entityJson = form2js("my-form-id",null,false); // js library to get json from form
var entityJsonStr = JSON.stringify(entityJson);

var formData = new FormData();
formData.append("data", new Blob([entityJsonStr], {
                type : "application/json"  // ** specify that this is JSON**
            })); 


// append files, if there are any
$.each($("#my-form-id").find("input[type='file']"), function(i, tag) {
    $.each($(tag)[0].files, function(i, file) {
       formData.append(tag.name, file);
    });
});

$.ajax({
    url:     theUrl,
    type:    'POST',
    processData: false,
    contentType: false,
    cache: false,
    data:    formData,
    error: function(xhr,status,err){
        // failure handling
    },
    success: function(response){
        // success handling
    }
});

and then the controller looks the same as earlier.

There was one more change, that I ended up doing for my entity. Since I now have this new form field as "image" which was not meant to be a property in my entity directly.

So I asked Jackson to ignore those unmapped properties

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
// MyEntity class goes here {}

This works now and I am able to ajax submit the form with the form-data as well as the file.

Upvotes: 3

Related Questions