Angular - file upload request, adding #RequestParam - angularjs

I want to add #RequestParam to my http request so it will match spring MVC #RequestParam.
How can I add this to my file upload request:
/*
#param file - file from input
#param uploadUrl - url
*/
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
//add file to FormData
fd.append(file.name, file);
//send request
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(result){
console.log(result);
})
.error(function(err){
console.log(err);
});
}
In my backend the error is Required String parameter 'filename' is not present
Here is my Spring MVC controller (only the header part):
#Controller
#RequestMapping("/file")
public class FileUploadController {
/**
* Upload single file using Spring Controller
*/
#RequestMapping(value = "/uploadFile", method = RequestMethod.POST)
public #ResponseBody String uploadFileHandler(#RequestParam("filename") String filename, #RequestParam("file") MultipartFile file) {
//rest of the function
}

So I just append another param to my FormData:
fd.append('file', file);
fd.append('filename', file.name);
Match the #RequestParam's.
Thanks.

Related

File upload from AngularJS to Spring MVC on Tomcat 8 gives this error: Required request part 'file' is not present

I'm trying to upload a file from AngularJS frontend to Spring MVC backend, using Tomcat 8 server.
This is my AngularJS controller function:
vm.add = function(photo) {
let file = document.getElementById('file').files[0];
let reader = new FileReader();
reader.onload = function(e) {
let photoFile = e.target.result;
photoService.create($routeParams.lid, photo,photoFile).then(
function(response) {
$location.path('/books');
vm.photo = response.data;
})
}
reader.readAsBinaryString(file);
}
This is my service function, still on the AngularJS side:
service.create = function(bookId, photo, file) {
var formData = new FormData();
formData.append('name', photo.name);
formData.append('file', file);
return $http(
{
url : BASE_URL + authService.getToken().id
+ '/book/' + bookId + '/photo/',
method : 'POST',
data : formData,
headers : {
'Content-Type' : undefined
},
transformRequest: angular.identity
}).then(function(res) {
return res;
});
};
I have this bean in my dispatcher xml:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="10000000" />
</bean>
And this in my Spring MVC controller:
#Override
#RequestMapping(value = "user/{uid}/book/{lid}/photo", method = RequestMethod.POST)
public Photo create(HttpServletRequest request, HttpServletResponse response,
#PathVariable int uid, #PathVariable int lid,
#RequestParam("file") MultipartFile file) {
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
return photoDAO.create(uid,lid,file);
}
I can send the file and save it just fine directly from the html, but for some reason sending it from AngualrJS gives me this error on the Spring side:
2018-09-02 17:45:00,027 DEBUG [org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod] - Error resolving argument [4] [type=org.springframework.web.multipart.MultipartFile]
HandlerMethod details:
Controller [controllers.PhotoControllerImpl]
Method [public entities.Photo controllers.PhotoControllerImpl.create(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse,int,int,org.springframework.web.multipart.MultipartFile)]
org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present
Even though I do see the file in my request payload:
018-09-02 17:45:00,028 DEBUG [com.github.isrsal.logging.LoggingFilter] - Request: request id=4; method=POST; content type=multipart/form-data; boundary=----WebKitFormBoundaryfNOybpMz7ZO1IyZX; uri=/InfiniteLegacyREST/api/user/1/legacy/1/photo/; payload=------WebKitFormBoundaryfNOybpMz7ZO1IyZX
Content-Disposition: form-data; name="name"
s
------WebKitFormBoundaryfNOybpMz7ZO1IyZX
Content-Disposition: form-data; name="file"
this is a text
------WebKitFormBoundaryfNOybpMz7ZO1IyZX--
What is causing this? Why does uploading the file in a multipart/form-data directly submitted from the html work just fine but doing it from AngularJS doesn't?
Looking at your error message, that #RequestParam MultipartFile you're using in your public Photo create(...) controller method may need to be a #RequestPart instead:
#RequestPart(name = "file", required = false) MultipartFile file
My TightBlog app has a working example of an Spring & Angular-based file upload: REST controller, angular.js and JSP.

File upload fails with angularjs and spring boot

I want to upload file
controller.js
userService.saveProfile($scope.user.profile.companyLogo).then(function(response){
if(response.status==201){
$('#profileModal').hide();
$scope.load();
}
});
service.js
saveProfile:function(logo){
var formData = new FormData();
formData.append("file",logo);
var retVal = $http({
method : 'POST',
url : '/api/user/profile',
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
data: formData
}).then(function(response){
return response;
});
return retVal;
}
Controller.java
#RequestMapping(value="/profile",method = RequestMethod.POST,headers="'Content-Type':'multipart/form-data'")
public ResponseEntity saveProfile(#RequestBody MultipartFile file){
System.out.println(file);
return new ResponseEntity(HttpStatus.CREATED);
}
if I add headers to #RequestMapping I'm getting 404 and if I remove it I'm getting file null
Please suggest me the correct way of doing file upload
It worked!
I removed headers from #RequestMapping and used #RequestPart instead of #RequestBody
#RequestMapping(value="/profile",method = RequestMethod.POST)
public ResponseEntity saveProfile(#RequestPart("file") MultipartFile file){
System.out.println(file);
return new ResponseEntity(HttpStatus.CREATED);
}

uploading files using angularjs and spring boot

