WebUploader是由Baidu团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥html5的优势,同时又不摒弃主流IE浏览器,沿用原来的FLASH运行时,兼容IE6+,iOS 6+, Android 4+。两套运行时,同样的调用方式,可供用户任意选用。 采用大文件分片并发上传,极大的提高了文件上传效率。
官方文档及更多示例请参考: http://fex.baidu.com/webuploader/
不扯废话了,由于我需要的只是上传图片功能,官网上边还说“WebUploader只包含文件上传的底层实现,不包括UI部分,所以交互方面可以自由发挥。”但是我又看到官网的例子不错,就把demo的js和css扒了下来.
前台相关代码:
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>uploadTest Demo
您可以尝试文件拖拽,使用QQ截屏工具,然后激活窗口后粘贴,或者点击添加图片按钮,来体验此demo.
或将照片拖到这里,单次最多可选300张
uploader_demo.js
jQuery(function() { var $ = jQuery, // just in case. Make sure it's not an other libaray. $wrap = $('#uploader'), // 图片容器 $queue = $('
' + file.name + '
' + ''+ '' + '
' +
'删除' +
'向右旋转' +
'向左旋转
').appendTo( $li ),
$prgress = $li.find('p.progress span'),
$wrap = $li.find( 'p.imgWrap' ),
$info = $(''),
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 {
// @todo lazyload
$wrap.text( '预览中' );
uploader.makeThumb( file, function( error, src ) {
if ( error ) {
$wrap.text( '不能预览' );
return;
}
var img = $('');
$wrap.empty().append( img );
}, 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' ) {
percentages[ file.id ][ 1 ] = 0;
} else if ( cur === 'progress' ) {
$info.remove();
$prgress.css('display', 'block');
} else if ( cur === 'complete' ) {
$li.append( '' );
}
$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(),
deg;
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) +')');
// use jquery animate to rotation
// $({
// rotation: rotation
// }).animate({
// rotation: file.rotation
// }, {
// easing: 'linear',
// step: function( now ) {
// now = now * Math.PI / 180;
// var cos = Math.cos( now ),
// sin = Math.sin( now );
// $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')");
// }
// });
}
});
$li.appendTo( $queue );
}
// 负责view的销毁
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 + '张照片上传失败,重新上传失败图片或忽略'
}
} 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.parent().removeClass('filled');
$queue.hide();
$statusBar.addClass( 'element-invisible' );
uploader.refresh();
break;
case 'ready':
$placeHolder.addClass( 'element-invisible' );
$( '#filePicker2' ).removeClass( 'element-invisible');
$queue.parent().addClass('filled');
$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();
$upload.text( '开始上传' ).addClass( 'disabled' );
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 ) {
alert( 'Eroor: ' + code );
};
$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 );
updateTotalProgres});
uploader_demo.css
#container { color: #838383; font-size: 12px; } #uploader .queueList { margin: 20px; border: 3px dashed #e6e6e6; } #uploader .queueList.filled { padding: 17px; margin: 0; border: 3px dashed transparent; } #uploader .queueList.webuploader-dnd-over { border: 3px dashed #999999; } #uploader p {margin: 0;} .element-invisible { position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px,1px,1px,1px); } #uploader .placeholder { min-height: 350px; padding-top: 178px; text-align: center; background: url(../images/image.png) center 93px no-repeat; color: #cccccc; font-size: 18px; position: relative; } #uploader .placeholder .webuploader-pick { font-size: 18px; background: #00b7ee; border-radius: 3px; line-height: 44px; padding: 0 30px; *width: 120px; color: #fff; display: inline-block; margin: 0 auto 20px auto; cursor: pointer; box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); } #uploader .placeholder .webuploader-pick-hover { background: #00a2d4; } #uploader .placeholder .flashTip { color: #666666; font-size: 12px; position: absolute; width: 100%; text-align: center; bottom: 20px; } #uploader .placeholder .flashTip a { color: #0785d1; text-decoration: none; } #uploader .placeholder .flashTip a:hover { text-decoration: underline; } #uploader .filelist { list-style: none; margin: 0; padding: 0; } #uploader .filelist:after { content: ''; display: block; width: 0; height: 0; overflow: hidden; clear: both; } #uploader .filelist li { width: 110px; height: 110px; background: url(../images/bg.png) no-repeat; text-align: center; margin: 0 8px 20px 0; position: relative; display: inline; float: left; overflow: hidden; font-size: 12px; } #uploader .filelist li p.log { position: relative; top: -45px; } #uploader .filelist li p.title { position: absolute; top: 0; left: 0; width: 100%; overflow: hidden; white-space: nowrap; text-overflow : ellipsis; top: 5px; text-indent: 5px; text-align: left; } #uploader .filelist li p.progress { position: absolute; width: 100%; bottom: 0; left: 0; height: 8px; overflow: hidden; z-index: 50; margin: 0; border-radius: 0; background: none; -webkit-box-shadow: 0 0 0; } #uploader .filelist li p.progress span { display: none; overflow: hidden; width: 0; height: 100%; background: #1483d8 url(../images/progress.png) repeat-x; -webit-transition: width 200ms linear; -moz-transition: width 200ms linear; -o-transition: width 200ms linear; -ms-transition: width 200ms linear; transition: width 200ms linear; -webkit-animation: progressmove 2s linear infinite; -moz-animation: progressmove 2s linear infinite; -o-animation: progressmove 2s linear infinite; -ms-animation: progressmove 2s linear infinite; animation: progressmove 2s linear infinite; -webkit-transform: translateZ(0); } @-webkit-keyframes progressmove { 0% { background-position: 0 0; } 100% { background-position: 17px 0; } } @-moz-keyframes progressmove { 0% { background-position: 0 0; } 100% { background-position: 17px 0; } } @keyframes progressmove { 0% { background-position: 0 0; } 100% { background-position: 17px 0; } } #uploader .filelist li p.imgWrap { position: relative; z-index: 2; line-height: 110px; vertical-align: middle; overflow: hidden; width: 110px; height: 110px; -webkit-transform-origin: 50% 50%; -moz-transform-origin: 50% 50%; -o-transform-origin: 50% 50%; -ms-transform-origin: 50% 50%; transform-origin: 50% 50%; -webit-transition: 200ms ease-out; -moz-transition: 200ms ease-out; -o-transition: 200ms ease-out; -ms-transition: 200ms ease-out; transition: 200ms ease-out; } #uploader .filelist li img { width: 100%; } #uploader .filelist li p.error { background: #f43838; color: #fff; position: absolute; bottom: 0; left: 0; height: 28px; line-height: 28px; width: 100%; z-index: 100; } #uploader .filelist li .success { display: block; position: absolute; left: 0; bottom: 0; height: 40px; width: 100%; z-index: 200; background: url(../images/success.png) no-repeat right bottom; } #uploader .filelist div.file-panel { position: absolute; height: 0; filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#80000000', endColorstr='#80000000')\0; background: rgba( 0, 0, 0, 0.5 ); width: 100%; top: 0; left: 0; overflow: hidden; z-index: 300; } #uploader .filelist div.file-panel span { width: 24px; height: 24px; display: inline; float: right; text-indent: -9999px; overflow: hidden; background: url(../../img/uploader_icons.png) no-repeat; margin: 5px 1px 1px; cursor: pointer; } #uploader .filelist div.file-panel span.rotateLeft { background-position: 0 -24px; } #uploader .filelist div.file-panel span.rotateLeft:hover { background-position: 0 0; } #uploader .filelist div.file-panel span.rotateRight { background-position: -24px -24px; } #uploader .filelist div.file-panel span.rotateRight:hover { background-position: -24px 0; } #uploader .filelist div.file-panel span.cancel { background-position: -48px -24px; } #uploader .filelist div.file-panel span.cancel:hover { background-position: -48px 0; } #uploader .statusBar { height: 63px; border-top: 1px solid #dadada; padding: 0 20px; line-height: 63px; vertical-align: middle; position: relative; } #uploader .statusBar .progress { border: 1px solid #1483d8; width: 198px; background: #fff; height: 18px; position: relative; display: inline-block; text-align: center; line-height: 20px; color: #6dbfff; position: relative; margin: 0 10px 0 0; } #uploader .statusBar .progress span.percentage { width: 0; height: 100%; left: 0; top: 0; background: #1483d8; position: absolute; } #uploader .statusBar .progress span.text { position: relative; z-index: 10; } #uploader .statusBar .info { display: inline-block; font-size: 14px; color: #666666; } #uploader .statusBar .btns { position: absolute; top: 10px; right: 20px; line-height: 40px; } #filePicker2 { display: inline-block; float: left; } #uploader .statusBar .btns .webuploader-pick, #uploader .statusBar .btns .uploadBtn, #uploader .statusBar .btns .uploadBtn.state-uploading, #uploader .statusBar .btns .uploadBtn.state-paused { background: #ffffff; border: 1px solid #cfcfcf; color: #565656; padding: 0 18px; display: inline-block; border-radius: 3px; margin-left: 10px; cursor: pointer; font-size: 14px; float: left; } #uploader .statusBar .btns .webuploader-pick-hover, #uploader .statusBar .btns .uploadBtn:hover, #uploader .statusBar .btns .uploadBtn.state-uploading:hover, #uploader .statusBar .btns .uploadBtn.state-paused:hover { background: #f0f0f0; } #uploader .statusBar .btns .uploadBtn { background: #00b7ee; color: #fff; border-color: transparent; } #uploader .statusBar .btns .uploadBtn:hover { background: #00a2d4; } #uploader .statusBar .btns .uploadBtn.disabled { pointer-events: none; opacity: 0.6; }
后台代码:
@Controller @RequestMapping("/upload") public class UpLoaderTestController { @RequestMapping(params = "method=uploadPic") public String uploadPic(HttpServletRequest request){ return "uploaderDemo/uploaderTest"; } @RequestMapping(params="method=upload") @ResponseBody public String uploads(@RequestParam("file")MultipartFile sortPicImg,HttpServletRequest request,HttpServletResponse response) { String path = SysConstants.PIC_SERVER_FILE_ROOT_DIR +SysConstants.PIC_PTYPE_DIR ; String fileName = System.currentTimeMillis()+"_"+sortPicImg.getOriginalFilename(); File targetFile = new File(path, fileName); if (!targetFile.exists()) { targetFile.mkdirs(); } JSONObject json = new JSONObject(); //保存 try { sortPicImg.transferTo(targetFile); } catch (Exception e) { e.printStackTrace(); json.put("msg","error"); return json.toJSONString(); } json.put("msg","success"); //json.put("filePath",request.getContextPath() + "/upload/" + fileName); File retfile = new File(SysConstants.PIC_SERVER_DNS +SysConstants.PIC_PTYPE_DIR, fileName); json.put("filePath",retfile.getPath()); System.out.println("json="+json.toJSONString()); return json.toJSONString(); } }
前台传到后台的图片是一张一张传的,每传一张图片调用一次该server方法,直到传完为止。
将图片文件上传到图片服务器后,再将该图片地址存储在数据库中。