Ajax asynchronous upload with progress bar video and extract thumbnail _ajax related

Source: Internet
Author: User
Tags file upload tomcat

Recently in a collection of rich media features in a project. Need to upload video. Here I would like to make an asynchronous upload, and have a progress bar, the response has status code, video connection, thumbnails.

Service-side response

 {
   "thumbnail": "/slsxpt//upload/thumbnail/fdceefc.jpg",
   "Success": True,
   "link": "/slsxpt//upload/ Video/fdceefc.mp "
 }

And I want my input file control to not be wrapped by a form tag. The reason is that the form can not be nested form, another form tag in the browser or a little default style, do not want to write CSS.

Previously done with Ajaxfileupload file asynchronous upload. But this thing has not been updated for a long time, code and bugs, although the last reluctantly successful use, but always feel bad. and ajaxfileupload not directly add XHR2 Progress event response, more trouble.

Search the Internet and find a lot of ways.

For example, after the file upload, upload progress to the session, polling server session. But I always feel that this approach is problematic, and I think this approach should see the progress of my server application code (my action) copying files from the temporary directory of the servers, because all requests should be submitted to the Server software first, Tomcat, Tomcat encapsulates the request with objects such as Session,request, and the file should actually be received by it. That means the file is actually uploaded before my action code executes.

Later found a better way to use the Jquery.form.js plug-in Ajaxsubmit method. This method is submitted as a table forms, that is, $.fn.ajaxsubmit.:$ (form selector). Ajaxsubmit ({}), the advantage of this API is that it has already processed xhr2 progress time. You can pass a uploadprogress function in the call and you can get the progress in the function. And if you don't want to input file to be a form package it doesn't matter, in the code createelement should be able to. But I did not succeed in this way because I made a small mistake, but unfortunately.

Ajaxsubmit Source

Finally, we use the $.ajax method to do it. $.ajax does not need to associate form, a bit like a static method Oh. The only regret is that there is no response to progress in $.ajax options. However, it has a parameter of XHR, that is, you can customize XHR, so long you can add progress event handlers through XHR. Combined with a look at the Ajaxsubmit method to deal with the progress incident, suddenly suddenly enlightened

