java webuploader+smartUpload 实现文件批量上传
弄了好久终于把 这两个组件给弄清楚了,webuploader 前端插件,smartUpload java上传文件组件。
前端代码:
<label class="form-label col-xs-4 col-sm-2">图片上传:</label> <input type="hidden" name="goodsUrl" id="imgUrl" value="${goods.goodsUrl}"/><!--隐藏域传递图片地址存入数据库--> <div class="formControls col-xs-8 col-sm-9"> <div class="uploader-list-container"> <div class="queueList"> <div id="dndArea" class="placeholder"> <div id="filePicker-2"></div> <p>或将照片拖到这里,单次最多可选300张</p> </div> </div> <div class="statusBar" style="display:none;"> <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>
js代码:
1 (function( $ ){ 2 // 当domReady的时候开始初始化 3 $(function() { 4 var $wrap = $('.uploader-list-container'), 5 6 // 图片容器 7 $queue = $( '<ul class="filelist"></ul>' ) 8 .appendTo( $wrap.find( '.queueList' ) ), 9 10 // 状态栏,包括进度和控制按钮 11 $statusBar = $wrap.find( '.statusBar' ), 12 13 // 文件总体选择信息。 14 $info = $statusBar.find( '.info' ), 15 16 // 上传按钮 17 $upload = $wrap.find( '.uploadBtn' ), 18 19 // 没选择文件之前的内容。 20 $placeHolder = $wrap.find( '.placeholder' ), 21 22 $progress = $statusBar.find( '.progress' ).hide(), 23 24 // 添加的文件数量 25 fileCount = 0, 26 27 // 添加的文件总大小 28 fileSize = 0, 29 30 // 优化retina, 在retina下这个值是2 31 ratio = window.devicePixelRatio || 1, 32 33 // 缩略图大小 34 thumbnailWidth = 110 * ratio, 35 thumbnailHeight = 110 * ratio, 36 37 // 可能有pedding, ready, uploading, confirm, done. 38 state = 'pedding', 39 40 // 所有文件的进度信息,key为file id 41 percentages = {}, 42 // 判断浏览器是否支持图片的base64 43 isSupportBase64 = ( function() { 44 var data = new Image(); 45 var support = true; 46 data.onload = data.onerror = function() { 47 if( this.width != 1 || this.height != 1 ) { 48 support = false; 49 } 50 } 51 data.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 52 return support; 53 } )(), 54 55 // 检测是否已经安装flash,检测flash的版本 56 flashVersion = ( function() { 57 var version; 58 59 try { 60 version = navigator.plugins[ 'Shockwave Flash' ]; 61 version = version.description; 62 } catch ( ex ) { 63 try { 64 version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash') 65 .GetVariable('$version'); 66 } catch ( ex2 ) { 67 version = '0.0'; 68 } 69 } 70 version = version.match( /\d+/g ); 71 return parseFloat( version[ 0 ] + '.' + version[ 1 ], 10 ); 72 } )(), 73 74 supportTransition = (function(){ 75 var s = document.createElement('p').style, 76 r = 'transition' in s || 77 'WebkitTransition' in s || 78 'MozTransition' in s || 79 'msTransition' in s || 80 'OTransition' in s; 81 s = null; 82 return r; 83 })(), 84 85 // WebUploader实例 86 uploader; 87 88 if ( !WebUploader.Uploader.support('flash') && WebUploader.browser.ie ) { 89 90 // flash 安装了但是版本过低。 91 if (flashVersion) { 92 (function(container) { 93 window['expressinstallcallback'] = function( state ) { 94 switch(state) { 95 case 'Download.Cancelled': 96 alert('您取消了更新!') 97 break; 98 99 case 'Download.Failed': 100 alert('安装失败') 101 break; 102 103 default: 104 alert('安装已成功,请刷新!'); 105 break; 106 } 107 delete window['expressinstallcallback']; 108 }; 109 110 var swf = 'expressInstall.swf'; 111 // insert flash object 112 var html = '<object type="application/' + 113 'x-shockwave-flash" data="' + swf + '" '; 114 115 if (WebUploader.browser.ie) { 116 html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '; 117 } 118 119 html += 'width="100%" height="100%" style="outline:0">' + 120 '<param name="movie" value="' + swf + '" />' + 121 '<param name="wmode" value="transparent" />' + 122 '<param name="allowscriptaccess" value="always" />' + 123 '</object>'; 124 125 container.html(html); 126 127 })($wrap); 128 129 // 压根就没有安转。 130 } else { 131 $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>'); 132 } 133 134 return; 135 } else if (!WebUploader.Uploader.support()) { 136 alert( 'Web Uploader 不支持您的浏览器!'); 137 return; 138 } 139 140 // 实例化 141 uploader = WebUploader.create({ 142 pick: { 143 id: '#filePicker-2', 144 label: '点击选择图片' 145 }, 146 formData: { 147 uid: 123 148 }, 149 dnd: '#dndArea', 150 paste: '#uploader', 151 swf: 'lib/webuploader/0.1.5/Uploader.swf', 152 chunked: false, 153 chunkSize: 512 * 1024, 154 server: '../FileUpload.do', 155 // runtimeOrder: 'flash', 156 157 // accept: { 158 // title: 'Images', 159 // extensions: 'gif,jpg,jpeg,bmp,png', 160 // mimeTypes: 'image/*' 161 // }, 162 163 // 禁掉全局的拖拽功能。这样不会出现图片拖进页面的时候,把图片打开。 164 disableGlobalDnd: true, 165 fileNumLimit: 300, 166 fileSizeLimit: 200 * 1024 * 1024, // 200 M 167 fileSingleSizeLimit: 50 * 1024 * 1024 // 50 M 168 }); 169 170 // 拖拽时不接受 js, txt 文件。 171 uploader.on( 'dndAccept', function( items ) { 172 var denied = false, 173 len = items.length, 174 i = 0, 175 // 修改js类型 176 unAllowed = 'text/plain;application/javascript '; 177 178 for ( ; i < len; i++ ) { 179 // 如果在列表里面 180 if ( ~unAllowed.indexOf( items[ i ].type ) ) { 181 denied = true; 182 break; 183 } 184 } 185 186 return !denied; 187 }); 188 189 uploader.on('dialogOpen', function() { 190 console.log('here'); 191 }); 192 193 // uploader.on('filesQueued', function() { 194 // uploader.sort(function( a, b ) { 195 // if ( a.name < b.name ) 196 // return -1; 197 // if ( a.name > b.name ) 198 // return 1; 199 // return 0; 200 // }); 201 // }); 202 203 // 添加“添加文件”的按钮, 204 uploader.addButton({ 205 id: '#filePicker2', 206 label: '继续添加' 207 }); 208 209 uploader.on('ready', function() { 210 window.uploader = uploader; 211 }); 212 213 // 当有文件添加进来时执行,负责view的创建 214 function addFile( file ) { 215 var $li = $( '<li id="' + file.id + '">' + 216 '<p class="title">' + file.name + '</p>' + 217 '<p class="imgWrap"></p>'+ 218 '<p class="progress"><span></span></p>' + 219 '</li>' ), 220 221 $btns = $('<div class="file-panel">' + 222 '<span class="cancel">删除</span>' + 223 '<span class="rotateRight">向右旋转</span>' + 224 '<span class="rotateLeft">向左旋转</span></div>').appendTo( $li ), 225 $prgress = $li.find('p.progress span'), 226 $wrap = $li.find( 'p.imgWrap' ), 227 $info = $('<p class="error"></p>'), 228 229 showError = function( code ) { 230 switch( code ) { 231 case 'exceed_size': 232 text = '文件大小超出'; 233 break; 234 235 case 'interrupt': 236 text = '上传暂停'; 237 break; 238 239 default: 240 text = '上传失败,请重试'; 241 break; 242 } 243 244 $info.text( text ).appendTo( $li ); 245 }; 246 247 if ( file.getStatus() === 'invalid' ) { 248 showError( file.statusText ); 249 } else { 250 // @todo lazyload 251 $wrap.text( '预览中' ); 252 uploader.makeThumb( file, function( error, src ) { 253 var img; 254 255 if ( error ) { 256 $wrap.text( '不能预览' ); 257 return; 258 } 259 260 if( isSupportBase64 ) { 261 img = $('<img src="'+src+'">'); 262 $wrap.empty().append( img ); 263 } else { 264 $.ajax('lib/webuploader/0.1.5/server/preview.php', { 265 method: 'POST', 266 data: src, 267 dataType:'json' 268 }).done(function( response ) { 269 if (response.result) { 270 img = $('<img src="'+response.result+'">'); 271 $wrap.empty().append( img ); 272 } else { 273 $wrap.text("预览出错"); 274 } 275 }); 276 } 277 }, thumbnailWidth, thumbnailHeight ); 278 279 percentages[ file.id ] = [ file.size, 0 ]; 280 file.rotation = 0; 281 } 282 283 file.on('statuschange', function( cur, prev ) { 284 if ( prev === 'progress' ) { 285 $prgress.hide().width(0); 286 } else if ( prev === 'queued' ) { 287 $li.off( 'mouseenter mouseleave' ); 288 $btns.remove(); 289 } 290 291 // 成功 292 if ( cur === 'error' || cur === 'invalid' ) { 293 console.log( file.statusText ); 294 showError( file.statusText ); 295 percentages[ file.id ][ 1 ] = 1; 296 } else if ( cur === 'interrupt' ) { 297 showError( 'interrupt' ); 298 } else if ( cur === 'queued' ) { 299 percentages[ file.id ][ 1 ] = 0; 300 } else if ( cur === 'progress' ) { 301 $info.remove(); 302 $prgress.css('display', 'block'); 303 } else if ( cur === 'complete' ) { 304 $li.append( '<span class="success"></span>' ); 305 } 306 307 $li.removeClass( 'state-' + prev ).addClass( 'state-' + cur ); 308 }); 309 310 $li.on( 'mouseenter', function() { 311 $btns.stop().animate({height: 30}); 312 }); 313 314 $li.on( 'mouseleave', function() { 315 $btns.stop().animate({height: 0}); 316 }); 317 318 $btns.on( 'click', 'span', function() { 319 var index = $(this).index(), 320 deg; 321 322 switch ( index ) { 323 case 0: 324 uploader.removeFile( file ); 325 return; 326 327 case 1: 328 file.rotation += 90; 329 break; 330 331 case 2: 332 file.rotation -= 90; 333 break; 334 } 335 336 if ( supportTransition ) { 337 deg = 'rotate(' + file.rotation + 'deg)'; 338 $wrap.css({ 339 '-webkit-transform': deg, 340 '-mos-transform': deg, 341 '-o-transform': deg, 342 'transform': deg 343 }); 344 } else { 345 $wrap.css( 'filter', 'progid:DXImageTransform.Microsoft.BasicImage(rotation='+ (~~((file.rotation/90)%4 + 4)%4) +')'); 346 // use jquery animate to rotation 347 // $({ 348 // rotation: rotation 349 // }).animate({ 350 // rotation: file.rotation 351 // }, { 352 // easing: 'linear', 353 // step: function( now ) { 354 // now = now * Math.PI / 180; 355 356 // var cos = Math.cos( now ), 357 // sin = Math.sin( now ); 358 359 // $wrap.css( 'filter', "progid:DXImageTransform.Microsoft.Matrix(M11=" + cos + ",M12=" + (-sin) + ",M21=" + sin + ",M22=" + cos + ",SizingMethod='auto expand')"); 360 // } 361 // }); 362 } 363 364 365 }); 366 367 $li.appendTo( $queue ); 368 } 369 370 // 负责view的销毁 371 function removeFile( file ) { 372 var $li = $('#'+file.id); 373 374 delete percentages[ file.id ]; 375 updateTotalProgress(); 376 $li.off().find('.file-panel').off().end().remove(); 377 } 378 379 function updateTotalProgress() { 380 var loaded = 0, 381 total = 0, 382 spans = $progress.children(), 383 percent; 384 385 $.each( percentages, function( k, v ) { 386 total += v[ 0 ]; 387 loaded += v[ 0 ] * v[ 1 ]; 388 } ); 389 390 percent = total ? loaded / total : 0; 391 392 393 spans.eq( 0 ).text( Math.round( percent * 100 ) + '%' ); 394 spans.eq( 1 ).css( 'width', Math.round( percent * 100 ) + '%' ); 395 updateStatus(); 396 } 397 398 function updateStatus() { 399 var text = '', stats; 400 401 if ( state === 'ready' ) { 402 text = '选中' + fileCount + '张图片,共' + 403 WebUploader.formatSize( fileSize ) + '。'; 404 } else if ( state === 'confirm' ) { 405 stats = uploader.getStats(); 406 if ( stats.uploadFailNum ) { 407 text = '已成功上传' + stats.successNum+ '张照片至XX相册,'+ 408 stats.uploadFailNum + '张照片上传失败,<a class="retry" href="#">重新上传</a>失败图片或<a class="ignore" href="#">忽略</a>' 409 } 410 411 } else { 412 stats = uploader.getStats(); 413 text = '共' + fileCount + '张(' + 414 WebUploader.formatSize( fileSize ) + 415 '),已上传' + stats.successNum + '张'; 416 417 if ( stats.uploadFailNum ) { 418 text += ',失败' + stats.uploadFailNum + '张'; 419 } 420 } 421 422 $info.html( text ); 423 } 424 425 function setState( val ) { 426 var file, stats; 427 428 if ( val === state ) { 429 return; 430 } 431 432 $upload.removeClass( 'state-' + state ); 433 $upload.addClass( 'state-' + val ); 434 state = val; 435 436 switch ( state ) { 437 case 'pedding': 438 $placeHolder.removeClass( 'element-invisible' ); 439 $queue.hide(); 440 $statusBar.addClass( 'element-invisible' ); 441 uploader.refresh(); 442 break; 443 444 case 'ready': 445 $placeHolder.addClass( 'element-invisible' ); 446 $( '#filePicker2' ).removeClass( 'element-invisible'); 447 $queue.show(); 448 $statusBar.removeClass('element-invisible'); 449 uploader.refresh(); 450 break; 451 452 case 'uploading': 453 $( '#filePicker2' ).addClass( 'element-invisible' ); 454 $progress.show(); 455 $upload.text( '暂停上传' ); 456 break; 457 458 case 'paused': 459 $progress.show(); 460 $upload.text( '继续上传' ); 461 break; 462 463 case 'confirm': 464 $progress.hide(); 465 $( '#filePicker2' ).removeClass( 'element-invisible' ); 466 $upload.text( '开始上传' ); 467 468 stats = uploader.getStats(); 469 if ( stats.successNum && !stats.uploadFailNum ) { 470 setState( 'finish' ); 471 return; 472 } 473 break; 474 case 'finish': 475 stats = uploader.getStats(); 476 if ( stats.successNum ) { 477 alert( '上传成功' ); 478 } else { 479 // 没有成功的图片,重设 480 state = 'done'; 481 location.reload(); 482 } 483 break; 484 } 485 486 updateStatus(); 487 } 488 489 uploader.onUploadProgress = function( file, percentage ) { 490 var $li = $('#'+file.id), 491 $percent = $li.find('.progress span'); 492 493 $percent.css( 'width', percentage * 100 + '%' ); 494 percentages[ file.id ][ 1 ] = percentage; 495 updateTotalProgress(); 496 }; 497 498 uploader.onFileQueued = function( file ) { 499 fileCount++; 500 fileSize += file.size; 501 502 if ( fileCount === 1 ) { 503 $placeHolder.addClass( 'element-invisible' ); 504 $statusBar.show(); 505 } 506 507 addFile( file ); 508 setState( 'ready' ); 509 updateTotalProgress(); 510 }; 511 512 uploader.onFileDequeued = function( file ) { 513 fileCount--; 514 fileSize -= file.size; 515 516 if ( !fileCount ) { 517 setState( 'pedding' ); 518 } 519 520 removeFile( file ); 521 updateTotalProgress(); 522 523 }; 524 525 //在上传完成之前客户端询问服务器上传是否成功 526 uploader.on( 'uploadAccept', function( file, response) { 527 var obj = eval(response); 528 //alert(obj.state+"--"+obj.filePath); 529 if(obj.state=="NO"){ 530 return false; 531 } 532 $("#imgUrl").val(obj.filePath); 533 //alert($("#imgUrl").val()); 534 }); 535 uploader.on( 'all', function( type ) { 536 var stats; 537 switch( type ) { 538 case 'uploadFinished': 539 setState( 'confirm' ); 540 break; 541 542 case 'startUpload': 543 setState( 'uploading' ); 544 break; 545 546 case 'stopUpload': 547 setState( 'paused' ); 548 break; 549 550 } 551 }); 552 553 uploader.onError = function( code ) { 554 alert( 'Eroor: ' + code ); 555 }; 556 557 $upload.on('click', function() { 558 if ( $(this).hasClass( 'disabled' ) ) { 559 return false; 560 } 561 562 if ( state === 'ready' ) { 563 uploader.upload(); 564 } else if ( state === 'paused' ) { 565 uploader.upload(); 566 } else if ( state === 'uploading' ) { 567 uploader.stop(); 568 } 569 }); 570 571 $info.on( 'click', '.retry', function() { 572 uploader.retry(); 573 } ); 574 575 $info.on( 'click', '.ignore', function() { 576 alert( 'todo' ); 577 } ); 578 579 $upload.addClass( 'state-' + state ); 580 updateTotalProgress(); 581 }); 582 583 })( jQuery );
后台实现:
1 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 2 System.out.println("开始上传"); 3 resp.setCharacterEncoding("utf-8"); 4 //设置上传文件保存的路径 5 String filePath = req.getSession().getServletContext().getRealPath("/")+"images"; 6 //System.out.println(filePath); 7 File file = new File(filePath); 8 if(!file.exists()){ 9 file.mkdirs(); 10 } 11 12 SmartUpload su = new SmartUpload(); 13 //初始化smartupload 14 su.initialize(getServletConfig(), req, resp); 15 //设置文件的大小 16 su.setMaxFileSize(1024*1024*10); 17 //设置所有文件的大小 18 su.setTotalMaxFileSize(1024*1024*100); 19 //设置允许上传的文件类型 20 su.setAllowedFilesList("jpg,png,gif"); 21 //设置禁止上传的文件类型 22 JSONObject json = new JSONObject(); 23 try { 24 su.setDeniedFilesList("rar,zip,jsp,js"); 25 su.upload(); 26 int count = su.save(filePath); 27 String filepath = "../images/"+ su.getFiles().getFile(0).getFileName(); 28 if(count>0){ 29 json.put("state", "OK"); 30 json.put("filePath", filepath); 31 } 32 else{ 33 json.put("state", "NO"); 34 } 35 //System.out.println(json.toString()); 36 resp.getWriter().write(json.toString()); 37 //System.out.println("上传成功"+count+"个文件!"); 38 } catch (Exception e) { 39 e.printStackTrace(); 40 } 41 } 42 }
至此上传文件到服务器指定目录并返回文件地址赋给隐藏input 的value,最后提交表单存入数据库。功能已基本实现,后续扩展自己研究。
文章未经版主同意不可任意转载,如有需要请标明文章出处。