Im doing a webapp to upload files to a server.
I have this form in my view:
<body>
<form>
<input id="file" type="file" name="file">
<input id="send" value="Upload" type="button" />
</form>
</body>
And i send the file with jquery and ajax:
var form = new FormData();
form.append('file', $("#file")[0].files[0]);
$.ajax({
type: 'POST',
url: 'http://localhost:8080/UploadMotion/upload',
cache: false,
contentType: false,
processData: false,
data: form,
success: function (data) {
alert("Funciono");
},
error: function () {
alert("Fallo");
}
});
The jquery looks like correct, because the value of the file is sent correctly in the form var.
I send this data to my controller, but I'm not receiving the correct file. I'm receiving a temporal file, with this format:
...\...\AppData\Local\Temp\upload_c72334c_14b9858dd1d__8000_00000004.tmp
This is the code of the controller:
public Render upload(File file) throws IOException{
String folderName = "C:\\Users\\Inma\\Documents\\MisDescargas";
String token = UUID.randomUUID().toString();
String fileName = folderName+ File.separator + token;
FileInputStream inputStream = new FileInputStream(file);
FileOutputStream outputStream = new FileOutputStream(fileName);
IOUtils.copy(inputStream, outputStream);
inputStream.close();
outputStream.close();
return renderJSON("token",token);
}
I use webmotion, a framework to develop web applications.
This is the mapping file:
[config]
package.views=WEB-INF/views
package.actions=com.vincle.actions
[actions]
GET / view:index.jsp
POST /upload MainController.upload
GET /download MainController.download
The networks screen shows this: http://postimg.org/image/lguc3q1ex/
When I try to create the FileInputStream to copy this file to my server, I get the exception FileNotFound exception, because this file doesn't exist.
What is the problem? Why don't I recieve the correct file?
Thanks in advance
Related
How to implement multiple file upload feature, with each of file have it own extra field (eg. comment, documentType) in Spring Boot?
This answer might be related but it's for single file only:
Spring boot controller - Upload Multipart and JSON to DTO
Html side
<input id="files" type="file" name="files[]" multiple />
Upload
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script type="text/javascript">
function uploadFiles(){
var form = new FormData();
var i=0;
$.each($("input[type='file']")[0].files, function(i, file) {
form.append('file', file);
form.append('extradata','ola'+i);
i++;
});
// send form data with ajax
$.ajax({
type: 'POST',
url: '/uploadFiles',
cache: false,
contentType: false,
processData: false,
data : form,
success: function(result){
console.log(result);
alert('upload success');
},
error: function(err){
console.log(err);
}
})
}
</script>
and server side
#PostMapping("/uploadFiles")
public String uploadFiles(#RequestParam("file") MultipartFile[] files,
#RequestParam("extradata") String[] extras) throws Exception {
int i = 0;
Files.createDirectories(Paths.get("./uploaded/"));
for (MultipartFile f : files) {
Files.copy(f.getInputStream(), Paths.get("./uploaded/" + extras[i] + f.getOriginalFilename()));
i++;
}
return "success";
}
you can find running example here https://github.com/ozkanpakdil/spring-examples/tree/master/demoMultiFileUpload
You can encode multiple request parts in the POST payload and process that with Spring Boot.
Let's say you need to pass in two things per file:
Blob with the file contents
metadata - an object that can hold whatever - title/comments - you name it.
FrontEnd
You can use anything to simulate FormData params, this is in TypeScript:
let's say a document looks like this:
export interface NewDocument {
title: string,
comment: string,
author: string,
file: File
}
So the generating of the FormData might be like:
private getFormData(doc: NewDocument): FormData {
let formData: FormData = new FormData();
const json: Blob = new Blob([JSON.stringify(doc)], {type: 'application/json'});
formData.append('metadata', json); //adding the metadata
const blob: Blob = new Blob([doc.file[0]], {type: doc.file[0].type});
formData.append('file', blob); //adding the file contents
return formData;
}
You can then POST the form data to a given endpoint.
BackEnd
You can specify the different RequestParts you're expecting in the request
#PostMapping
public ResponseEntity<Void> uploadFile(#RequestPart("metadata") FileMetadata metadata,
#RequestPart("file") MultipartFile file) {
//process
}
FileMetadata here is a custom Java POJO into which you can deserialize the JSON representation of the FrontEnd's NewDocument
You should be able to turn this into a multiples version.
#PostMapping
public ResponseEntity<Void> uploadFile(#RequestPart("metadata") FileMetadata[] metadatas,
#RequestPart("file") MultipartFile[] files) {
//process
}
The problem now is how to identify which metadata is for which file.
A simple way would be to have the filename encoded in the metadata object and use that for mapping.
I know this is a very basic question but there are so many implementations out there and I can't get them to work.
So in my project if the user clicks a button, I'm generating a zip file on a servlet (which is called through an AJAX POST). Naturally, I want that file to get downloaded to the user.
Here's my code for the request:
<button type="button" class="btn btn-info btn-lg" onclick="getZip();">
<span class="glyphicon glyphicon-download"></span> Download clusters (.zip)
</button>
Here's the AJAX for the POST:
function getzip() {
$.ajax({
url:'GetZipServlet',
type:'GET',
});
}
And this is my code for the download:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
System.out.println("Downloading clusters.zip");
/* Generate the directory on the server, then zip it. */
ClinicoGenomic.getInstance().clustersToFiles();
ClinicoGenomic.getInstance().zipClusters();
System.out.println("Done generating the .zip");
String parent_dir = System.getProperty("catalina.base");
String filename = "clusters.zip";
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename);
ZipOutputStream zipStream = new ZipOutputStream( response.getOutputStream() );
ZipInputStream fi = new ZipInputStream(new FileInputStream(parent_dir + "/" + filename));
int i;
while ((i = fi.read())!=-1)
zipStream.write(i);
zipStream.close();
fi.close();
System.out.println(".zip file downloaded at client successfully");
}
I get the correct messages in my console, up to the .zip file downloaded at client successfully. But the download doesn't start. what could be wrong here???
if you are correctly sending the response you should just simply handle it after your ajax call, like this:
$.ajax({
url:'GetZipServlet',
type:'GET',
success: function (response) {
//handle the response here
}
});
I have developed web service using Play framework. I have created POST rest service in Play framework as below.
In routes file:
POST /imageUpload controllers.Application.imageUpload()
In Application.java:
public static Result imageUpload() {
ObjectNode result = Json.newObject();
MultipartFormData body = request().body().asMultipartFormData();
FilePart file = body.getFile("file");
File trainImg = file.getFile();
File temp = new File("/Play_Framework/temp.jpg");
trainImg.renameTo(temp);// moved the image to another folder to check the correct image.
.
.
.
return ok(result);
}
In the service, I have written the code to save the image which is received from the request.
I have called this service from the Ajax as given below.
In my index.html file:
var formData = new FormData();
var blob = new Blob([imageData], { type: "image/jpg"});
formData.append("file", blob, "capturedImage.jpg");
$.ajax({
url: 'http://localhost:9000/imageUpload',
data: formData,
crossDomain: true,
processData: false,
contentType: false,
async: false,
cache: false,
dataType: "json",
type: 'POST',
success: function(data){
alert(data);
var responseStr = JSON.stringify(data);
alert("Response str -- "+responseStr);
}
});
When I upload the file as Multipart form data, I can receive it as multipart data in the server side. But it is stored as "multipartBody7906599875117091855asTemporaryFile".
If I get this file's mimitype - "content/unknown".
When I debug, I got the below multipart form data path "/var/folders/f3/r3rfqfl949z5pf2cprwn95dm0000gn/T/multipartBody7906599875117091855asTemporaryFile".
How do parse this as "jpg" file? Can anyone help me to do this?
The following worked for me:
Application.java
public class Application extends Controller {
public static Result index() {
return ok(index.render("SO answer 30229421"));
}
public static Result imageUpload() {
ObjectNode result = Json.newObject();
Http.MultipartFormData body = request().body().asMultipartFormData();
Http.MultipartFormData.FilePart file = body.getFile("file");
File trainImg = file.getFile();
File temp = new File("/tmp/temp.jpg");
trainImg.renameTo(temp); // moved the image to another folder to check the correct image.
result.put("path", temp.getAbsolutePath());
return ok(result);
}
public static Result imageDownload(String path) {
return ok(new File(path));
}
index.scala.html
#(message: String)
<html>
<body>
<h1>#message</h1>
<input type="file" id="imageData"/>
<button onclick="send()">Send image</button>
<div id="image">
</div>
<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
function send() {
var imageData = $('#imageData')[0].files[0];
var formData = new FormData();
var blob = new Blob([imageData], { type: "image/jpg"});
formData.append("file", blob, "capturedImage.jpg");
$.ajax({
url: 'http://localhost:9000/imageUpload',
data: formData,
crossDomain: true,
processData: false,
contentType: false,
async: false,
cache: false,
dataType: "json",
type: 'POST',
success: function(data){
$('#image').html('<img src="http://localhost:9000/imageDownload?path=' + data.path + '"/>');
}
});
}
</script>
</body>
</html>
The only difference, is that because you didn't include how you get the imageData value, I used this version (as per this SO answer):
var imageData = $('#imageData')[0].files[0];
I have angularjs And spring rest file upload it work well but i need to change file upload in html file to dropzone.js or any drag drop file upload,I tried dropzone.js library but I couldn't integrate it with angular ,Can any one help me how can i do that?
Angularjs controller
$scope.document = {};
$scope.setTitle = function(fileInput) {
var file=fileInput.value;
var filename = file.replace(/^.*[\\\/]/, '');
var title = filename.substr(0, filename.lastIndexOf('.'));
$("#title").val(title);
$("#title").focus();
$scope.document.title=title;
};
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http.post('/app/newDocument', formData, {
transformRequest: function(data, headersGetterFunction) {
return data;
},
headers: { 'Content-Type': undefined }
}).success(function(data, status) {
console.log("Success ... " + status);
}).error(function(data, status) {
console.log("Error ... " + status);
});
};
});
html form
<form ng-submit="uploadFile()" class="form-horizontal"
enctype="multipart/form-data">
<input type="file" name="file" ng-model="document.fileInput" id="file" />
<input type="text" class="col-sm-4" ng-model="document.title" id="title" />
</form>
Rest Controller
#RequestMapping(value="/newDocument", method = RequestMethod.POST)
public void UploadFile(MultipartHttpServletRequest request,
HttpServletResponse response) throws IOException {
Attachment attachment=new Attachment();
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
attachment.setName(fileName);
File dir = new File("D:\\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");
}
}
I would personally use a dedicated directive such as the excellent:
https://github.com/danialfarid/angular-file-upload
https://github.com/flowjs/ng-flow
These take care of the boilerplate code and let you focus on styling and creating an upload service that works in sync with your API.
I created an angular js program for downloading a file from the server here follows the code
HTML Code
<a download="fullList.csv" ng-href="{{ fullListUrl }}" type="button" class="btn btn-success btn-xs exec-batch" ng-click="exportCSVBulk(batchExec)">
<span class="glyphicon glyphicon-ok"></span> EXPORT AS CSV
</a>
AngularJS Controller
$scope.exportCSVBulk=function(){
var page = "../importExportService/exportBulkCSV/"+batchExec.id;
$http.get(page).success(function(response) {
$scope.fullListUrl = 'data:text/csv;charset=utf-8,' + escape(response);
});
}
Here what i am doing is when a user click on the EXPORT AS CSV link the function exportCSVBulk fires and from that function the url value (fullListUrl) sets. But this is an ajax request, so when a user click on the link the url, the response time become little bit long which results the url will not redirected properly. Is it possible to fix this problem? or is there is any alternative way to fix this?
I have faced the similar issue for downloading files such as .pdf, .xls, .xlsx etc through Ajax.
Its a fact that we cant download files through Ajax, even though i came up with a solution which downloads files through Ajax like.
You can use jquery.fileDownload - A jQuery File Download Plugin for Ajax like, feature rich file downloads.
Demo Working
Server Side
I am using Spring at the server side
#RequestMapping(value = "exportXLS", method = RequestMethod.POST, produces = APP_JSON)
#ResponseBody
public void getCSV(final HttpServletResponse response, #RequestParam(value = "empId", required = true) final String empId) throws IOException, Exception
{
final byte[] csv = ExportXLSUtil.getFileBytes(empId); // get the file bytes
final OutputStream output = getOutputStream(response);
response.setHeader("Content-Disposition", "attachment; filename=documents_" + new DateTime() + ".xls");
response.setContentType(CONTENT_TYPE);
response.setContentLength(csv.length);
write(output, csv);
}
Client Side
At the client side, I am using AngularJS
$downloadXLS = function(id)
{
$.fileDownload('/user/exportXLS',
{
httpMethod : "POST",
data : {
empId : id
}
}).done(function(e, response)
{
// success
}).fail(function(e, response)
{
// failure
});
}
Download Link - jquery.fileDownload.js
I created a more angular way solution. The server has to provide content-type and content-disposition if you want to sync with server info, although you could add type and download properties manually.
vm.export = function () {
//PopUps.showLoading()
$http.get(Url).then(function (result) {
//PopUps.hideLoading()
var headers = result.headers()
var blob = new Blob([result.data], { type: headers['content-type'] })
var windowUrl = (window.URL || window.webkitURL)
var downloadUrl = windowUrl.createObjectURL(blob)
var anchor = document.createElement("a")
anchor.href = downloadUrl
var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
anchor.download = fileNamePattern.exec(headers['content-disposition'])[1]
document.body.appendChild(anchor)
anchor.click()
windowUrl.revokeObjectURL(blob)
})
}