Then I can also add the Progress event handler in the $.ajax method. To extract the operation of the DOM from the upload business, I decided to write it as a plugin. Here is the code for the plug-in

 ;(function ($) {var defaults = {Uploadprogress:null, beforesend:null, success
   : null,}, setting = {}; 
       var upload = function ($this) {$this. Parent (). On (' Change ', $this, function (event) {//var $this = $ (event.target), var formData = new FormData (), target = Event.target | |
       Event.srcelement;
       $.each (Target.files, function (key, value)//{//Console.log (key);
       Formdata.append (key, value);
       //});
       Formdata.append (' file ', target.files[]);
       Settings.filetype && formdata.append (' FileType ', settings.filetype);
         $.ajax ({URL: $this. Data (' URL '), type: "POST", Data:formdata,
         DataType: ' json ', Processdata:false, Contenttype:false, Cache:false,
           Beforesend:function () {//console.log (' start '); if (setTings.beforesend) {settings.beforesend ();
           }, Xhr:function () {var xhr = $.ajaxsettings.xhr (); if (xhr.upload) {Xhr.upload.addEventListener (' progress '), function (event) {var total = Event.tota L, Position = event.loaded | |
               Event.position, percent =;
               if (event.lengthcomputable) {percent = Math.ceil (Position/total *);
               } if (settings.uploadprogress) {settings.uploadprogress (event, position, total, percent);
           }}, False);
         return XHR; }, Success:function (DATA,STATUS,JXHR) {if (settings.success) {settings.success (dat
           a); }}, Error:function (Jxhr,status,error) {if (settings.error) {Settings.err
         or (Jxhr,status,error);  }
         }
       });
   });
   };
     $.fn.uploadfile = function (options) {settings = $.extend ({}, defaults, options);
     File Upload return This.each (function () {Upload ($ (this));
   }); }) ($ | | | jQuery);

You can use this API in my JSP page below.

<div class= "col-sm-" > <input type= "text" name= "Resource_url" id= "Resource_url" hidden= "hidden"/> <di V class= "Progress" style= ' display:none; ' > <div class= "Progress-bar progress-bar-success uploadvideoprogress" role= "ProgressBar" "Aria-valuemin=" "aria-valuemax=" "style=" width:% "> </div> </div> <input type=" file "class= "Form-control file inline btn btn-primary uploadinput uploadvideo" accept= "VIDEO/MP" data-url= Ad-video.action "data-label=" <i class= ' Glyphicon glyphicon-circle-arrow-up ' ></i>   selection file/>
             T;script> (function ($) {$ (document). Ready (function () {var $progress = $ ('. Uploadvideoprogress '),
         start = false; $ (' Input.uploadInput.uploadVideo '). UploadFile ({beforesend:function () {$progress. Parent (). Show
           (); }, Uploadprogress:function (event, PositiOn, total, percent) {$progress. attr (' Aria-valuenow ', percent);
             $progress. Width (percent+ '% ');
               If (Percent >=) {$progress. Parent (). Hide ();
               $progress. attr (' Aria-valuenow ');
             $progress. Width (+ '% '); }}, Success:function (data) {if (data.success) {settimeout (function
               () {$ (' #thumbnail '). attr (' src ', data.thumbnail);
             },);
       }
           }
         });
     });
   }) (JQuery); </script> </div>

Here, in response to Succes, set a timeout of 800 milliseconds to get the picture, because the extraction thumbnail is another process that has not yet been extracted when the possible response is complete.

Look at the effect.

Extract thumbnail

The following section is the server-side processing upload, and the video extraction of the thumbnail below is the action of the processing code

Package org.lyh.app.actions;
 Import Org.apache.commons.io.FileUtils;
 Import Org.apache.struts.ServletActionContext;
 Import org.lyh.app.base.BaseAction;
 Import Org.lyh.library.SiteHelpers;
 Import Org.lyh.library.VideoUtils;
 Import Java.io.File;
 Import java.io.IOException;
 Import Java.security.KeyStore;
 Import Java.util.HashMap;
 Import Java.util.Map;
 /** * Created by admin on//.
   * * public class Uploadaction extends baseaction{private String savebasepath;
   Private String ImagePath;
   Private String Videopath;
   Private String audiopath;
   Private String Thumbnailpath;
   private file file;
   Private String Filefilename;
   Private String Filecontenttype; Omit Setter Getter method public String video () {map<string, object> Datajson = new hashmap<string, Object&gt
     ;();
     System.out.println (file);
     System.out.println (Filefilename);
     System.out.println (Filecontenttype); String fileextend = filefilename.substring (filefilename.lastindexof("."));
     String NewFileName = sitehelpers.md (Filefilename + file.gettotalspace ());
     String Typedir = "normal";
     String thumbnailname = Null,thumbnailfile = null;
     Boolean needthumb = False,extractok = false;
       if (Filecontenttype.contains ("video")) {typedir = Videopath;
       Extract Indent Graph Needthumb = true;
       Thumbnailname = NewFileName + ". jpg";
     Thumbnailfile = App.getrealpath (Savebasepath + thumbnailpath) + "/" + thumbnailname;
     String Realpath = App.getrealpath (Savebasepath + typedir);
     File SaveFile = new file (Realpath, NewFileName + fileextend); There is a file with the same name, skipping if (!savefile.exists ()) {if (!savefile.getparentfile (). exists ()) {Savefile.getparentfi
       Le (). Mkdirs ();
         try {fileutils.copyfile (file, savefile);
           if (needthumb) {Extractok = Videoutils.extractthumbnail (SaveFile, thumbnailfile);
         System.out.println ("Extract thumbnail success:" +extractok);
 }        Datajson.put ("Success", true);
         catch (IOException e) {System.out.println (E.getmessage ());
       Datajson.put ("Success", false);
     }}else{Datajson.put ("Success", true); } if ((Boolean) datajson.get ("Success")) {datajson.put ("link", App.getcontextpath () + "/" + SAVEBASEP
       Ath + typedir + "/" + NewFileName + fileextend);  if (needthumb) {datajson.put ("thumbnail", App.getcontextpath () + "/" + Savebasepath + Thumbnailpath +
       "/" + thumbnailname);
     } This.responcejson (Datajson);
   return NONE; }
 }

Action Configuration

 <action name= "upload-*" class= "uploadaction" method= "{}" > <param name= "Savebasepath"
     >/upload</ param>
     <param name= "ImagePath" >/images</param>
     <param name= "Videopath" >/video</ param>
     <param name= "audiopath" >/audio</param>
     <param name= "Thumbnailpath" >/ Thumbnail</param>
 </action>

Here personally think, if the file name and size exactly the same, they are a file of the probability is very large, so I take the filename here and file size to do MD5 operations, should be able to slightly avoid the duplicate upload the same file.

When you turn the code, you use the ffmpeg. Need can go here to download.

Package org.lyh.library;
 Import Java.io.File;
 Import java.io.IOException;
 Import Java.io.InputStream;
 Import java.util.ArrayList;
 Import java.util.List;
 /** * Created by admin on//.
   * * Public class Videoutils {public static final String ffmpeg_executor = "C:/software/ffmpeg.exe";
   public static final int thumbnail_width =;
   public static final int thumbnail_height =; public static Boolean Extractthumbnail (File inputfile,string thumbnailoutput) {list<string> command = new Array
     List<string> ();
     File Ffmpegexe = new file (ffmpeg_executor);
       if (!ffmpegexe.exists ()) {System.out.println ("transcoding tool does not exist");
     return false;
     } System.out.println (Ffmpegexe.getabsolutepath ());
     System.out.println (Inputfile.getabsolutepath ());
     Command.add (Ffmpegexe.getabsolutepath ());
     Command.add ("I");
     Command.add (Inputfile.getabsolutepath ());
     Command.add ("Y");
     Command.add ("F");
     Command.add ("image"); Command.add("-ss");
     Command.add ("");
     Command.add ("-t");
     Command.add (".");
     Command.add ("-S");
     Command.add (thumbnail_width+ "*" +thumbnail_height);
     Command.add (Thumbnailoutput);
     Processbuilder builder = new Processbuilder ();
     Builder.command (command);
     Builder.redirecterrorstream (TRUE);
       try {Long starttime = System.currenttimemillis ();
       Process process = Builder.start ();
       System.out.println ("Start time consuming" + (System.currenttimemillis ()-starttime));
     return true;
       catch (IOException e) {e.printstacktrace ();
     return false; }
   }
 }

In addition here by Java started another process, in my opinion they should be irrelevant, Java started Ffmpeg.exe, should come back to continue to execute the following code, so do not need a separate thread to extract the thumbnail. The test also found that the time was not too time-consuming. The time of the long pass is not very different, the following is two times to upload the same file time consuming

First time

Second time

There is no big difference in the user experience.

In addition, uploading larger files here requires a bit of configuration for Tomcat and struct.

Modify the Server.xml file in the tomcat below Conf directory, add properties for Connector node maxpostsize= "0" indicates no upload size

In addition, modify the Struts.xml add configuration, where the value unit is byte, here about 300 MB

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.