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
Carlos Verdes's answer failed to work with my $http interceptor, which adds authorization headers and so on. So I decided to add to his solution and create mine using $http.
My form (using the controllerAs syntax) is assuming a file and a simple object containing the information we need to send to the server. In this case I'm using a simple name and type String property.
The first step was to create a directive that binds my file to the scope of the designated controller (in this case myController) so I can access it. Binding it directly to a model in your controller won't work as the input type=file isn't a built-in feature.
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Secondly I created a factory called myObject with an instance method create that allows me to transform the data upon invoking create on the server. This method adds everything to a FormData object and converts it using the transformRequest method (angular.identity). It is crucial to set your header to undefined. (Older Angular versions might require something than undefined to be set). This will allow the multidata/boundary marker to be set automatically (see Carlos's post).
myObject.prototype.create = function(myObject, file) {
var formData = new FormData();
formData.append('refTemplateDTO', angular.toJson(myObject));
formData.append('file', file);
return $http.post(url, formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined }
});
}
All that is left to do client side is instantiating a new myObject in myController and invoking the create method in the controller's create function upon submitting my form.
this.myObject = new myObject();
this.create = function() {
//Some pre handling/verification
this.myObject.create(this.myObject, this.file).then(
//Do some post success/error handling
);
}.bind(this);
On the RestController I can now simply do the following: (Assuming we have a POJO MyObject)
@RequestMapping(method = RequestMethod.POST)
@Secured({ "ROLE_ADMIN" }) //This is why I needed my $httpInterceptor
public void create(MyObject myObject, MultipartFile file) {
//delegation to the correct service
}
Notice, I'm not using requestparameters but just letting spring do the JSON to POJO/DTO conversion. Make sure you got the MultiPartResolver bean set up correctly too and added to your pom.xml. (And Jackson-Mapper if needed)
spring-context.xml
pom.xml
commons-fileupload
commons-fileupload
${commons-fileupload.version}