欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ajax 異步上傳帶進(jìn)度條視頻并提取縮略圖

 更新時(shí)間:2015年09月29日 12:23:47   投稿:mrr  
這篇文章主要介紹了ajax 異步上傳帶進(jìn)度條視頻并提取縮略圖的相關(guān)資料,需要的朋友可以參考下

最近在做一個(gè)集富媒體功能于一身的項(xiàng)目。需要上傳視頻。這里我希望做成異步上傳,并且有進(jìn)度條,響應(yīng)有狀態(tài)碼,視頻連接,縮略圖。

服務(wù)端響應(yīng)

 {
   "thumbnail": "/slsxpt//upload/thumbnail/fdceefc.jpg",
   "success": true,
   "link": "/slsxpt//upload/video/fdceefc.mp"
 }

并且希望我的input file控件不要被form標(biāo)簽包裹。原因是form中不能嵌套form,另外form標(biāo)簽在瀏覽器了還是有一點(diǎn)點(diǎn)默認(rèn)樣式的,搞不好又要寫(xiě)css。

以前用ajaxFileUpload做過(guò)文件異步上傳。不過(guò)這個(gè)東西好久未更新,代碼還有bug,雖然最后勉強(qiáng)成功用上了,但總覺(jué)不好。而且ajaxFileUpload沒(méi)有直接添加xhr2的progress事件響應(yīng),比較麻煩。

上網(wǎng)找了一下,發(fā)現(xiàn)方法都是很多。

比如在文件上傳后,將上傳進(jìn)度放到session中,輪詢(xún)服務(wù)器session。但我總覺(jué)的這個(gè)方法有問(wèn)題,我認(rèn)為這種方法看到的進(jìn)度,應(yīng)該是我的服務(wù)端應(yīng)用程序代碼(我的也就是action)從服務(wù)器的臨時(shí)目錄復(fù)制文件的進(jìn)度,因?yàn)樗姓?qǐng)求都應(yīng)該先提交給服務(wù)器軟件,也就是tomcat,tomcat對(duì)請(qǐng)求進(jìn)行封裝session,request等對(duì)象,并且文件實(shí)際上也應(yīng)該是它來(lái)接收的。也就是說(shuō)在我的action代碼執(zhí)行之前,文件實(shí)際上已經(jīng)上傳完畢了。

后來(lái)找到個(gè)比較好的方法使用 jquery.form.js插件的ajaxSubmit方法。這個(gè)方法以表單來(lái)提交,也就是 $.fn.ajaxSubmit.:$(form selector).ajaxSubmit({}),這個(gè)api的好處是它已經(jīng)對(duì)xhr2的progress時(shí)間進(jìn)行了處理,可以在調(diào)用時(shí)傳遞一個(gè)uploadProgress的function,在function里就能夠拿到進(jìn)度。而且如果不想input file被form包裹也沒(méi)關(guān)系,在代碼里createElement應(yīng)該可以。不過(guò)這個(gè)方法我因?yàn)榉噶藗€(gè)小錯(cuò)誤最后沒(méi)有成功,可惜了。

ajaxSubmit源碼

最后,還是使用了$.ajax 方法來(lái)做。$.ajax 不需要關(guān)聯(lián)form,有點(diǎn)像個(gè)靜態(tài)方法哦。唯一的遺憾就是$.ajax options里沒(méi)有對(duì)progress的響應(yīng)。不過(guò)它有一個(gè)參數(shù)為 xhr ,也就是你可以定制xhr,那么久可以通過(guò)xhr添加progress的事件處理程序。再結(jié)合看一看ajaxSubmit方法里對(duì)progress事件的處理,頓時(shí)豁然開(kāi)朗

那么我也可以在$.ajax 方法中添加progress事件處理函數(shù)了。為了把對(duì)dom的操作從上傳業(yè)務(wù)中抽取出來(lái),我決定以插件的形式寫(xiě)。下面是插件的代碼

 ;(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.total,
                 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(data);
           }
         },
         error      :  function(jXhr,status,error){
           if(settings.error){
             settings.error(jXhr,status,error);
           }
         }
       });
     });
   };
   $.fn.uploadFile = function (options) {
     settings = $.extend({}, defaults, options);
     // 文件上傳
     return this.each(function(){
       upload($(this));
     });
   }
 })($ || jQuery);

