My problem is simple and complex same time:
Im tryin to upload files using jQuery fileUpload library with spring mvc controller as server side, but my files are being uploaded by one request each. What i want is posting them ALL in ONE request.
I have tried singleFileUploads: false option but its not working, if i pass 4 files to upload, the method responsible for handling the post is called 4 times.
Im using this form to post files:
<div class="upload-file-div">
<b>Choose csv files to load</b> <input id="csvUpload" type="file"
name="files[] "data-url="adminpanel/uploadCsv" multiple />
</div>
<div id="dropzoneCsv">Or drop files here</div>
<div id="progressCsv">
<div class="bar" style="width: 0%;"></div>
</div>
Jquery method to upload files:
$('#csvUpload').fileupload(
{
singleFileUploads: false,
dataType : 'json',
done : function(e, data) {
$("tr:has(td)").remove();
$.each(data.result, function(index, file) {
$("#uploaded-csv").append(
$('<tr/>').append(
$('<td/>').text(file.fileName))
.append(
$('<td/>').text(
file.fileSize))
.append(
$('<td/>').text(
file.fileType))
.append(
$('<td/>').text(
file.existsOnServer))
.append($('<td/>')));
});
},
progressall : function(e, data) {
var progress = parseInt(data.loaded / data.total * 100,
10);
$('#progressCsv .bar').css('width', progress + '%');
},
dropZone : $('#dropzoneCsv')
});
And handler method :
#RequestMapping(value = "/adminpanel/uploadCsv", method = RequestMethod.POST)
public #ResponseBody
List<FileMeta> uploadCsv(MultipartHttpServletRequest request, HttpServletResponse response) {
// 1. build an iterator
Iterator<String> itr = request.getFileNames();
MultipartFile mpf = null;
List<FileMeta> csvFiles = new ArrayList<FileMeta>();
// 2. get each file
while (itr.hasNext()) {
// 2.1 get next MultipartFile
mpf = request.getFile(itr.next());
System.out.println(mpf.getOriginalFilename() + " uploaded! ");
// 2.3 create new fileMeta
FileMeta fileMeta = new FileMeta();
fileMeta.setFileName(mpf.getOriginalFilename());
fileMeta.setFileSize(mpf.getSize() / 1024 + " Kb");
fileMeta.setFileType(mpf.getContentType());
try {
File dir = new File(Thread.currentThread().getContextClassLoader()
.getResource("").getPath()+"CSV");
if(!dir.exists()) dir.mkdirs();
File newCSV = new File(dir+"\\"+ mpf.getOriginalFilename());
if(!newCSV.exists())
{
mpf.transferTo(newCSV);
fileMeta.setExistsOnServer(false);
}
else fileMeta.setExistsOnServer(true);
} catch (IllegalStateException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// 2.4 add to files
csvFiles.add(fileMeta);
}
return csvFiles;
}
I would really need an assistance here :( Files should be loaded in one request, thats why im doing the iterator, but its just not working.
ps. Sorry for my terrible english :(
You may want to try Programmatic file upload instead. The send method will ensure only one request is issued.
Basically keep a filelist variable, update it everytime fileuploadadd callback happens, then use this filelist for the send method.
For example:
$document.ready(function(){
var filelist = [];
$('#form').fileupload({
... // your fileupload options
}).on("fileuploadadd", function(e, data){
for(var i = 0; i < data.files.length; i++){
filelist.push(data.files[i])
}
})
$('#button').click(function(){
$('#form').fileupload('send', {files:filelist});
})
})
It is inspired by this question.
The reason I found it useful is even if you set singleFileUploads to false, if you do multiple individual selections, they will still be sent with individual requests each, as the author said himself in this GitHub issue
Related
I use a image gallery plugin called Unite Gallery plugin in an ASP.NET MVC project in order to display images stored in database. However, loading all of the images at the same time takes too long time (because each photo is in 1MB-4MB size and loading 500 photos at the same time on page load is not a good idea) and I think there must be a better approach i.e. asenkron loading or partial loading. Here is my Razor and Controller code. I have a look at many pages on the wweb and docs, but there is not an example in the documentation page. Do you have any idea?
<div id="gallery" style="display:none;">
#foreach (var item in Model)
{
if (item.FileData != null)
{
var base64 = Convert.ToBase64String(item.FileData);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img alt='Image'
src="#imgSrc"
data-image="#imgSrc"
data-description='Image'>
}
}
</div>
<script type="text/javascript">
jQuery(document).ready(function () {
var gallery = jQuery("#gallery").unitegallery({
gallery_theme: "default" //theme skin
});
gallery.on("item_change", function (num, data) {
if((num%15) == 0)
{
$.ajax({
url: '#Url.Action("List", "PhotoContest")',
data: { isAll: isAllChecked, page: num }, //??? I pass the page parameter???
success: function(data){
//call is successfully completed and we got result in data
//??? NO IDEA ???
},
error:function (xhr, ajaxOptions, thrownError){
//some errror, some show err msg to user and log the error
alert(xhr.responseText);
}
});
}
});
});
</script>
public ActionResult List(string query)
{
var model = db.Photo.Select(m => new PhotoViewModel
{
Id = m.Id,
Name = m.Name,
StatusId = m.StatusId,
SubmitDate = m.SubmitDate,
FileAttachments = m.FileAttachments,
SubmitNo = m.SubmitNo
})
.ToArray();
return View("List", model);
}
Update:
After trying to apply #Kris's perfect approach, I encountered the error shown below. There is not a fix or solution regarding to this specific problem on the web. Any idea?
The image after page load overloads div and gallery borders as shown below:
Load 30 images at a time
Load remaining in Itemchange event available in Unite gallery
Main Page
<div id="gallery" >
<input type="hidden" id="galleryPage" value="0"/>
#HTML.Action("GalleryImages") //first load 30 items as PageNo = 0
</div>
<script type="text/javascript">
var gallery;
jQuery(document).ready(function () {
gallery = jQuery("#gallery").unitegallery({
gallery_theme: "default" //theme skin
});
gallery.on("item_change", function (num, data) {
//when item loaded equals to 15 or 30 or multiples of 15 another 30 items get loaded
if((num%15) == 0)
{
$.ajax({
url: '#HTML.Action("GalleryImages")'+"?pageNo="+jQuery("galleryPage").val(),
data: { isAll: isAllChecked },
success: function(data){
jQuery("gallery").append(data);//partial view with new images
jQuery("galleryPage").val(gallery.getNumItems()/30); //page number total items/number of items per page
},
error:function (xhr, ajaxOptions, thrownError){
//some errror, some show err msg to user and log the error
alert(xhr.responseText);
}
});
}
});
});
</script>
Partial View (_galleryImages.cshtml)
#foreach (var item in Model)
{
if (item.FileData != null)
{
var base64 = Convert.ToBase64String(item.FileData);
var imgSrc = String.Format("data:image/gif;base64,{0}", base64);
<img alt='Image'
src="#imgSrc"
data-image="#imgSrc"
data-description='Image'>
}
}
Controller
//Main View
public ActionResult List()
{
return View();
}
//Partial View
public Action GalleryImages(int PageNo)
{
int PageSize = 30;
var model = db.Photo.Select(m => new PhotoViewModel
{
Id = m.Id,
Name = m.Name,
StatusId = m.StatusId,
SubmitDate = m.SubmitDate,
FileAttachments = m.FileAttachments,
SubmitNo = m.SubmitNo
}).Skip(PageNo*PageSize).Take(PageSize).ToArray();
return PartialView("_galleryImages", model);
}
I don't think there's just one issue here. First, loading 100s of images all at once is going to be slow no matter what you do. For this point #Kris probably has the right idea. I'm unfamiliar with this particular library, but if it provides a way to progressively load in a handful of images at a time, you should definitely make use of that.
The second issue is that you're using base64-encoded data URIs. Images encoded in this way are roughly 150% as large as the actual image data itself. In other words, you're adding greater stress to an already stressed situation. Instead, you should have an action that returns the image data, something like:
public ActionResult GetImage(int id)
{
var image = db.Images.Find(id);
if (image == null)
{
return new HttpNotFoundResult();
}
return File(image.FileData, image.FileType);
}
You can get somewhat creative here by caching the database query result or even the entire response, but be advised that you'll need a significant amount of RAM, since you're going to be storing a lot of image data there.
Third, there's the issue of using a database to store image data in the first place. Just because databases provide a blob type, doesn't mean you need to use it. The most performant approach is always going to be serving directly from the filesystem, as IIS can serve static files directly, without involving all the ASP.NET machinery. Instead of storing the image data in your database, write the image to a filesystem location and then merely store the path to the image in the database. You could then optimize even further by actually offloading all the images to a CDN, ensuring super-fast delivery and taking virtually all load off your server.
I'm with a little problem on my project.
Hi have several jsp's and Java class. In one jsp i create a form with only a input type="file" and type="submit", then I have an ajax call and send all the formdata to a doPost class on my servel. Then I send that file to the DataBase and it all's go fine, my problem is I want to return the id from the database to the .jsp. I can access and have prints on the doPost to check my key, but cant send it to success function inside the ajax call..
Here's my code, i really apreciate any kind of help, thanks!
<form id="uploadDocuments" target="invisible" method="POST" action="UploadDocumentsAjaxService" enctype="multipart/form-data">
<iframe name="invisible" style="display:none;"></iframe>
<h3 style="width: 71%;margin-left: 8%;">ANEXAR FICHEIROS:</h3>
<h4 style="margin-left: 8%; color: #F7A707" >Escolher ficheiro para anexar: </h4>
<input type="file" id="file_input" name="file" size="50" style="width: 60%; margin-left: 8%;"/>
<input type="submit" value="Upload" />
</form>
the I have my Ajax Call:
$("#uploadDocuments").submit(function (e) {
alert(10);
alert($("#uploadDocuments").attr('action'));
$.ajax({
type: $("#uploadDocuments").attr('method'),
url: $("#uploadDocuments").attr('action'),
contentType: $("#uploadDocuments").attr( "enctype"),
data: new FormData($("#uploadDocuments")[0]),
processData: true,
success: function (data) {
alert("submitDocument");
alert();
/* key = data;
addFilesToTable(key); */
return true;
}
});
e.preventDefault();
$(form).off('submit');
return false;
});
And then my servlet class:
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
response.setContentType("text/html;charset=ISO-8859-1");
PrintWriter out = response.getWriter();
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
ChangeEntityRequestActionBean actionBean = new ChangeEntityRequestActionBean();
if(!isMultipart)
return;
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Sets the size threshold beyond which files are written directly to
// disk.
factory.setSizeThreshold(MAX_MEMORY_SIZE);
// constructs the folder where uploaded file will be stored
String uploadFolder = getServletContext().getRealPath("") + DATA_DIRECTORY;
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Set overall request size constraint
upload.setSizeMax(MAX_REQUEST_SIZE);
String fileName = "";
Long documentKey = null;
String key = "";
try {
// Parse the request
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {
fileName = new File(item.getName()).getName();
String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);
System.out.println(filePath);
// saves the file to upload directory
item.write(uploadedFile);
}
documentKey = actionBean.insertDocument(item, fileName);
System.out.println("Key from DAO ------->>>>>"+documentKey);
key = String.valueOf(documentKey);
}
System.out.println("Key in String from DAO ----->"+key);
System.out.println();
out.println("success");
response.flushBuffer();
}catch (FileUploadException ex) {
throw new ServletException(ex);
} catch (Exception ex) {
throw new ServletException(ex);
} finally {
out.close();
}
}
All I want is to send the key value to out.println so I can use that value on a jquery function
In the first line of doPost() in your servlet, change the content-type of the response to "application/json". Then write a JSON string to the output stream. There are libraries available to do this for you, but for something so simple, you can compose the JSON yourself. This might actually have an advantage because your key is a java long; treat it as a string and you don't have to worry about how the integer is represented.
// replace out.println("success"); with this:
out.print("{\"key\": \"" + key + "\"}");
Then in the success callback function, you can access the key as a field of the data object. You'll need to specify the data type in the ajax method (dataType: 'json').
success: function (data) {
var key = data['key'];
addFilesToTable(key);
return true;
}
I'm trying to upload generated client side documents (images for the moment) with Dropzone.js.
// .../init.js
var myDropzone = new Dropzone("form.dropzone", {
autoProcessQueue: true
});
Once the client have finished his job, he just have to click a save button which call the save function :
// .../save.js
function save(myDocument) {
var file = {
name: 'Test',
src: myDocument,
};
console.log(myDocument);
myDropzone.addFile(file);
}
The console.log() correctly return me the content of my document
data:image/png;base64,iVBORw0KGgoAAAANS...
At this point, we can see the progress bar uploading the document in the drop zone but the upload failed.
Here is my (standart dropzone) HTML form :
<form action="/upload" enctype="multipart/form-data" method="post" class="dropzone">
<div class="dz-default dz-message"><span>Drop files here to upload</span></div>
<div class="fallback">
<input name="file" type="file" />
</div>
</form>
I got a Symfony2 controller who receive the post request.
// Get request
$request = $this->get('request');
// Get files
$files = $request->files;
// Upload
$do = $service->upload($files);
Uploading from the dropzone (by drag and drop or click) is working and the uploads are successfull but using the myDropzone.addFile() function return me an empty object in my controller :
var_dump($files);
return
object(Symfony\Component\HttpFoundation\FileBag)#11 (1) {
["parameters":protected]=>
array(0) {
}
}
I think i don't setup correctly my var file in the save function.
I tryied to create JS image (var img = new Image() ...) but without any success.
Thanks for your help !
Finally i found a working solution without creating canvas :
function dataURItoBlob(dataURI) {
'use strict'
var byteString,
mimestring
if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
byteString = atob(dataURI.split(',')[1])
} else {
byteString = decodeURI(dataURI.split(',')[1])
}
mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0]
var content = new Array();
for (var i = 0; i < byteString.length; i++) {
content[i] = byteString.charCodeAt(i)
}
return new Blob([new Uint8Array(content)], {type: mimestring});
}
And the save function :
function save(dataURI) {
var blob = dataURItoBlob(dataURI);
myDropzone.addFile(blob);
}
The file appears correctly in dropzone and is successfully uploaded.
I still have to work on the filename (my document is named "blob").
The dataURItoBlob function have been found here : Convert Data URI to File then append to FormData
[EDIT] : I finally wrote the function in dropzone to do this job. You can check it here : https://github.com/CasperArGh/dropzone
And you can use it like this :
var dataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAmAAAAKwCAYAAA...';
myDropzone.addBlob(dataURI, 'test.png');
I can't comment currently and wanted to send this to you.
I know you found your answer, but I had some trouble using your Git code and reshaped it a little for my needs, but I am about 100% positive this will work for EVERY possible need to add a file or a blob or anything and be able to apply a name to it.
Dropzone.prototype.addFileName = function(file, name) {
file.name = name;
file.upload = {
progress: 0,
total: file.size,
bytesSent: 0
};
this.files.push(file);
file.status = Dropzone.ADDED;
this.emit("addedfile", file);
this._enqueueThumbnail(file);
return this.accept(file, (function(_this) {
return function(error) {
if (error) {
file.accepted = false;
_this._errorProcessing([file], error);
} else {
file.accepted = true;
if (_this.options.autoQueue) {
_this.enqueueFile(file);
}
}
return _this._updateMaxFilesReachedClass();
};
})(this));
};
If this is added to dropzone.js (I did just below the line with Dropzone.prototype.addFile = function(file) { potentially line 1110.
Works like a charm and used just the same as any other. myDropzone.addFileName(file,name)!
Hopefully someone finds this useful and doesn't need to recreate it!
1) You say that: "Once the client have finished his job, he just have to click a save button which call the save function:"
This implies that you set autoProcessQueue: false and intercept the button click, to execute the saveFile() function.
$("#submitButton").click(function(e) {
// let the event not bubble up
e.preventDefault();
e.stopPropagation();
// process the uploads
myDropzone.processQueue();
});
2) check form action
Check that your form action="/upload" is routed correctly to your SF controller & action.
3) Example Code
You may find a full example over at the official Wiki
4) Ok, thanks to your comments, i understood the question better:
"How can i save my base64 image resource with dropzone?"
You need to embedd the image content as value
// base64 data
var dataURL = canvas.toDataURL();
// insert the data into the form
document.getElementById('image').value = canvas.toDataURL('image/png');
//or jQ: $('#img').val(canvas.toDataURL("image/png"));
// trigger submit of the form
document.forms["form1"].submit();
You might run into trouble doing this and might need to set the "origin-clean" flag to "true". see http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#security-with-canvas-elements
how to save html5 canvas to server
I'm using Uploadify to upload some images with ASP.NET.
I use Response.WriteFile() in ASP.NET to return the result of the upload back to JavaScript.
As specified in the documentation I'm using onAllComplete event to check for response string from ASP.NET.
The problem is it that the alert(response); is always undefined in JavaScript.
JavaScript code as below:
$(document).ready(function() {
var auth = "<% = Request.Cookies[FormsAuthentication.FormsCookieName]==null ? string.Empty : Request.Cookies[FormsAuthentication.FormsCookieName].Value %>";
$('#btnUpdateProfileImg').uploadify({
'uploader': '../script/uploadify/uploadify.swf',
'script': '../uploadprofimg.aspx',
'cancelImg': '../script/uploadify/cancel.png',
'folder': '../script/uploadify',
'scriptData': { 'id': $(this).attr("id"), 'token': auth },
'onAllComplete': function(event, queueID, fileObj, response, data) {
alert(response);
}
});
});
ASP.NET code a below;
protected void Page_Load(object sender, EventArgs e)
{
try
{
string token = Request.Form["token"].ToString();
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(token);
if (ticket != null)
{
var identity = new FormsIdentity(ticket);
if (identity.IsAuthenticated)
{
HttpPostedFile hpFile = Request.Files["ProfileImage"];
string appPath = HttpContext.Current.Request.ApplicationPath;
string fullPath = HttpContext.Current.Request.MapPath(appPath) + #"\avatar\";
hpFile.SaveAs(Server.MapPath("~/" + uniqName));
Response.ContentType = "text/plain";
Response.Write("test");
}
}
}
catch (Exception ex)
{
Response.Write("test");
}
}
Reason for the FormsAuthenticationTicket object is to pass the authentication cookie though when using the Uploadify with Firefox.
I have seen many examples where Response.Write returns a value back to the onAllComplete event. But all I get is undefined.
I have also tried to use Context.Response.Write, this.Response.Write, HttpContext.Current.Response.Write. They all return undefined.
Any help appreciated.
Thanks
It seems that the onAllComplete event never fires. This is possibly because I'm automatically uploading single files rather than multiple files.
I find that the onComplete event fires and I can use that instead.
Hi I wanted to upload images(along with other form details) and preview them, using jsp and servlets. I am able to do the uploading part but could not get, how to preview the images in the frontend.
I am using YUI to implement it. Actually I am trying to reuse an example which is implemented in PHP. I am attaching my Servlet code here. In this 'completeFileName' will be populated when a upload has been done.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if(completeFileName == null) {
PrintWriter pout = response.getWriter();
JSONObject obj = new JSONObject();
obj.put("hasError", new Boolean(true));
pout.println(obj.toString());
}
try {
OutputStream out = response.getOutputStream();
Image image = Toolkit.getDefaultToolkit().getImage(completeFileName);
ImageIcon icon = new ImageIcon(image);
int height = icon.getIconHeight();
int width = icon.getIconWidth();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ImageIO.write(bi, "jpg", out);
out.flush();
} catch (Exception ex) {
}
My Jsp code looks like this:
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.0/build/connection/connection.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.0/build/utilities/utilities.js"></script>
<script type="text/javascript">
var $E = YAHOO.util.Event;
var $ = YAHOO.util.Dom.get;
var $D = YAHOO.util.Dom;
function init(){
var listImageHandler = {
success:function(o) {
var r = eval('(' + o.responseText + ')');
if(!r.hasError) {
var imageListCon = $('imageListCon');
var img = document.createElement('img');
//img.src = 'image.php?i=' + r.imageList[i];
img.src = r.fileName;
imageListCon.appendChild(img);
}
}
};
var onUploadButtonClick = function(e){
var uploadHandler = {
upload: function(o) {
//console.log(o.responseText);
$D.setStyle('indicator', 'visibility', 'hidden');
var r = eval('(' + o.responseText + ')');
if(r.hasError){
var errorString = '';
for(var i=0; i < r.errors.length; i++){
errorString += r.errors[i];
}
alert(errorString);
}else{
YAHOO.util.Connect.asyncRequest('GET', 'UploadFileServlet', listImageHandler);
}
}
};
$D.setStyle('indicator', 'visibility', 'visible');
//the second argument of setForm is crucial,
//which tells Connection Manager this is an file upload form
YAHOO.util.Connect.setForm('testForm', true);
YAHOO.util.Connect.asyncRequest('POST', 'UploadFileServlet', uploadHandler);
};
$E.on('uploadButton', 'click', onUploadButtonClick);
YAHOO.util.Connect.asyncRequest('GET', 'UploadFileServlet', listImageHandler);
}
$E.on(window, 'load', init);
</script>
</head>
<body>
<form action="UploadFileServlet" method="POST" enctype="multipart/form-data" id="testForm">
<input type="file" name="testFile"><br>
<input type="button" id="uploadButton" value="Upload"/>
</form>
<div class="restart">Redo It</div>
<div style="visibility:hidden; margin-bottom:1.5em;" id="indicator">Uploading... <img src="indicator.gif"/></div>
<div id="imageListCon">
</div>
</body>
I am unable to get the response, can anyone help in this please ?
Thanks,
Amit
try this:
http://pixeline.be/experiments/jqUploader/
Due to security limitations, you cannot preview the image on the front-end prior to uploading
If you are already able to upload the image in a folder at your server, you can easily display the image with a image control in your page. Let that folder be a temp folder which you may wish to empty after upload is completed. Then you first upload the file in the temp folder and display it to the user. If the user cancels the operation, you can delete the file from the folder.
But remember this will not be the real image preview as we generally visualize. But since this mimics the image preview, it may be a choice.
I don't know YUI, so I can't go in detail about this, but I can at least tell that there are several flaws in your logic: you're attempting to write the entire binary contents of the image back to the ajax response. This isn't going to work. In HTML you can only display images using an <img> element whose src attribute should point to a valid URL. Something like:
<img src="/images/uploadedimage.jpg">
To achieve this, just store the image at the local disk file system or a database at the server side and give in the ajax response the URL back with which the client can access the image. Let the ajax success handler create a DOM element <img> and fill its src value with the obtained URL.
You'll need to create a Servlet which listens on this URL and get the image as an InputStream from the local disk file system by FileInputStream or from the database by ResultSet#getBinaryStream() and writes it to the OutputStream of the response, along with a correct set of response headers with at least content-type. You can find here an example of such a servlet.
That said, you really don't need the Java 2D API for that. The Image and ImageIcon only unnecessarily adds much overhead. Just get it as an InputStream and write it the usual Java IO way to the OutputStream of the response.