Hi,
In Angular file upload is a bit tricky as ng-model doesn't support file and in JSON we can't send file.
In Spring with File Multipart accepting with other values is complex to implement.
It was time consuming to find approaches to Upload file from Angular and Accepting as File MultiPart in Spring.
In Angular file upload is a bit tricky as ng-model doesn't support file and in JSON we can't send file.
In Spring with File Multipart accepting with other values is complex to implement.
It was time consuming to find approaches to Upload file from Angular and Accepting as File MultiPart in Spring.
Angular side
1. Create a directive to fetch the file.
2. Inject all required things to the Controller.
Here in Directive restrict type 'A' is used. You can change with any type if required.
I have used JSP to ease with csrf tokens.
<!--
Author : Ramakrishna Panni
name: fileUpload.jsp
details: To test file upload with a File,Pic and a String
-->
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta name="_csrf" content="${_csrf.token}"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" content="${_csrf.headerName}"/>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.11.3.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.24/angular.min.js"></script>
</head>
<body ng-app='fileUpload' ng-controller='UploadController'>
<form enctype="multipart/form-data"
ng-submit="submitForm()">
File to upload: <input type="file" file-model="cvBlob"><br /> Name: <input
type="text" name="name" ng-model="result.success"><br /> <br />
Pic to Upload: <input type="file" file-model="picBlob"><br /> <br /><input type="submit"
value="Upload"> Press here to upload the file!
<input type="hidden" id="csrf" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<script type="text/javascript">
var upload = angular.module('fileUpload', []);
upload.controller('UploadController', ['$scope', '$window','$http', function($scope, $window,$http,fileUpload) {
$scope.result = {};
var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");
$scope.submitForm = function(){
var pic = $scope.picBlob;
var cv = $scope.cvBlob;
var uploadUrl = "/upload?_csrf="+token
console.log(pic);
var fd = new FormData();
fd.append('pic', pic);
fd.append('cv', cv);
fd.append('result',JSON.stringify($scope.result)); //You should make it to String while sending
$http.post(uploadUrl, fd, {
transformRequest: function (data, headersGetterFunction) {
return data;
}, // To take Http Request and Headers and making it Serialized, without serizlized object Spring will give Media Not Supported error
headers: {'Content-Type': undefined}
}) .success(function(data){
if (data.error === "") {
// Showing errors.
$scope.success = data.success;
} else {
$scope.error = data.error;
}
})
.error(function(){
});
};
}]);
upload.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]);
});
});
}
};
}]);
</script>
</body>
</html>
Points to look on
In this you can set the max upload size,encoding, lazy resolve,temp directory and others.
Define in Application configuration class.
MultipartFilter
Define in Application configuration class.
- Append every data in FormData object using property tags.
- Stringify JSON append in FormData
- Transform the request with headers as Serialized
- Make Content Undefined as Angular will convert it to right one
Spring Side
- Create Bean of "MultipartResolver"
- Add Multipart Filter in "AbstractSecurityWebApplicationInitializer"
JAR's needed commons-io,commons-fileupload and jackson.
MultipartResolver Bean
In this you can set the max upload size,encoding, lazy resolve,temp directory and others.
Define in Application configuration class.
@Bean(name = "filterMultipartResolver")
public CommonsMultipartResolver commonsMultipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
MultipartFilter
Define in Application configuration class.
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
Controller Class
Points to look on
package com.mindfiresolutions.springmaven.controller;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import com.mindfiresolutions.springmaven.models.Result;
/**
* Author: Ramakrishna Panni
* Class: FileUploadController
* Details: Created to handle Sample file Upload
*/
@Controller
public class FileUploadController {
@RequestMapping(value="/upload", method=RequestMethod.GET)
public @ResponseBody Result provideUploadInfo() {
Result res = new Result();
res.setError("You can upload a file by posting to this same URL.");
return res;
}
@RequestMapping(value="/upload", method=RequestMethod.POST, consumes = {"multipart/form-data"})
public @ResponseBody Result handleFileUpload( @RequestParam("result") String res, @RequestParam("cv") MultipartFile file, @RequestParam("pic") MultipartFile pic){
Result result = new Result();
ObjectMapper mapper = new ObjectMapper();
Result resNew = new Result();
try {
resNew = mapper.readValue(res,Result.class);
} catch (Exception e) {
result.setError("JSON mapping failed"+e.getMessage());
return result;
}
if (!pic.isEmpty()) {
try {
byte[] bytes = pic.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File("pic.jpg")));
stream.write(bytes);
stream.close();
result.setSuccess("You successfully uploaded "+resNew.getSuccess());
return result;
} catch (Exception e) {
result.setError("You failed to upload " + e.getMessage());
}
} else {
result.setError("You failed to upload because the file was empty.");
}
if (!file.isEmpty()) {
try {
byte[] bytes = file.getBytes();
BufferedOutputStream stream =
new BufferedOutputStream(new FileOutputStream(new File("new.txt")));
stream.write(bytes);
stream.close();
result.setSuccess("You successfully uploaded "+resNew.getSuccess());
return result;
} catch (Exception e) {
result.setError("You failed to upload " + e.getMessage());
return result;
}
} else {
result.setError("You failed to upload because the file was empty.");
return result;
}
}
}
Points to look on
@RequestParam with the property tag name should be used to get Stringified JSON. @RequestPart with the property tag name should be used to get MultiPartFile.- Object Mapper will help to make String to Object.
Thanks,