下面就可以在我的jsp頁(yè)面里面使用這個(gè)api了。

<div class="col-sm-">
   <input type="text" name="resource_url" id="resource_url" hidden="hidden"/>
   <div class="progress" style='display: none;'>
     <div class="progress-bar progress-bar-success uploadVideoProgress" role="progressbar"
        aria-valuenow="" 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="${baseUrl}/upload-video.action"
      data-label="<i class='glyphicon glyphicon-circle-arrow-up'></i> &nbsp;選擇文件" />
   <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>

這里在響應(yīng)succes的時(shí)候設(shè)置超時(shí)800毫秒之后獲取圖片,因?yàn)樘崛】s量圖是另一個(gè)進(jìn)程在做可能響應(yīng)完成的時(shí)候縮略圖還沒(méi)提取完成

看下效果

提取縮量圖

下面部分就是服務(wù)端處理上傳,并且對(duì)視頻提取縮量圖下面是action的處理代碼

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;
   // 省略setter getter方法
   public String video() {
     Map<String, Object> dataJson = new HashMap<String, Object>();
     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;
       // 提取縮量圖
       needThumb = true;
       thumbnailName = newFileName + ".jpg";
       thumbnailFile
           = app.getRealPath(saveBasePath + thumbnailPath) + "/" + thumbnailName;
     }
     String realPath = app.getRealPath(saveBasePath + typeDir);
     File saveFile = new File(realPath, newFileName + fileExtend);
     // 存在同名文件,跳過(guò)
     if (!saveFile.exists()) {
       if (!saveFile.getParentFile().exists()) {
         saveFile.getParentFile().mkdirs();
       }
       try {
         FileUtils.copyFile(file, saveFile);
         if(needThumb){
           extractOk = VideoUtils.extractThumbnail(saveFile, thumbnailFile);
           System.out.println("提取縮略圖成功:"+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() + "/" + saveBasePath + typeDir + "/" + newFileName + fileExtend);
       if(needThumb){
         dataJson.put("thumbnail",
             app.getContextPath() + "/" + saveBasePath + thumbnailPath + "/" + thumbnailName);
       }
     }
     this.responceJson(dataJson);
     return NONE;
   }
 }

action配置

 <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>

這里個(gè)人認(rèn)為,如果文件的名稱(chēng)跟大小完全一樣的話(huà),它們是一個(gè)文件的概率就非常大了,所以我這里取文件名跟文件大小做md5運(yùn)算,應(yīng)該可以稍微避免下重復(fù)上傳相同文件了。

轉(zhuǎn)碼的時(shí)候用到FFmpeg。需要的可以去這里下載。

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 ArrayList<String>();
     File ffmpegExe = new File(FFMPEG_EXECUTOR);
     if(!ffmpegExe.exists()){
       System.out.println("轉(zhuǎn)碼工具不存在");
       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("啟動(dòng)耗時(shí)"+(System.currentTimeMillis()-startTime));
       return true;
     } catch (IOException e) {
       e.printStackTrace();
       return false;
     }
   }
 }

另外這里由java啟動(dòng)了另外一個(gè)進(jìn)程,在我看來(lái)他們應(yīng)該是互不相干的,java啟動(dòng)了ffmpeg.exe之后,應(yīng)該回來(lái)繼續(xù)執(zhí)行下面的代碼,所以并不需要單獨(dú)起一個(gè)線(xiàn)程去提取縮量圖。測(cè)試看也發(fā)現(xiàn)耗時(shí)不多。每次長(zhǎng)傳耗時(shí)也區(qū)別不大,下面是兩次上傳同一個(gè)文件耗時(shí)

第一次

第二次

就用戶(hù)體驗(yàn)來(lái)說(shuō)沒(méi)有很大的區(qū)別。

另外這里上傳較大文件需要對(duì)tomcat和struct做點(diǎn)配置

修改tomcat下conf目錄下的server.xml文件,為Connector節(jié)點(diǎn)添加屬性 maxPostSize="0"表示不顯示上傳大小

另外修改 struts.xml添加配置,這里的value單位為字節(jié),這里大概300多mb

