在项目中使用了WebUpload视频上传,由于对WebUpload的配置参数上不是很了解,走了不少弯路,以下是整理出来的代码。
前台jsp页面只有通过iframe引入该文件即可。
file_uploadMutil.jsp页面
<%@page import="com.jfinal.kit.PropKit"%>
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<% String path = request.getContextPath(); %>
<!DOCTYPE html>
<html lang="zh-CN">
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" type="text/css" href="<%=path %>/res/webuploader-0.1.5/css/webuploader.css" />
<link rel="stylesheet" type="text/css" href="<%=path %>/res/image-upload/style.css" />
</head>
<div id="wrapper">
<div id="container">
<div id="uploader">
<div class="queueList">
<div id="dndArea" class="placeholder">
<div id="filePicker"></div>
<p>可将视频拖到这里,支持多张</p>
</div>
</div>
<div class="statusBar" style=";">
<div class="progress">
<span class="text">0%</span>
<span class="percentage"></span>
</div><div class="info"></div>
<div class="btns">
<div id="filePicker2"></div><div class="uploadBtn">开始上传</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript" src="<%=path %>/res/image-upload/jquery.js"></script>
<script type="text/javascript" src="<%=path %>/res/image-upload/cross.js"></script>
<script type="text/javascript" src="<%=path %>/res/webuploader-0.1.5/dist/webuploader.js"></script>
<script type="text/javascript">
$(function() {
var $wrap = $('#uploader'),
$queue = $( '<ul class="filelist"></ul>' )
.appendTo( $wrap.find( '.queueList' ) ),
$statusBar = $wrap.find( '.statusBar' ),
$info = $statusBar.find( '.info' ),
$upload = $wrap.find( '.uploadBtn' ),
$placeHolder = $wrap.find( '.placeholder' ),
$progress = $statusBar.find( '.progress' ).hide(),
fileCount = 0,
fileSize = 0,
ratio = window.devicePixelRatio || 1,
thumbnailWidth = 110 * ratio,
thumbnailHeight = 110 * ratio,
state = 'pedding',
percentages = {},
isSupportBase64 = ( function() {
var data = new Image();
var support = true;
data.onload = data.onerror = function() {
if( this.width != 1 || this.height != 1 ) {
support = false;
data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
return support;
} )(),
flashVersion = ( function() {
var version;
try {
version = navigator.plugins[ 'Shockwave Flash' ];
version = version.description;
} catch ( ex ) {
try {
version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash')
.GetVariable('$version');
} catch ( ex2 ) {
version = '0.0';
version = version.match( /\d+/g );
return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 );
} )(),
supportTransition = (function(){
var s = document.createElement('p').style,
r = 'transition' in s ||
'WebkitTransition' in s ||
'MozTransition' in s ||
'msTransition' in s ||
'OTransition' in s;
s = null;
return r;
})(),
uploader;
if ( !WebUploader.Uploader.support('flash') && WebUploader.browser.ie ) {
if (flashVersion) {
(function(container) {
window['expressinstallcallback'] = function( state ) {
switch(state) {
case 'Download.Cancelled':
alert('您取消了更新!')
break;
case 'Download.Failed':
alert('安装失败')
break;
default:
alert('安装已成功,请刷新!');
break;
delete window['expressinstallcallback'];
var swf = './expressInstall.swf';
var html = '<object type="application/' +
'x-shockwave-flash" data="' + swf + '" ';
if (WebUploader.browser.ie) {
html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
html += 'width="100%" height="100%" style="outline:0">' +
'<param name="movie" value="' + swf + '" />' +
'<param name="wmode" value="transparent" />' +
'<param name="allowscriptaccess" value="always" />' +
'</object>';
container.html(html);
})($wrap);
} else {
$wrap.html('<a href="http://www.adobe.com/go/getflashplayer" target="_blank" border="0"><img alt="get flash player" src="http://www.adobe.com/macromedia/style_guide/images/160x41_Get_Flash_Player.jpg" /></a>');
return;
} else if (!WebUploader.Uploader.support()) {
alert( 'Web Uploader 不支持您的浏览器!');
return;
uploader = WebUploader.create({
pick: {
id: '#filePicker',
label: '点击选择视频',
multiple:false
formData: {
uid: 123
dnd: '#dndArea',
paste: '#uploader',
swf: '<%=path %>/res/webuploader-0.1.5/dist/Uploader.swf',
chunked:false,
server: '<%=path %>/upfile',
accept: {
title: 'files',
extensions: 'mpg,m4v,mp4,flv,3gp,mov,avi,rmvb,mkv,wmv',
mimeTypes: 'file/*'
disableGlobalDnd: true,
thumb:{
width: 200,
height: 200,
quality: 70,
allowMagnify: false,
crop: true,
type: 'file/mp4'
compress:{
width: 600,
height: 600,
quality: 90,
allowMagnify: false,
crop: false,
preserveHeaders: true,
noCompressIfLarger: false,
compressSize: 20*1024
fileSizeLimit: 500 * 1024 * 1024,
fileSingleSizeLimit: 500 * 1024 * 1024
var array=[];
var videoNames = [];
uploader.on('uploadSuccess',function(file,response ){
array.push(response.savepath);
videoNames.push(response.filename);
$(window.parent.document).find("#files").val(array.join(","));
$(window.parent.document).find("#filenames").val(videoNames.join(","));
uploader.on( 'dndAccept', function( items ) {
var denied = false,
len = items.length,
i = 0,
unAllowed = 'text/plain;application/javascript ';
for ( ; i < len; i++ ) {
if ( ~unAllowed.indexOf( items[ i ].type ) ) {
denied = true;
break;
return !denied;
uploader.on('dialogOpen', function() {
console.log('here');
uploader.addButton({
id: '#filePicker2',
label: '继续添加'
uploader.on('ready', function() {
window.uploader = uploader;
function addFile( file ) {
console.log("addfile--file:" + file);
var $li = $( '<li id="' + file.id + '">' +
'<p class="title">' + file.name + '</p>' +
'<p class="imgWrap"></p>'+
'<p class="progress"><span></span></p>' +
'</li>' ),
$btns = $('<div class="file-panel">' +
'<span class="cancel">删除</span>' +
'<span class="rotateRight">向右旋转</span>' +
'<span class="rotateLeft">向左旋转</span></div>').appendTo( $li ),
$prgress = $li.find('p.progress span'),
$wrap = $li.find( 'p.imgWrap' ),
$info = $('<p class="error"></p>'),
showError = function( code ) {
switch( code ) {
case 'exceed_size':
text = '文件大小超出';
break;
case 'interrupt':
text = '上传暂停';
break;
default:
text = '上传失败,请重试';
break;
$info.text( text ).appendTo( $li );
if ( file.getStatus() === 'invalid' ) {
showError( file.statusText );
} else {
$wrap.text( '预览中' );
uploader.makeThumb( file, function( error, src ) {
var img;
if ( error ) {
$wrap.text( '不能预览' );
return;
if( isSupportBase64 ) {
img = $('<video width="160" height="120" controls="controls"><source src="'+src+'" type="video/'+src.substring(src.lastindexof('.'))+'">');
$wrap.empty().append( img );
} else {
$.ajax('../../server/preview.php', {
method: 'POST',
data: src,
dataType:'json'
}).done(function( response ) {
if (response.result) {
img = $('<video width="160" height="120" controls="controls"><source src="'+src+'" type="video/'+src.substring(src.lastindexof('.'))+'">');
$wrap.empty().append( img );
} else {
$wrap.text("预览出错");
}, thumbnailWidth, thumbnailHeight );
percentages[ file.id ] = [ file.size, 0 ];
file.rotation = 0;
file.on('statuschange', function( cur, prev ) {
if ( prev === 'progress' ) {
$prgress.hide().width(0);
} else if ( prev === 'queued' ) {
$li.off( 'mouseenter mouseleave' );
$btns.remove();
if ( cur === 'error' || cur === 'invalid' ) {
console.log( file.statusText );
showError( file.statusText );
percentages[ file.id ][ 1 ] = 1;
} else if ( cur === 'interrupt' ) {
showError( 'interrupt' );
} else if ( cur === 'queued' ) {
$info.remove();
$prgress.css('display', 'block');
percentages[ file.id ][ 1 ] = 0;
} else if ( cur === 'progress' ) {
$info.remove();
$prgress.css('display', 'block');
} else if ( cur === 'complete' ) {
$prgress.hide().width(0);
$li.append( '<span class="success"></span>' );
$li.removeClass( 'state-' + prev ).addClass( 'state-' + cur );
$li.on( 'mouseenter', function() {
$btns.stop().animate({height: 30});
$li.on( 'mouseleave', function() {
$btns.stop().animate({height: 0});
$btns.on( 'click', 'span', function() {
var index = $(this).index(),
switch ( index ) {
case 0:
uploader.removeFile( file );
return;
case 1:
file.rotation += 90;
break;
case 2:
file.rotation -= 90;
break;
if ( supportTransition ) {
deg = 'rotate(' + file.rotation + 'deg)';
$wrap.css({
'-webkit-transform': deg,
'-mos-transform': deg,
'-o-transform': deg,
'transform': deg
} else {
$wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')');
$li.appendTo( $queue );
function removeFile( file ) {
var $li = $('#'+file.id);
delete percentages[ file.id ];
updateTotalProgress();
$li.off().find('.file-panel').off().end().remove();
function updateTotalProgress() {
var loaded = 0,
total = 0,
spans = $progress.children(),
percent;
$.each( percentages, function( k, v ) {
total += v[ 0 ];
loaded += v[ 0 ] * v[ 1 ];
percent = total ? loaded / total : 0;
spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' );
spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' );
updateStatus();
function updateStatus() {
var text = '', stats;
if ( state === 'ready' ) {
text = '选中' + fileCount + '个视频,共' +
WebUploader.formatSize( fileSize ) + '。';
} else if ( state === 'confirm' ) {
stats = uploader.getStats();
if ( stats.uploadFailNum ) {
text = '已成功上传' + stats.successNum+ '个视频至XX相册,'+
stats.uploadFailNum + '个视频上传失败,<a class="retry" href="#">重新上传</a>失败视频或<a class="ignore" href="#">忽略</a>'
} else {
stats = uploader.getStats();
text = '共' + fileCount + '张(' +
WebUploader.formatSize( fileSize ) +
'),已上传' + stats.successNum + '张';
if ( stats.uploadFailNum ) {
text += ',失败' + stats.uploadFailNum + '张';
$info.html( text );
function setState( val ) {
var file, stats;
if ( val === state ) {
return;
$upload.removeClass( 'state-' + state );
$upload.addClass( 'state-' + val );
state = val;
switch ( state ) {
case 'pedding':
$placeHolder.removeClass( 'element-invisible' );
$queue.hide();
$statusBar.addClass( 'element-invisible' );
uploader.refresh();
break;
case 'ready':
$placeHolder.addClass( 'element-invisible' );
$( '#filePicker2' ).removeClass( 'element-invisible');
$queue.show();
$statusBar.removeClass('element-invisible');
uploader.refresh();
break;
case 'uploading':
$( '#filePicker2' ).addClass( 'element-invisible' );
$progress.show();
$upload.text( '暂停上传' );
break;
case 'paused':
$progress.show();
$upload.text( '继续上传' );
break;
case 'confirm':
$progress.hide();
$( '#filePicker2' ).removeClass( 'element-invisible' );
$upload.text( '开始上传' );
stats = uploader.getStats();
if ( stats.successNum && !stats.uploadFailNum ) {
setState( 'finish' );
return;
break;
case 'finish':
stats = uploader.getStats();
if ( stats.successNum ) {
alert( '上传成功' );
} else {
state = 'done';
location.reload();
break;
updateStatus();
uploader.onUploadProgress = function( file, percentage ) {
var $li = $('#'+file.id),
$percent = $li.find('.progress span');
$percent.css( 'width', percentage * 100 + '%' );
percentages[ file.id ][ 1 ] = percentage;
updateTotalProgress();
uploader.onFileQueued = function( file ) {
fileCount++;
fileSize += file.size;
if ( fileCount === 1 ) {
$placeHolder.addClass( 'element-invisible' );
$statusBar.show();
addFile( file );
setState( 'ready' );
updateTotalProgress();
uploader.onFileDequeued = function( file ) {
fileCount--;
fileSize -= file.size;
if ( !fileCount ) {
setState( 'pedding' );
removeFile( file );
updateTotalProgress();
uploader.on( 'all', function( type ) {
var stats;
switch( type ) {
case 'uploadFinished':
setState( 'confirm' );
break;
case 'startUpload':
setState( 'uploading' );
break;
case 'stopUpload':
setState( 'paused' );
break;
uploader.onError = function( code ) {
console.log(code);
if (code == "Q_EXCEED_NUM_LIMIT") {
alert("只能上传1个视频");
}else if(code=='Q_EXCEED_SIZE_LIMIT'){
alert('添加的文件总大小超出最大值500M');
}else if(code=='F_EXCEED_SIZE'){
alert('上传视频不能超过500M');
}else{
alert('非法的文件类型');
$upload.on('click', function() {
if ( $(this).hasClass( 'disabled' ) ) {
return false;
if ( state === 'ready' ) {
uploader.upload();
} else if ( state === 'paused' ) {
uploader.upload();
} else if ( state === 'uploading' ) {
uploader.stop();
$info.on( 'click', '.retry', function() {
uploader.retry();
$info.on( 'click', '.ignore', function() {
alert( 'todo' );
$upload.addClass( 'state-' + state );
updateTotalProgress();
</script>
</body>
</html>
刚开始的时候由于有chunked参数,导致上传大视频文件的时候会产生多个小文件,chunkSize为分片文件大小。
前台页面引入方式:
<td class="value" width="20%"><label class="Validform_label">视频上传</label></td>
<td class="txt_value" colspan="3">
<div style="width:588px;height: 312px;">
<iframe scrolling="no" frameborder="0" id="FrameVideoID" name="FrameVideoID" src="<%=path%>/res/image-upload/file_uploadMutil.jsp" style="width:90%;height:100%;"></iframe>
<input type="hidden" id="files" name="files"/>
<input type="hidden" id="filenames" name="filenames"/>
</div>
引入WebUpload的js和css等文件,最后运行效果如下。
<link rel="stylesheet" type="text/css" href="<%=path %>/res/webuploader-0.1.5/css/webuploader.css" />
<link rel="stylesheet" type="text/css" href="<%=path %>/res/image-upload/style.css" />
由于我司业务关系,需实现兼容IE8+浏览器的视频上传功能,且支持多选断点上传。故借助Baidu WebFE(FEX)团队开发的webuploader文件上传插件实现此业务功能。
文件上传的一般联调步骤
1.js端认证(主要是判断视频是否已存在,若已存在,返回视频已上传的文件大小,只需要判断一次):
第一步:计算视频文件的md5,视频文件越大、计算md5的时间越久
第二步:获取视频文件...
如图所示:application.properties文件中的app.upload.location就是上传文件时所需要的额参数key了
2.通过上面配置文件中写了各个参数,下面怎么在Controlle里面读取?
本来在控制器方法里面写上传下载的默认路径是这样的
由于采用了配置文件,所以就用读取配置文件的方式去处理这个文件路径
①删掉之前的String path = "d:/uploaded";
②在Controller的方法上面定义文件路径属性
如图所示,.
<script type="text/javascript" src="{{ static_url('plupload/js/plupload.full.min.js') }}"></script>
2.html页面如图:
<label>上传视频:</label>
<input type=&qu
之前有人让我做一个
webuploader上传视频,但是一直没有时间,现在抽出了时间来。来完成以下这个简单的
demo
第一步,
上传视频和
上传 图片有什么区别么?
其实是没有的,因为执行的操作都是
上传,所以说我们并不用担心
上传的问题。
但是
webuploader实际上是限制了你
上传的参数(这里指的是限制了你的文件扩展名)
我们找到
webuploader中的js参数accept中的extensions
webuplader是百度的一个前端开源上传插件,支持加密、分片上传。还是阔以的。
不过文档写的实在是不敢恭维,挫到爆,gettting start介绍快速开始,写的都是缺少东西的,直接复制下来是不可以运行的。
总结出一个经验,测试html最好还是使用jsp,不然修改了页面,浏览器上总是有缓存,清缓存是个很蛋疼的事情。
1. 引如外部资源 css,js文件
这里${ctxStati
之前有人让我做一个
webuploader上传视频,但是一直没有时间,现在抽出了时间来。来完成以下这个简单的
demo
第一步,
上传视频和
上传 图片有什么区别么?
其实是没有的,因为执行的操作都是
上传,所以说我们并不用担心
上传的问题。
但是
webuploader实际上是限制了你
上传的参数(这里指的是限制了你的文件扩展名)
我们找到
webuploader中的js参数accept中的extensions
accept: {
title: 'Images',
exten
前段时间一直在做一个生物资源共享平台,采用SSM框架技术,其中涉及一个模块,是关于视频资源的播放。
本来不是很大的问题,但是无奈用户要求较多,需要支持N种格式的视频播放,没有办法,转码是必不可少的了。
对于一个从来没接触过这些什么音频视频编码格式的我,浪费了很长时间,其中很多博客的教学都不太完善。
反正就是有一堆麻烦事...
开发过程中我们难免会遇到上传视频的需求。如果视频过大或者后端需要将前端上传的视频切割为播放更友好的m8u3格式,我们的分段上传视频就显得尤为重要
一、注意事项
下面的代码基于vue2.0框架使用混入的方法进行调用。需要注意的是如果你的项目使用了ESlint需要关闭while (true) 循环条件永恒进入的校验 or 用自己方法编写也是可以的
二、使用步骤
1.组件代码
/* 使用示例
使用时更改自己的接口地址 使用到依赖axios
import upviedo from './upvid
一、上传功能
首先引用基于jquery的百度上传组件webuploader(webuploader.css,webuploader.js)(jquery版本要求>1.10,webuploader版本:0.1.5),下载链接:http://www.jq22.com/jquery-info2665
<link rel="stylesheet" type="text/css" href=...
众所皆知,web上传大文件,一直是一个痛。上传文件大小限制,页面响应时间超时.这些都是web开发所必须直面的。
本文给出的解决方案是:前端实现数据流分片长传,后面接收完毕后合并文件的思路。
实现文件夹上传,要求:服务端保留层级结构,支持10w级别的文件夹上传。
大文件上传及断点续传,要求:支持50G级的单个文件上传和续传。续传要求:在刷新浏览器后能够续传上传,在重启浏览器后能够继续上传上(关...
启动tomcat报 Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContex
106722