I have a Java Spring MVC Web application as server. And AngularJS based application as client.
In AngularJS, I have to upload a file and send to server.
Here
I have had the same problem and found a complete solution to send both json and file from angular based page to a Spring MVC method.
The main problem is the $http which doesn't send the proper Content-type header (I will explain why).
To send both json and file we need to send a multipart/form-data, which means "we send different items in the body separated by a special separator". This special separator is called "boundary", which is a string that is not present in any of the elements that are going to be sent.
The server needs to know which boundary is being used so it has to be indicated in the Content-type header (Content-Type multipart/form-data; boundary=$the_boundary_used).
So... two things are needed:
Example of a good request:
Content-Type multipart/form-data; boundary=---------------------------129291770317552
Which is telling the server "I send a multipart message with the next separator (boundary): ---------------------------129291770317552
-----------------------------129291770317552 Content-Disposition: form-data; name="clientInfo"
{ "name": "Johny", "surname":"Cash"}
-----------------------------129291770317552
Content-Disposition: form-data; name="file"; filename="yourFile.pdf"
Content-Type: application/pdf
%PDF-1.4
%õäöü
-----------------------------129291770317552 --
Where we are sending 2 arguments, "clientInfo" and "file" separated by the boundary.
If the request is sent with $http, the boundary is not sent in the header (point 1), so Spring is not able to process the data (it doesn't know how to split the "parts" of the request).
The other problem is that the boundary is only known by the FormData... but FormData has no accesors so it's impossible to know which boundary is being used!!!
Instead of using $http in js you should use standard XMLHttpRequest, something like:
//create form data to send via POST
var formData=new FormData();
console.log('loading json info');
formData.append('infoClient',angular.toJson(client,true));
// !!! when calling formData.append the boundary is auto generated!!!
// but... there is no way to know which boundary is being used !!!
console.log('loading file);
var file= ...; // you should load the fileDomElement[0].files[0]
formData.append('file',file);
//create the ajax request (traditional way)
var request = new XMLHttpRequest();
request.open('POST', uploadUrl);
request.send(formData);
Then, in your Spring method you could have something like:
@RequestMapping(value = "/", method = RequestMethod.POST)
public @ResponseBody Object newClient(
@RequestParam(value = "infoClient") String infoClientString,
@RequestParam(value = "file") MultipartFile file) {
// parse the json string into a valid DTO
ClientDTO infoClient = gson.fromJson(infoClientString, ClientDTO.class);
//call the proper service method
this.clientService.newClient(infoClient,file);
return null;
}