相關(guān)文章

  • 不使用XMLHttpRequest對(duì)象實(shí)現(xiàn)Ajax效果的方法小結(jié)

    不使用XMLHttpRequest對(duì)象實(shí)現(xiàn)Ajax效果的方法小結(jié)

    這篇文章主要介紹了不使用XMLHttpRequest對(duì)象實(shí)現(xiàn)Ajax效果的方法,結(jié)合具體實(shí)例形式分析了三種不使用XMLHttpRequest對(duì)象實(shí)現(xiàn)Ajax功能的相關(guān)實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2019-07-07
  • 解決ajax的delete、put方法接收不到參數(shù)的問(wèn)題方法

    解決ajax的delete、put方法接收不到參數(shù)的問(wèn)題方法

    今天小編就為大家分享一篇解決ajax的delete、put方法接收不到參數(shù)的問(wèn)題方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • ajax中data傳參的兩種方式分析

    ajax中data傳參的兩種方式分析

    這篇文章主要介紹了ajax中data傳參的兩種方式,結(jié)合實(shí)例形式簡(jiǎn)單分析了ajax參數(shù)傳遞的POST與GET方式,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下
    2015-12-12
  • ajax實(shí)現(xiàn)輸入提示效果

    ajax實(shí)現(xiàn)輸入提示效果

    這篇文章主要為大家詳細(xì)介紹了ajax實(shí)現(xiàn)輸入提示效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • AJAX中同時(shí)發(fā)送多個(gè)請(qǐng)求XMLHttpRequest對(duì)象處理方法

    AJAX中同時(shí)發(fā)送多個(gè)請(qǐng)求XMLHttpRequest對(duì)象處理方法

    AJAX中同時(shí)發(fā)送多個(gè)請(qǐng)求XMLHttpRequest對(duì)象處理方法...
    2007-04-04
  • 基于HTML5 Ajax實(shí)現(xiàn)文件上傳并顯示進(jìn)度條

    基于HTML5 Ajax實(shí)現(xiàn)文件上傳并顯示進(jìn)度條

    這篇文章主要介紹了基于HTML5 Ajax實(shí)現(xiàn)文件上傳并顯示進(jìn)度條的相關(guān)資料,需要的朋友可以參考下
    2016-02-02
  • 揭開(kāi)AJAX神秘的面紗(AJAX個(gè)人學(xué)習(xí)筆記)

    揭開(kāi)AJAX神秘的面紗(AJAX個(gè)人學(xué)習(xí)筆記)

    寫(xiě)這個(gè)學(xué)習(xí)筆記,只是記載一下自己的學(xué)習(xí)經(jīng)過(guò)和體會(huì),把一些學(xué)習(xí)重點(diǎn)記錄下來(lái),以備今后的鞏固復(fù)習(xí)及應(yīng)用,很多知識(shí)點(diǎn)沒(méi)有詳細(xì)介紹,所以并不完全適用于初學(xué)者,如果你是初學(xué)者,最好選擇一本AJAX學(xué)習(xí)的書(shū)籍,然后與這篇學(xué)習(xí)筆記對(duì)照學(xué)習(xí),效果會(huì)更好。
    2009-09-09
  • 使用jQuery簡(jiǎn)化Ajax開(kāi)發(fā)

    使用jQuery簡(jiǎn)化Ajax開(kāi)發(fā)

    jQuery 是一個(gè)JavaScript 庫(kù),它有助于簡(jiǎn)化 JavaScript&#8482; 以及 Asynchronous JavaScript + XML (Ajax) 編程。與類(lèi)似的 JavaScript 庫(kù)不同,jQuery 具有獨(dú)特的基本原理,可以簡(jiǎn)潔地表示常見(jiàn)的復(fù)雜代碼。
    2009-11-11
  • AJAX 驗(yàn)證框架13個(gè)

    AJAX 驗(yàn)證框架13個(gè)

    眾所周知,驗(yàn)證,最好是在客戶(hù)端盡量解決,以降低服務(wù)端資源開(kāi)銷(xiāo);在目前AJAX流行的今天,基于AJAX的驗(yàn)證更能夠?yàn)榭蛻?hù)端驗(yàn)證提供豐富的機(jī)制和美觀的交互效果。本文收集了13個(gè)比較通用的AJAX驗(yàn)證框架,與大家分享!
    2009-08-08
  • 關(guān)于Ajax的疑難雜癥詳解

    關(guān)于Ajax的疑難雜癥詳解

    這篇文章主要給大家介紹了關(guān)于Ajax的疑難雜癥,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03

最新評(píng)論