I have an angularjs application deployed in a server, and a spring boot application deployed in another server.
in my angularjs application I have a form that uploads a file and send it via a rest controller, this controller then saves this file inside a folder in the server where the spring boot application is deployed.
this is my rest controller :
#CrossOrigin(origins="*")
#RestController
public class Upload {
#RequestMapping(value="/imageUpload", method = RequestMethod.POST)
public void UploadFile(MultipartHttpServletRequest request) throws IOException {
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
File dir = new File("C:\\file");
if (dir.isDirectory())
{
File serverFile = new File(dir,fileName);
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(serverFile));
stream.write(file.getBytes());
stream.close();
}else {
System.out.println("not");
}
}
}
and this my angularjs controller which sends the file :
$scope.validerOffre= function(){
var file = $scope.fileUpload;
var uploadUrl = "/imageUpload";
fileUploadService.uploadFileToUrl(file, uploadUrl);
};
this controller then call the fileUploadService :
capValueRecruitApp.service('fileUploadService', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post('http://localhost:8080' + uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
});
and in my angularjs application I want to display the files that I uploaded but I cant do that since the files were uploaded in the spring boot application server, which is another server .
so my question is how can I save the files that I uploaded in a folder in the angularjs application server instead of the server where the spring boot application is deployed.
You basically have two solutions :
1: you create a new #RequestMapping that takes the filename ( or even better an id returned by your fileUpload controller) and that returns the file.
something like this :
#RequestMapping(value="/imageDownload", method = RequestMethod.POST)
public void downloadFile(#RequestParam(value = "fileName", required = true) String fileName,HttpServletResponse response) throws IOException {
File dir = new File("C:\\file");
File fileToDownload = new File(dir,fileName);
if (dir.isDirectory() && fileToDownload.exists()){
//read fileToDownload and send stream to to response.getOutputStream();
}else {
System.out.println("no such file "+ fileToDownload.toString());
response.sendError(404);
return;
}
}
Then you call http://localhost:8080/imageDownload?filename=yourUploadedFile.jpg
2: When you save the file in your upload, save it somewhere where your webserver has direct access.
If our angularjs files are served by your spring application, you could add a new folder in spring.resources.staticLocations in the application.properties file. (see this : http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-web-applications.html#boot-features-spring-mvc-static-content )

angular http get, download file from spring mvc server

I'm using apache commons IOUtils copy method to send file from server to angularjs.
This is my controller :
#RequestMapping(value="/download", method = RequestMethod.GET)
public void downloadFile(HttpServletResponse response) {
response.setContentType("image/jpg");
try {
File file = new File(filePath);
InputStream inputStream = new FileInputStream(file);
IOUtils.copy(inputStream, response.getOutputStream());
} catch (...) {
.......
}
In angularJs controller :
$http({
method: 'GET',
url: '.../download',
headers: {'Content-Type': 'image/jpg'}
})
.success(function(data, status){
console.log(data);
var blob = new Blob([data], {type: 'image/jpg'});
saveAs(blob, 'test.jpg');
})
.error(function(data, status){
....
})
When I download the file in the client side, I can't read it. When I open it with notepad++ I find that special characters are modified.
For example, when I open the original file with Notpad++, I get a line like this :
òŽsCJVäl·²HWƒ…;¹(òÈ$ÓÒ«Á‘{S€~9ÎsŠÒogk
The same line, when I open the downloaded file with notepad++ becomes :
��sCJV�l��HW��;�(��$�Ӂҫ��{S�~9�s��ogk
However, when I put the download link (localhost/myApplication/download) directly in a browser, it works correctly. Files are supposed to be encrypted and authorization is needed to download a file, so I have to use angular HTTP get.
Any help would be appreciated.
I had to add responseType to HTTP get request :
$http({
method: 'GET',
url: '.../download',
responseType: 'arraybuffer'
})
.success(function(data, status){
console.log(data);
var blob = new Blob([data], {type: 'image/jpg'});
saveAs(blob, 'test.jpg');
})
.error(function(data, status){
....
})
Now it is working.

Save a file in angular from a http response

I was wondering how I can save a file that is contained in a response from the server in angular ? (So that the file is automatically downloaded when the response arrives)
Edit :
I have a $http post method, and I get pdf data in the response. On success, I want to save the response data as a pdf file.
E. g :
$http({
method: 'POST',
url : 'theUrl',
data: //some array that is received
headers : //content type info
}
.success(function(response) { // I want to save the response as a pdf });
On angular 2... you can do:
import { saveAs } from 'browser-filesaver/FileSaver.js'
downloadFile(data: Response) {
var blob = new Blob([data], {type: 'application/x-tar'});
saveAs(blob, "report.tgz");
}
Using HTML5 FileSaver interface, this can be achieved:
https://github.com/eligrey/FileSaver.js/
Example solution:
//Call API to retrieve file stream using POST request
$http.post("URL", searchData, { responseType: 'arraybuffer' }).then(
response => {
//Download file from response
saveFileAs(response);
},
data => {
//raise error
}
);
function saveFileAs(response) {
var contentDisposition = response.headers("content-disposition");
//Retrieve file name from content-disposition
var fileName = contentDisposition.substr(contentDisposition.indexOf("filename=") + 9);
fileName = fileName.replace(/\"/g, "");
var contentType = response.headers("content-type");
var blob = new Blob([response.data], { type: contentType });
saveAs(blob, fileName);
}
You can't save the document as you don't have access to the users file system in a browser. You could send the URL of the pdf back, then trigger the browsers build in file save / open mechanism by adding a dummy iFrame to the body:
$http({
method: 'POST',
url : 'theUrl',
data: //some array that is received
headers : //content type info
}
.success(function (data) {
if ($('#iframe').length == 0) {
var $iframe = $('<iframe id="iframe" style="display: none"></iframe>');
$('body').append($iframe);
}
$('#iframe').attr('src', {{url to retrieve the file}})
})

Resources