• 文件上传


    一、上传到自己的服务器:

    使用 AdminLTE 2 网站中的 form 表单的代码:https://adminlte.io/themes/AdminLTE/pages/forms/general.html (使用其原先css样式及HTML代码,代码内容经过精简)

    前端代码:

    首先:一个带有输入框跟上传按钮的HTML文件(样式图如下:)

    1 <div class="form-group">
    2     <label for="thumbnail-form">缩略图</label>
    3     <div class="input-group">
    4         <input type="text" class="form-control" id="thumbnail-form" name="thumbnail">
    5         <span class="input-group-btn">
    6             <input type="file" class="btn btn-default" id="thumbnail-btn" value="上传文件">
    7         </span>
    8     </div>
    9 </div>
    View Code

    使用 input标签 , type=file 时显示的样式;

    将上图修改为下图的样式,使其更美观;

     1 <div class="form-group">
     2     <label for="thumbnail-form">缩略图</label>
     3     <div class="input-group">
     4         <input type="text" class="form-control" id="thumbnail-form" name="thumbnail">
     5         <span class="input-group-btn">
     6             <label class="btn btn-default btn-file">
     7                 上传图片<input  hidden type="file" class="btn btn-default" id="thumbnail-btn">
     8             </label>
     9         </span>
    10     </div>
    11 </div>
    View Code

    id = "thumbnail-form":输入框的ID;

    id = "thumbnail-btn":作为隐藏起来的 file标签 文件的一个按钮ID;

    使用 label标签,其中 for 中的值等于 input 的ID相当于点击“缩略图”时会默认点击下方输入框;点击“上传图片”会默认点击“type=file”的标签;二者之间存在关联;

    使用 hidden 将 file标签 隐藏起来,使“上传图片”的字体将其覆盖;

    使用js文件监听其上传时的点击事件;

     1 function News() {
     2 
     3 }
     4 
     5 News.prototype.run = function () {
     6     var self = this;
     7     self.ListenUploadFileEvent();
     8 };
     9 
    10 // 监听文件上传的事件;
    11 News.prototype.ListenUploadFileEvent = function () {
    12     var uploadBtn = $('#thumbnail-btn');
    13     uploadBtn.change(function () {
    14         var file = uploadBtn[0].files[0];
    15         var formData = new FormData();
    16         formData.append('file', file);
    17         xfzajax.post({
    18             'url': '/cms/upload_file/',
    19             'data': formData,
    20             'processData': false,
    21             'contentType': false,
    22             'success': function (result) {
    23                 if (result['code'] === 200){
    24                     var url = result['data']['url'];
    25                     var thumbnailInput = $('#thumbnail-form');
    26                     thumbnailInput.val(url);
    27                 }
    28             }
    29         })
    30     });
    31 };
    32 
    33 $(function () {
    34     var news = new News();
    35     news.run();
    36 });
    View Code

    change:用来监听进入上传文件选定文件后点击打开按钮的事件,此处不能使用 click 点击事件;

    因为 uploadBtn 得到的是一个集合,不是一个单一的对象。所以 var file = uploadBtn[0].files[0]; 中的 uploadBtn[0] 用来获取其中的唯一一个按钮,与其存储的所有文件中的第一个文件。

    formData:用来存储文件;

     formData.append('file', file); :引号中的字段名需与后台通过 ‘get’ 获取文件填写的字段名保持一致;

    然后通过ajax请求发送给后端服务器,跳转的 url 及其数据 formData,后两个 false  为告知上层 jquery-3.3.1.min.js 文件不对该文件的数据再次进行处理或添加其它内容,以及成功或者失败的返回内容(失败内容定义在ajax文件中);

    在后端中得到的url完整路径,调用 ‘restful’ 中的 ‘result’ 函数,再将获取的 ‘url’ 的值给到前端输入框中显示。

    ajax代码

     1 //static:xfzajax.js
     2 function getCookie(name) {
     3     var cookieValue = null;
     4     if (document.cookie && document.cookie !== '') {
     5         var cookies = document.cookie.split(';');
     6         for (var i = 0; i < cookies.length; i++) {
     7             var cookie = jQuery.trim(cookies[i]);
     8             // Does this cookie string begin with the name we want?
     9             if (cookie.substring(0, name.length + 1) === (name + '=')) {
    10                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
    11                 break;
    12             }
    13         }
    14     }
    15     return cookieValue;
    16 }
    17 
    18 var xfzajax = {
    19     'get': function (args) {
    20         args['method'] = 'get';
    21         this.ajax(args);
    22     },
    23     'post': function (args) {
    24         args['method'] = 'post';
    25         this._ajaxSetup();
    26         this.ajax(args);
    27     },
    28     'ajax': function (args) {
    29         var success = args['success'];
    30         args['success'] = function (result) {
    31             if (result['code'] === 200) {
    32                 if (success) {
    33                     success(result)
    34                 }
    35             } else {
    36                 var messageObject = result['message'];
    37                 if (typeof messageObject == 'string' || messageObject.constructor === String) {
    38                     window.messageBox.showError(messageObject);
    39                 } else {
    40                     // {"password":['密码最大长度不能超过20为!','xxx'],"telephone":['xx','x']}
    41                     for (var key in messageObject) {
    42                         var messages = messageObject[key];
    43                         var message = messages[0];
    44                         window.messageBox.showError(message);
    45                     }
    46                 }
    47                 if(success){
    48                     success(result)
    49                 }
    50             }
    51         };
    52         args['fail'] = function (error) {
    53             console.log(error);
    54             window.showError('服务器内部错误!')
    55         };
    56         $.ajax(args);
    57     },
    58     '_ajaxSetup': function () {
    59         $.ajaxSetup({
    60             beforeSend: function (xhr, settings) {
    61                 if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type) && !this.crossDomain) {
    62                     xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
    63                 }
    64             }
    65         });
    66     }
    67 };
    View Code

    后端代码:

    settings.py文件的设置:

    1 # 在末尾添加内容;
    2 
    3 STATIC_URL = '/static/'
    4 STATICFILES_DIRS = [
    5     os.path.join(BASE_DIR,'front','dist'),
    6 ]
    7 
    8 MEDIA_URL = '/media/'
    9 MEDIA_ROOT = os.path.join(BASE_DIR,'media')
    View Code

    使用MEDIA_ROOTMEDIA_URL,用来指定文件上传后存储的位置,在主目录中新建‘media’文件用来存储内容;

    文件的映射路径,与前端 ajax 内容中跳转的 url 一致。

     1 # 总的url链接;
     2 
     3 from django.urls import path,include
     4 from django.conf.urls.static import static
     5 from django.conf import settings
     6 
     7 urlpatterns = [
     8     path('cms/',include('apps.cms.urls')),
     9 ] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
    10 
    11 
    12 # cms的url:
    13 
    14 from django.urls import path
    15 from . import views
    16 
    17 app_name = 'cms'
    18 
    19 urlpatterns = [
    20     path('upload_file/',views.upload_file,name='upload_file'),
    21 ]
    View Code

    视图函数

     1 from django.views.decorators.http import require_POST, 
     2 from utils import restful
     3 from django.conf import settings
     4 import os
     5 
     6 
     7 # 文件上传;
     8 @require_POST
     9 def upload_file(request):
    10     file = request.FILES.get('file')
    11     name = file.name
    12     with open(os.path.join(settings.MEDIA_ROOT,name),'wb') as fp:
    13         for chunk in file.chunks():
    14             fp.write(chunk)
    15     url = request.build_absolute_uri(settings.MEDIA_URL + name)
    16     return restful.result(data={'url':url})
    View Code

    使用 “get” 获取的 “file” 与前端提到 “file” 一致;

    使用 build_absolute_uri 可以获取完整的url地址;

    restful.py文件(简化每个文件代码运行结果的代码量)

     1 from django.http import JsonResponse
     2 
     3 class HttpCode(object):
     4     ok = 200            # 正常运行;
     5     paramserror = 400   # 参数错误;
     6     unauth = 401        # 没授权;
     7     methoderror = 405   # 请求方法错误;
     8     servererror = 500   # 服务器内部错误;
     9 
    10 def result(code=HttpCode.ok,message='',data=None,kwargs=None):
    11     json_dict = {'code':code,'message':message,'data':data}
    12     if kwargs and isinstance(kwargs,dict) and kwargs.keys():
    13         json_dict.update(kwargs)
    14     return JsonResponse(json_dict)
    15 
    16 def ok():
    17     return result()
    18 
    19 def params_error(message='',data=None):
    20     return result(code=HttpCode.paramserror,message=message,data=data)
    21 
    22 def unauth(message='',data=None):
    23     return result(code=HttpCode.unauth,message=message,data=data)
    24 
    25 def method_error(message='',data=None):
    26     return result(code=HttpCode.methoderror,message=message,data=data)
    27 
    28 def server_error(message='',data=''):
    29     return result(code=HttpCode.servererror,message=message,data=data)
    View Code

    二、上传到七牛云

    1、登录注册七牛云:https://www.qiniu.com//

    2、登录后进入右上方管理控制台后,再点击右上角的个人图标进入密钥管理,记住 AK 与 SK ,后续用到;

    3、点击左侧 对象存储,新建存储空间 bucket 

    后端:

    1、下载 python SDKpip install qiniu

    2、创建一个获取 tokenurl

     1 # 上传七牛云;
     2 @require_GET
     3 def qntokon(request):
     4     access_key = 'GjdN0XJxtrLbINSxx4ZjXXitk7Aux5h046x9viB8'
     5     secret_key = '8ULlOQezsKZIRFl_Bie09GZIJyonH50aJH6RONhu'
     6     bucket = 'qmspace'
     7     # 创建授权信息q;
     8     q = qiniu.Auth(access_key,secret_key)
     9     # 生成上传凭证,传给前端;
    10     tokon = q.upload_token(bucket)
    11     return restful.result(data={'tokon':tokon})
    View Code

    前端:

    基于七牛 API 开发的前端 JavaScript SDK:https://github.com/qiniu/js-sdk(详细的官方文档讲解)

    在HTML代码的缩略图代码下添加进度条代码,默认隐藏;

     1 <!--html代码-->
     2 <script src="https://unpkg.com/qiniu-js@2.4.0/dist/qiniu.min.js
     3 "></script>
     4 --snip--
     5 <div class="form-group">
     6     <label for="thumbnail-form">缩略图</label>
     7     --snip--
     8     </div>
     9 </div>
    10 <!--上传进度条-->
    11 <div class="form-group" id="progress-group" style="display: none;">
    12     <div class="progress">
    13       <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20"
    14            aria-valuemin="0" aria-valuemax="100" style=" 0">
    15           0%
    16       </div>
    17     </div>
    18 </div>
    View Code

    通过 js 代码实现与七牛云的对接及文件的上传,以及进度条的显示情况;

     1 // 上传到七牛云;
     2 News.prototype.ListenQiniuuploadFileEvent = function(){
     3     var self = this;
     4     var uploadBtn = $('#thumbnail-btn');
     5     uploadBtn.change(function () {
     6         var file = this.files[0];
     7         xfzajax.get({
     8             'url': '/cms/qntokon/',
     9             'success': function (result) {
    10                 if (result['code'] ===200 ){
    11                     
    12                     // token: 上传验证信息,前端通过接口请求后端获得;
    13                     var tokon = result['data']['tokon'];
    14                     
    15                     // key: 文件资源名(当前时间+文件格式);
    16                     var key = (new Date()).getTime() + '.' + file.name.split('.')[-1];
    17                     
    18                     var putExtra = {
    19                         fname: key,
    20                         params: {},
    21                         mimeType: ['image/png','image/jpeg','image/gif','video/x-ms-wmv','video/mp4','video/x-flv']
    22                     };
    23                     
    24                     var config = {
    25                         useCdnDomain: true,
    26                         retryCount: 6,
    27                         region: qiniu.region.z2
    28                     };
    29                     
    30                     // 文件上传;
    31                     var observable = qiniu.upload(file,key,tokon,putExtra,config);
    32                     observable.subscribe({
    33                         'next': self.handFileUploadProcess,
    34                         'error': self.handFileUploadError,
    35                         'complete': self.handFileUploadComplete,
    36                     })
    37                 }
    38             }
    39         })
    40     })
    41 };
    42 
    43 News.prototype.handFileUploadProcess = function(response){
    44     var total = response.total;
    45     var percent = total.percent;
    46     var percentText = percent.toFixed() + '%';
    47     var progressGroup = News.progressGroup;
    48     progressGroup.show();
    49     var progressBar = $('.progress-bar');
    50     progressBar.css({"width":percentText});
    51     progressBar.text(percentText);
    52 };
    53 
    54 News.prototype.handFileUploadError = function(error){
    55     window.messageBox.showError(error.message);
    56     var progressGroup = News.progressGroup;
    57     progressGroup.hide();
    58     console.log(error.message);
    59 };
    60 
    61 News.prototype.handFileUploadComplete = function(response){
    62     console.log(response);
    63     var progressGroup = News.progressGroup;
    64     progressGroup.hide();
    65     var domain = 'http://ps96zui1h.bkt.clouddn.com/';
    66     var filename = response.key;
    67     var url = domain + filename;
    68     var thumbnailInput = $("input[name='thumbnail']");
    69     thumbnailInput.val(url)
    70 };
    71 
    72 $(function () {
    73     var news = new News();
    74     news.run();
    75     News.progressGroup = $('#progress-group');
    76 });
    View Code

    (官方文档很详细,不再做个人注解)

    上传成功:

  • 相关阅读:
    C# webservice服务跟踪调试方法(转)
    ServiceBase.OnStart 方法
    基本类型和引用类型
    js基本概念
    在HTML中使用JavaScript
    js中的this
    SQL 取两日期的记录
    常用数据结构[转]
    How to: Pass Values Between ASP.NET Web Pages
    example for store procedure with both transcration and error handling
  • 原文地址:https://www.cnblogs.com/liqiongming/p/10939252.html
Copyright © 2020-2023  润新知