最近在做一个集富媒体功能于一身的项目。需要上传视频。这里我希望做成异步上传,并且有进度条,响应有状态码,视频连接,缩略图。
服务端响应
{
"thumbnail": "/slsxpt//upload/thumbnail/fdceefc.jpg",
"success": true,
"link": "/slsxpt//upload/video/fdceefc.mp"
}
</div>
并且希望我的input file控件不要被form标签包裹。原因是form中不能嵌套form,另外form标签在浏览器了还是有一点点默认样式的,搞不好又要写css。
以前用ajaxFileUpload做过文件异步上传。不过这个东西好久未更新,代码还有bug,虽然最后勉强成功用上了,但总觉不好。而且ajaxFileUpload没有直接添加xhr2的progress事件响应,比较麻烦。
上网找了一下,发现方法都是很多。
比如在文件上传后,将上传进度放到session中,轮询服务器session。但我总觉的这个方法有问题,我认为这种方法看到的进度,应该是我的服务端应用程序代码(我的也就是action)从服务器的临时目录复制文件的进度,因为所有请求都应该先提交给服务器软件,也就是tomcat,tomcat对请求进行封装session,request等对象,并且文件实际上也应该是它来接收的。也就是说在我的action代码执行之前,文件实际上已经上传完毕了。
后来找到个比较好的方法使用 jquery.form.js插件的ajaxSubmit方法。这个方法以表单来提交,也就是 $.fn.ajaxSubmit.:$(form selector).ajaxSubmit({}),这个api的好处是它已经对xhr2的progress时间进行了处理,可以在调用时传递一个uploadProgress的function,在function里就能够拿到进度。而且如果不想input file被form包裹也没关系,在代码里createElement应该可以。不过这个方法我因为犯了个小错误最后没有成功,可惜了。
ajaxSubmit源码
最后,还是使用了$.ajax 方法来做。$.ajax 不需要关联form,有点像个静态方法哦。唯一的遗憾就是$.ajax options里没有对progress的响应。不过它有一个参数为 xhr ,也就是你可以定制xhr,那么久可以通过xhr添加progress的事件处理程序。再结合看一看ajaxSubmit方法里对progress事件的处理,顿时豁然开朗

那么我也可以在$.ajax 方法中添加progress事件处理函数了。为了把对dom的操作从上传业务中抽取出来,我决定以插件的形式写。下面是插件的代码
;(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);
</div>
下面就可以在我的jsp页面里面使用这个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> 选择文件" />
<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>
</div>
这里在响应succes的时候设置超时800毫秒之后获取图片,因为提取缩量图是另一个进程在做可能响应完成的时候缩略图还没提取完成
看下效果

提取缩量图
下面部分就是服务端处理上传,并且对视频提取缩量图下面是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";

