本篇文章給大家分享的是有關(guān)ajax異步上傳帶進(jìn)度條視頻并提取縮略圖的示例分析,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
在雙清等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站 網(wǎng)站設(shè)計(jì)制作定制制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營銷型網(wǎng)站,成都外貿(mào)網(wǎng)站建設(shè)公司,雙清網(wǎng)站建設(shè)費(fèi)用合理。
最近在做一個(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)樣式的,搞不好又要寫css。
以前用ajaxFileUpload做過文件異步上傳。不過這個(gè)東西好久未更新,代碼還有bug,雖然最后勉強(qiáng)成功用上了,但總覺不好。而且ajaxFileUpload沒有直接添加xhr2的progress事件響應(yīng),比較麻煩。
上網(wǎng)找了一下,發(fā)現(xiàn)方法都是很多。
比如在文件上傳后,將上傳進(jìn)度放到session中,輪詢服務(wù)器session。但我總覺的這個(gè)方法有問題,我認(rèn)為這種方法看到的進(jìn)度,應(yīng)該是我的服務(wù)端應(yīng)用程序代碼(我的也就是action)從服務(wù)器的臨時(shí)目錄復(fù)制文件的進(jìn)度,因?yàn)樗姓埱蠖紤?yīng)該先提交給服務(wù)器軟件,也就是tomcat,tomcat對請求進(jìn)行封裝session,request等對象,并且文件實(shí)際上也應(yīng)該是它來接收的。也就是說在我的action代碼執(zhí)行之前,文件實(shí)際上已經(jīng)上傳完畢了。
后來找到個(gè)比較好的方法使用 jquery.form.js插件的ajaxSubmit方法。這個(gè)方法以表單來提交,也就是 $.fn.ajaxSubmit.:$(form selector).ajaxSubmit({}),這個(gè)api的好處是它已經(jīng)對xhr2的progress時(shí)間進(jìn)行了處理,可以在調(diào)用時(shí)傳遞一個(gè)uploadProgress的function,在function里就能夠拿到進(jìn)度。而且如果不想input file被form包裹也沒關(guān)系,在代碼里createElement應(yīng)該可以。不過這個(gè)方法我因?yàn)榉噶藗€(gè)小錯誤最后沒有成功,可惜了。
ajaxSubmit源碼
最后,還是使用了$.ajax 方法來做。$.ajax 不需要關(guān)聯(lián)form,有點(diǎn)像個(gè)靜態(tài)方法哦。唯一的遺憾就是$.ajax options里沒有對progress的響應(yīng)。不過它有一個(gè)參數(shù)為 xhr ,也就是你可以定制xhr,那么久可以通過xhr添加progress的事件處理程序。再結(jié)合看一看ajaxSubmit方法里對progress事件的處理,頓時(shí)豁然開朗
那么我也可以在$.ajax 方法中添加progress事件處理函數(shù)了。為了把對dom的操作從上傳業(yè)務(wù)中抽取出來,我決定以插件的形式寫。下面是插件的代碼
;(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頁面里面使用這個(gè)api了。
選擇文件" />
這里在響應(yīng)succes的時(shí)候設(shè)置超時(shí)800毫秒之后獲取圖片,因?yàn)樘崛】s量圖是另一個(gè)進(jìn)程在做可能響應(yīng)完成的時(shí)候縮略圖還沒提取完成
看下效果
提取縮量圖
下面部分就是服務(wù)端處理上傳,并且對視頻提取縮量圖下面是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() { MapdataJson = new HashMap (); 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); // 存在同名文件,跳過 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配置
/upload /images /video /audio /thumbnail
這里個(gè)人認(rèn)為,如果文件的名稱跟大小完全一樣的話,它們是一個(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){ Listcommand = new ArrayList (); 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("啟動耗時(shí)"+(System.currentTimeMillis()-startTime)); return true; } catch (IOException e) { e.printStackTrace(); return false; } } }
另外這里由java啟動了另外一個(gè)進(jìn)程,在我看來他們應(yīng)該是互不相干的,java啟動了ffmpeg.exe之后,應(yīng)該回來繼續(xù)執(zhí)行下面的代碼,所以并不需要單獨(dú)起一個(gè)線程去提取縮量圖。測試看也發(fā)現(xiàn)耗時(shí)不多。每次長傳耗時(shí)也區(qū)別不大,下面是兩次上傳同一個(gè)文件耗時(shí)
第一次
第二次
就用戶體驗(yàn)來說沒有很大的區(qū)別。
另外這里上傳較大文件需要對tomcat和struct做點(diǎn)配置
修改tomcat下conf目錄下的server.xml文件,為Connector節(jié)點(diǎn)添加屬性 maxPostSize="0"表示不顯示上傳大小
另外修改 struts.xml添加配置,這里的value單位為字節(jié),這里大概300多mb
以上就是ajax異步上傳帶進(jìn)度條視頻并提取縮略圖的示例分析,小編相信有部分知識點(diǎn)可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。