zoukankan      html  css  js  c++  java
  • asp.net大文件(视频)分块上传

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。

    第一步:

    前端修改

    由于项目使用的是BJUI前端框架,并没有使用框架本身的文件上传控件,而使用的基于jQuery的Uploadify文件上传组件,在项目使用的jslib项目中找到了BJUI框架集成jQuery Uploadify的部分,这部分代码封装在bjui-all.js文件中,

    在bjui-all.js文件中的全局变量定义中有以下部分代码,这就是定义的有关于上传的Uploadify控件的重要变量:

    //文件上传对象

    function FileUploader(fileLoc, mgr)

    {

        var _this = this;

        this.id = fileLoc.id;

        this.ui = { msg: null, process: null, percent: null, btn: { del: null, cancel: null,post:null,stop:null }, div: null};

        this.isFolder = false; //不是文件夹

        this.app = mgr.app;

        this.Manager = mgr; //上传管理器指针

        this.event = mgr.event;

        this.Config = mgr.Config;

        this.fields = jQuery.extend({}, mgr.Config.Fields, fileLoc.fields);//每一个对象自带一个fields幅本

        this.State = this.Config.state.None;

        this.uid = this.fields.uid;

        this.fileSvr = {

              pid: ""

            , id: ""

            , pidRoot: ""

            , f_fdTask: false

            , f_fdChild: false

            , uid: 0

            , nameLoc: ""

            , nameSvr: ""

            , pathLoc: ""

            , pathSvr: ""

            , pathRel: ""

            , md5: ""

            , lenLoc: "0"

            , sizeLoc: ""

            , FilePos: "0"

            , lenSvr: "0"

            , perSvr: "0%"

            , complete: false

            , deleted: false

        };//json obj,服务器文件信息

        this.fileSvr = jQuery.extend(this.fileSvr, fileLoc);

        //准备

        this.Ready = function ()

        {

            this.ui.msg.text("正在上传队列中等待...");

            this.State = this.Config.state.Ready;

            this.ui.btn.post.click(function () {

                _this.ui.btn.post.hide();

                _this.ui.btn.del.hide();

                _this.ui.btn.cancel.hide();

                _this.ui.btn.stop.show();

                if (!_this.Manager.IsPostQueueFull()) {

                    _this.post();

                }

                else {

                    _this.ui.msg.text("正在上传队列中等待...");

                    _this.State = _this.Config.state.Ready;

                    $.each(_this.ui.btn, function (i, n) { n.hide(); });

                    _this.ui.btn.del.show();

                    //添加到队列

                    _this.Manager.AppendQueue(_this.fileSvr.id);

                }

            });

            this.ui.btn.stop.click(function () {

                _this.stop();

            });

            this.ui.btn.del.click(function () {

                _this.stop();

                _this.remove();

            });

            this.ui.btn.cancel.click(function () {

                _this.stop();

                _this.remove();

                //_this.PostFirst();//

            });

        };

        this.svr_error = function ()

        {

            alert("服务器返回信息为空,请检查服务器配置");

            this.ui.msg.text("向服务器发送MD5信息错误");

            //this.ui.btn.cancel.text("续传");

            this.ui.btn.stop.hide();

            this.ui.btn.cancel.show();

        };

        this.svr_error_same_name = function () {       

            this.ui.msg.text("服务器存在同名文件");

            this.ui.btn.stop.hide();

            this.ui.btn.cancel.show();

        };

        this.svr_create = function (sv)

        {

            if (sv.value == null)

            {

                this.Manager.RemoveQueuePost(this.fileSvr.id);

                this.svr_error(); return;

            }

            if (!sv.ret) {

                this.Manager.RemoveQueuePost(this.fileSvr.id);

                this.svr_error_same_name(); return;

            }

            var str = decodeURIComponent(sv.value);//

            this.fileSvr = JSON.parse(str);//

            //服务器已存在相同文件,且已上传完成

            if (this.fileSvr.complete)

            {

                this.post_complete_quick();

            } //服务器文件没有上传完成

            else

            {

                this.ui.process.css("width", this.fileSvr.perSvr);

                this.ui.percent.text(this.fileSvr.perSvr);

                this.post_file();

            }

        };

        this.svr_update = function () {

            if (this.fileSvr.lenSvr == 0) return;

            var param = { uid: this.fields["uid"], offset: this.fileSvr.lenSvr, lenSvr: this.fileSvr.lenSvr, perSvr: this.fileSvr.perSvr, id: this.id, time: new Date().getTime() };

            $.ajax({

                type: "GET"

                , dataType: 'jsonp'

                , jsonp: "callback" //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名

                , url: this.Config["UrlProcess"]

                , data: param

                , success: function (msg) {}

                , error: function (req, txt, err) { alert("更新文件进度错误!" + req.responseText); }

                , complete: function (req, sta) { req = null; }

            });

        };

        this.svr_remove = function ()

        {

            var param = { uid: this.fields["uid"], id: this.fileSvr.id, time: new Date().getTime() };

            $.ajax({

                type: "GET"

                , dataType: 'jsonp'

                , jsonp: "callback" //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名

                , url: this.Config["UrlDel"]

                , data: param

                , success: function (msg) { }

                , error: function (req, txt, err) { alert("删除文件失败!" + req.responseText); }

                , complete: function (req, sta) { req = null; }

            });

        };

        this.post_process = function (json)

        {

            this.fileSvr.lenSvr = json.lenSvr;//保存上传进度

            this.fileSvr.perSvr = json.percent;

            this.ui.percent.text("("+json.percent+")");

            this.ui.process.css("width", json.percent);

            var str = json.lenPost + " " + json.speed + " " + json.time;

            this.ui.msg.text(str);

        };

        this.post_complete = function (json)

        {

            this.fileSvr.perSvr = "100%";

            this.fileSvr.complete = true;

            $.each(this.ui.btn, function (i, n)

            {

                n.hide();

            });

            this.ui.process.css("width", "100%");

            this.ui.percent.text("(100%)");

            this.ui.msg.text("上传完成");

            this.Manager.arrFilesComplete.push(this);

            this.State = this.Config.state.Complete;

            //从上传列表中删除

            this.Manager.RemoveQueuePost(this.fileSvr.id);

            //从未上传列表中删除

            this.Manager.RemoveQueueWait(this.fileSvr.id);

            var param = { md5: this.fileSvr.md5, uid: this.uid, id: this.fileSvr.id, time: new Date().getTime() };

            $.ajax({

                type: "GET"

                  , dataType: 'jsonp'

                  , jsonp: "callback" //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名

                  , url: _this.Config["UrlComplete"]

                  , data: param

                  , success: function (msg)

                  {

                      _this.event.fileComplete(_this);//触发事件

                      _this.post_next();

                  }

                  , error: function (req, txt, err) { alert("文件-向服务器发送Complete信息错误!" + req.responseText); }

                  , complete: function (req, sta) { req = null; }

            });

        };

        this.post_complete_quick = function ()

        {

            this.fileSvr.perSvr = "100%";

            this.fileSvr.complete = true;

            this.ui.btn.stop.hide();

            this.ui.process.css("width", "100%");

            this.ui.percent.text("(100%)");

            this.ui.msg.text("服务器存在相同文件,快速上传成功。");

            this.Manager.arrFilesComplete.push(this);

            this.State = this.Config.state.Complete;

            //从上传列表中删除

            this.Manager.RemoveQueuePost(this.fileSvr.id);

            //从未上传列表中删除

            this.Manager.RemoveQueueWait(this.fileSvr.id);

            //添加到文件列表

            this.post_next();

            this.event.fileComplete(this);//触发事件

        };

        this.post_stoped = function (json)

        {

            this.ui.btn.post.show();

            this.ui.btn.del.show();

            this.ui.btn.cancel.hide();

            this.ui.btn.stop.hide();

            this.ui.msg.text("传输已停止....");

            if (this.Config.state.Ready == this.State)

            {

                this.Manager.RemoveQueue(this.fileSvr.id);

                this.post_next();

                return;

            }

            this.State = this.Config.state.Stop;

            //从上传列表中删除

            this.Manager.RemoveQueuePost(this.fileSvr.id);

            this.Manager.AppendQueueWait(this.fileSvr.id);//添加到未上传列表

            //传输下一个

            this.post_next();

        };

        this.post_error = function (json)

        {

            this.svr_update();

            this.ui.msg.text(this.Config.errCode[json.value]);

            this.ui.btn.stop.hide();

            this.ui.btn.post.show();

            this.ui.btn.del.show();

            this.State = this.Config.state.Error;

            //从上传列表中删除

            this.Manager.RemoveQueuePost(this.fileSvr.id);

            //添加到未上传列表

            this.Manager.AppendQueueWait(this.fileSvr.id);

            this.post_next();

        };

        this.md5_process = function (json)

        {

            var msg = "正在扫描本地文件,已完成:" + json.percent;

            this.ui.msg.text(msg);

        };

        this.md5_complete = function (json)

        {

            this.fileSvr.md5 = json.md5;

            this.ui.msg.text("MD5计算完毕,开始连接服务器...");

            this.event.md5Complete(this, json.md5);//biz event

            var loc_path = encodeURIComponent(this.fileSvr.pathLoc);

            var loc_len = this.fileSvr.lenLoc;

            var loc_size = this.fileSvr.sizeLoc;

            var param = jQuery.extend({}, this.fields, this.Config.bizData, { md5: json.md5, id: this.fileSvr.id, lenLoc: loc_len, sizeLoc: loc_size, pathLoc: loc_path, time: new Date().getTime() });

            $.ajax({

                type: "GET"

                , dataType: 'jsonp'

                , jsonp: "callback" //自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名

                , url: this.Config["UrlCreate"]

                , data: param

                , success: function (sv)

                {

                    _this.svr_create(sv);

                }

                , error: function (req, txt, err)

                {

                    _this.Manager.RemoveQueuePost(_this.fileSvr.id);

                    alert("向服务器发送MD5信息错误!" + req.responseText);

                    _this.ui.msg.text("向服务器发送MD5信息错误");

                    _this.ui.btn.cancel.show();

                    _this.ui.btn.stop.hide();

                }

                , complete: function (req, sta) { req = null; }

            });

        };

        this.md5_error = function (json)

        {

            this.ui.msg.text(this.Config.errCode[json.value]);

            //文件大小超过限制,文件大小为0

            if ("4" == json.value

                  || "5" == json.value)

            {

            this.ui.btn.stop.hide();

            this.ui.btn.cancel.show();

            }

            else

            {           

                this.ui.btn.post.show();

                this.ui.btn.stop.hide();

            }

            this.State = this.Config.state.Error;

            //从上传列表中删除

            this.Manager.RemoveQueuePost(this.fileSvr.id);

            //添加到未上传列表

            this.Manager.AppendQueueWait(this.fileSvr.id);

            this.post_next();

        };

        this.post_next = function ()

        {

            var obj = this;

            setTimeout(function () { obj.Manager.PostNext(); }, 300);

        };

        this.post = function ()

        {

            this.Manager.AppendQueuePost(this.fileSvr.id);

            this.Manager.RemoveQueueWait(this.fileSvr.id);

            if (this.fileSvr.md5.length > 0 || this.fileSvr.lenSvr > 0)

            {

                this.post_file();

            }

            else

            {

                this.check_file();

            }

        };

        this.post_file = function ()

        {

            $.each(this.ui.btn, function (i, n) { n.hide();});

            this.ui.btn.stop.show();

            this.State = this.Config.state.Posting;//

            this.app.postFile({ id: this.fileSvr.id, pathLoc: this.fileSvr.pathLoc, pathSvr:this.fileSvr.pathSvr,lenSvr: this.fileSvr.lenSvr, fields: this.fields });

        };

        this.check_file = function ()

        {

            //this.ui.btn.cancel.text("停止").show();

            this.ui.btn.stop.show();

            this.ui.btn.cancel.hide();

            this.State = this.Config.state.MD5Working;

            this.app.checkFile({ id: this.fileSvr.id, pathLoc: this.fileSvr.pathLoc });

        };

        this.stop = function ()

        {

            $.each(this.ui.btn, function (i, n) { n.hide();});

            this.svr_update();

            this.app.stopFile({ id: this.fileSvr.id });       

        };

        //手动停止,一般在StopAll中调用

        this.stop_manual = function ()

        {

            if (this.Config.state.Posting == this.State)

            {

                this.svr_update();

            this.ui.btn.post.show();

            this.ui.btn.stop.hide();

            this.ui.btn.cancel.hide();

                this.ui.msg.text("传输已停止....");

                this.app.stopFile({ id: this.fileSvr.id ,tip:false});

                this.State = this.Config.state.Stop;

            }

        };

        //删除,一般在用户点击"删除"按钮时调用

        this.remove = function ()

        {

            this.Manager.del_file(this.fileSvr.id);

            this.app.delFile(this.fileSvr);

            this.ui.div.remove();

            if (this.State != this.Config.state.Complete) this.svr_remove();

        };

    }

    upload:{uploadLimit:5,fileSizeLimit:31744,removeTimeout:0.8}

    以上三个变量代表的含义是:

    uploadLimit:表示上传文件个数的限制,5表示文件上传个数限制是5个

    fileSizeLimit:表示上传文件大小的限制,31744单位是KB,也就是表示31M

    removeTimeout:表示移除文件的时间限制

    继续查找使用到这些变量的地方,看到了文件大小超出限制等

    了解了BJUI前端框架对于上传大文件的限制,可以这样使用,增大文件上传大小和数量,可以按照如下进行修改,我们在bjui-all.js文件看到uploadLimit属性和fileSizeLimit属性的限制,我们在jsp文件中可以这样进行替换,这里使用的是覆盖原则,重新定义uploadLimit属性和fileSizeLimit属性,覆盖bjui-all.js文件的默认值设置。

    bjui-all.js文件的uploadLimit属性和fileSizeLimit属性对应到jsp文件中的属性就应该这样写,data-upload-limit属性和data-file-size-limit属性,只需要在后面改写为data-upload-limit=“800”和data-file-size-limit=“5131264”即可,一定要注意这里的单位是KB,以上数字表示501M。

    关于Uploadify控件属性可以参考这篇文章也可以直接看官网文档:

    http://blog.ncmem.com/wordpress/2019/08/07/java超大文件上传与下载/

    属性名称

    默认值

    说明

    auto

    true

    设置为true当选择文件后就直接上传了,为false需要点击上传按钮才上传 。

    buttonClass

    按钮样式

    buttonCursor

    ‘hand’

    鼠标指针悬停在按钮上的样子

    buttonImage

    null

    浏览按钮的图片的路径 。

    buttonText

    ‘SELECT FILES’

    浏览按钮的文本。

    checkExisting

    false

    文件上传重复性检查程序,检查即将上传的文件在服务器端是否已存在,存在返回1,不存在返回0

    debug

    false

    如果设置为true则表示启用SWFUpload的调试模式

    fileObjName

    ‘Filedata’

    文件上传对象的名称,如果命名为’the_files’,PHP程序可以用$_FILES['the_files']来处理上传的文件对象。

    fileSizeLimit

    0

    上传文件的大小限制 ,如果为整数型则表示以KB为单位的大小,如果是字符串,则可以使用(B, KB, MB, or GB)为单位,比如’2MB’;

    如果设置为0则表示无限制

    fileTypeDesc

    ‘All Files’

    这个属性值必须设置fileTypeExts属性后才有效,用来设置选择文件对话框中的提示文本,如设置fileTypeDesc为“请选择rar doc pdf文件”

    fileTypeExts

    ‘*.*’

    设置可以选择的文件的类型,格式如:’*.doc;*.pdf;*.rar’   。

    formData

    JSON格式上传每个文件的同时提交到服务器的额外数据,可在’onUploadStart’事件中使用’settings’方法动态设置。

    height

    30

    设置浏览按钮的高度 ,默认值

    itemTemplate

    false

    用于设置上传队列的HTML模版,可以使用以下标签:
        instanceID –   Uploadify实例的ID
        fileID – 列队中此文件的ID,或者理解为此任务的ID
        fileName – 文件的名称
        fileSize – 当前上传文件的大小
        插入模版标签时使用格式如:${fileName}

    method

    Post

    提交方式Post或Get

    multi

    true

    设置为true时可以上传多个文件。

    overrideEvents

    设置哪些事件可以被重写,JSON格式,如:’overrideEvents’ : ['onUploadProgress']

    preventCaching

    true

    如果为true,则每次上传文件时自动加上一串随机字符串参数,防止URL缓存影响上传结果

    progressData

    ‘percentage’

    设置上传进度显示方式,percentage显示上传百分比,speed显示上传速度

    queueID

    false

    设置上传队列容器DOM元素的ID,如果为false则自动生成一个队列容器。

    queueSizeLimit

    999

    队列最多显示的任务数量,如果选择的文件数量超出此限制,将会出发onSelectError事件。
        注意此项并非最大文件上传数量,如果要限制最大上传文件数量,应设置uploadLimit。

    removeCompleted

    true

    是否自动将已完成任务从队列中删除,如果设置为false则会一直保留此任务显示。

    removeTimeout

    3

    如果设置了任务完成后自动从队列中移除,则可以规定从完成到被移除的时间间隔。

    requeueErrors

    false

    如果设置为true,则单个任务上传失败后将返回错误,并重新加入任务队列上传。

    successTimeout

    30

    文件上传成功后服务端应返回成功标志,此项设置返回结果的超时时间

    swf

    ‘uploadify.swf’

    uploadify.swf 文件的相对路径。

    uploader

    uploadify.php

    后台处理程序的相对路径。

    uploadLimit

    999

    最大上传文件数量,如果达到或超出此限制将会触发onUploadError事件。

    width

    120

    设置文件浏览按钮的宽度。

    第二步:

    后端修改

    由于项目后端使用的Spring Boot,本身也就是使用的Spring MVC文件上传部分,Spring MVC使用的是已经对Servlet文件上传封装了的MultipartResolver接口及其相关实现类和一些相关的类,具体的可以看Spring MVC文件上传源码部分,认为Spring源码还是需要读的,我们只要在Spring Boot启动类中注入这个Bean,或者自行写一个WebConfig配置类,注入一些Web相关的Bean即可,这样Spring Boot启动就会加载配置类,也需要自己写拦截器和全局AOP切面,去捕捉文件上传大小超过限制的异常处理等

    基于Spring MVC文件上传组件MultipartResolver接口(核心),使用其中的CommonsMultipartResolver(实现了MultipartResolver接口)这个实现类,CommonsMultipartResolver中的maxUploadSize属性是它继承的抽象父类CommonsFileUploadSupport,这个抽象类其中的一个属性是FileUpload类,而这个类又继承自FileUploadBase这个抽象类,其中它的private long sizeMax = -1;就是maxUploadSize属性的最终设置地方。-1表示文件上传大小没有限制,但是我们一般都会设置一个限制值,这里设置的是210763776,这个值的单位是字节,我们将它设置为525336576字节,也就是501M的大小限制。

    修改完以上前端和后端,提交修改的代码到git上即可。

    第三步:

    Nginx配置

    进入到项目部署发布所在的Linux下,进入nginx服务器所安装的目录,

    进入到nginx服务器所安装的目录

    进入到nginx服务器目录下的conf目录

    查看nginx.conf配置文件内容中的client_max_body_size配置的大小,这里设置的是300M。

    使用vi或者vim打开nginx.conf配置文件,修改client_max_body_size的大小为501M,保存即可

    进入到nginx服务器下的sbin目录下,我们使用./nginx -t查看配置文件是否成功使用,然后使用./nginx -s reload重启Nginx服务器即可。

    第四步:

    Tomcat配置

    由于项目使用的是Spring Cloud,自然使用Spring Boot,我们这个项目还是使用外置的Tomcat作为他的服务器,便于我们对Tomcat服务器进行优化和设置。

    进入到项目使用的Tomcat服务器的目录

    进入到指定项目使用的Tomcat服务器的目录

    进入到Tomcat服务器下的conf配置目录中

    看到server.xml配置文件后

    先行查看Tomcat服务器的配置,其中两个属性对于这次是比较重要的一个是connectionTimeout这个连接超时时间设置以及默认的maxPostSize属性的设置

    使用vi或者vim打开server.xml配置文件,修改connectionTimeout的大小为2000000,这个属性的单位是毫秒,换算之后大概是半个小时,我们配置缺省的maxPostSize属性的值,默认情况下它的值是2097152,它的单位是字节,也就是2M的大小,修改完保存即可

    修改完服务器之后,使用发布工具重新从git上拉取最新的代码和部署发布,重新启动脚本即可完成修改,再次尝试大文件上传,功能基本实现。

    以上需要注意的是maxPostSize属性在各个Tomcat版本中的不同,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/07/java超大文件上传与下载/

    欢迎入群一起讨论:374992201

  • 相关阅读:
    从Oracle提供两种cube产品说开
    Sql Server DWBI的几个学习资料
    Unload Oracle data into text file
    初学Java的几个tips
    我常用的Oracle知识点汇总
    benefits by using svn
    如何在windows上使用putty来显示远端linux的桌面
    building commercial website using Microsoft tech stack
    Understand Thread and Lock
    Update google calendar by sunbird
  • 原文地址:https://www.cnblogs.com/songsu/p/14376151.html
Copyright © 2011-2022 走看看