溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

WebUploader+SpringMVC實現(xiàn)文件上傳功能

發(fā)布時間:2020-08-19 17:11:03 來源:腳本之家 閱讀:136 作者:layman1024 欄目:編程語言

WebUploader是由Baidu團隊開發(fā)的一個簡單的以HTML5為主,F(xiàn)LASH為輔的現(xiàn)代文件上傳組件。在現(xiàn)代的瀏覽器里面能充分發(fā)揮html5的優(yōu)勢,同時又不摒棄主流IE瀏覽器,沿用原來的FLASH運行時,兼容IE6+,iOS 6+, Android 4+。兩套運行時,同樣的調(diào)用方式,可供用戶任意選用。 采用大文件分片并發(fā)上傳,極大的提高了文件上傳效率。

官方文檔及更多示例請參考: http://fex.baidu.com/webuploader/

不扯廢話了,由于我需要的只是上傳圖片功能,官網(wǎng)上邊還說“WebUploader只包含文件上傳的底層實現(xiàn),不包括UI部分,所以交互方面可以自由發(fā)揮?!钡俏矣挚吹焦倬W(wǎng)的例子不錯,就把demo的js和css扒了下來.

WebUploader+SpringMVC實現(xiàn)文件上傳功能

WebUploader+SpringMVC實現(xiàn)文件上傳功能

前臺相關(guān)代碼:

jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
 pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--引入CSS-->
<link rel="stylesheet" type="text/css" href="${basePath}/js/plugins/webuploader/webuploader.css" rel="external nofollow" >
<link rel="stylesheet" type="text/css" href="${basePath}/views/uploaderDemo/uploader_demo.css" rel="external nofollow" >
<!--引入JS-->
<script src="${basePath}/js/jquery.min.js"></script>
<script src="${basePath}/js/plugins/webuploader/webuploader.js"></script>
<script src="${basePath}/js/bootstrap.min.js"></script>
<script src="${basePath}/views/uploaderDemo/uploader_demo.js"></script>
<title>uploadTest</title>
</head>
<body>
 <div id="post-container" class="container">
  <div class="page-container">
   <h2 id="demo">Demo</h2>
   <p>您可以嘗試文件拖拽,使用QQ截屏工具,然后激活窗口后粘貼,或者點擊添加圖片按鈕,來體驗此demo.</p>
   <div id="uploader" class="wu-example">
    <div class="queueList">
     <div id="dndArea" class="placeholder">
      <div id="filePicker"></div>
      <p>或?qū)⒄掌系竭@里,單次最多可選300張</p>
     </div>
    </div>
    <div class="statusBar" >
     <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>
</body>
</html>

uploader_demo.js

jQuery(function() {
 var $ = jQuery, // just in case. Make sure it's not an other libaray.
  $wrap = $('#uploader'),  // 圖片容器
  $queue = $('<ul class="filelist"></ul>')
   .appendTo( $wrap.find('.queueList') ),  // 狀態(tài)欄,包括進度和控制按鈕
  $statusBa $wrap.find('.statusBar'),
  // 文件總體選擇信息。
  $info = $statusBar.find('.info'),
  // 上傳按鈕
  $upload = $wrap.find('.uploadBtn'),
  // 沒選擇文件之前的內(nèi)容。
  $placeHolder = $wrap.find('.placeholder'),
  // 總體進度條
  $progress = $statusBar.find('.progress').hide(),
  // 添加的文件數(shù)量
  fileCount = 0,
  // 添加的文件總大小
  fileSize = 0,
  // 優(yōu)化retina, 在retina下這個值是2
  ratio = window.devicePixelRatio || 1,
  // 縮略圖大小
  thumbnailWidth = 110 * ratio,
  thumbnailHeight = 110 * ratio,
  // 可能有pedding, ready, uploading, confirm, done.
  state = 'pedding',
  // 所有文件的進度信息,key為file id
  percentages = {},
  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;
  })(),
  // WebUploader實例
  uploader;
 if ( !WebUploader.Uploader.support() ) {
  alert( 'Web Uploader 不支持您的瀏覽器!如果你使用的是IE瀏覽器,請嘗試升級 flash 播放器');
  throw new Error( 'WebUploader does not support the browser you are using.' );
 }
 // 實例化
 uploader = WebUploader.create({
  pick: {
   id: '#filePicker',
   label: '點擊選擇圖片'
  },
  dnd: '#uploader .queueList',
  paste: document.body,
  accept: {
   title: 'Images',
   extensions: 'gif,jpg,jpeg,bmp,png',
   mimeTypes: 'image/*'
  },
  // swf文件路徑,就是控件下的swf文件地址
  swf: 'js/plugins/webuploader/Uploader.swf',
  disableGlobalDnd: true,
  chunked: true,
  // 文件接收服務(wù)端,寫你要執(zhí)行的方法就行
  **server: 'http://localhost:8080/test/upload.do?method=upload'**,
  fileNumLimit: 300,
  fileSizeLimit: 5 * 1024 * 1024, // 200 M
  fileSingleSizeLimit: 1 * 1024 * 1024 // 50 M
 });
 // 添加“添加文件”的按鈕,
 uploader.addButton({
  id: '#filePicker2',
  label: '繼續(xù)添加'
 });
 // 當有文件添加進來時執(zhí)行,負責(zé)view的創(chuàng)建
 function addFile( 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">向右旋轉(zhuǎn)</span>' +
    '<span class="rotateLeft">向左旋轉(zhuǎn)</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 {
   // @todo lazyload
   $wrap.text( '預(yù)覽中' );
   uploader.makeThumb( file, function( error, src ) {
    if ( error ) {
     $wrap.text( '不能預(yù)覽' );
     return;
    }
    var img = $('<img src="'+src+'">');
    $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( '<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(),
    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 );
 }
 // 負責(zé)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 + '張照片上傳失敗,<a class="retry" href="#" rel="external nofollow" rel="external nofollow" >重新上傳</a>失敗圖片或<a class="ignore" href="#" rel="external nofollow" rel="external nofollow" >忽略</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.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( '繼續(xù)上傳' );
    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 {
     // 沒有成功的圖片,重設(shè)
     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();
 }
 }

前臺傳到后臺的圖片是一張一張傳的,每傳一張圖片調(diào)用一次該server方法,直到傳完為止。

將圖片文件上傳到圖片服務(wù)器后,再將該圖片地址存儲在數(shù)據(jù)庫中。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI