精华内容
下载资源
问答
  • webuploader下载
    2020-05-21 16:41:07

    一、概述

     

    所谓断点续传,其实只是指下载,也就是要从文件已经下载的地方开始继续下载。在以前版本的HTTP协议是不支持断点的,HTTP/1.1开始就支持了。一般断点下载时才用到Range和Content-Range实体头。HTTP协议本身不支持断点上传,需要自己实现。

     

    二、Range 

     

    用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

     

        Range:用于客户端到服务端的请求,可以通过改字段指定下载文件的某一段大小及其单位,字节偏移从0开始。典型格式:

        Ranges:    (unit=first byte pos)-[last byte pos]

        Ranges:    bytes=4000- 下载从第4000字节开始到文件结束部分

        Ranges:    bytes=0~N 下载第0-N字节范围的内容

        Ranges:    bytes=M-N 下载第M-N字节范围的内容

        Ranges:    bytes=-N 下载最后N字节内容


     

     

    1.以下几点需要注意:

    (1)这个数据区间是个闭合区间,起始值是0,所以“Range: bytes=0-1”这样一个请求实际上是在请求开头的2个字节。

    (2)“Range: bytes=-200”,它不是表示请求文件开始位置的201个字节,而是表示要请求文件结尾处的200个字节。

    (3)如果last byte pos小于first byte pos,那么这个Range请求就是无效请求,server需要忽略这个Range请求,然后回应一个200,把整个文件发给client。

    (4)如果last byte pos大于等于文件长度,那么这个Range请求被认为是不能满足的,server需要回应一个416,Requested range not satisfiable。

     

    2.示例解释:

    表示头500个字节:bytes=0-499  

    表示第二个500字节:bytes=500-999  

    表示最后500个字节:bytes=-500  

    表示500字节以后的范围:bytes=500-  

    第一个和最后一个字节:bytes=0-0,-1  

    同时指定几个范围:bytes=500-600,601-999 

     

    三、Content-Range

     

    用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式: 

     

    Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 

     

    四、Header示例

     

    请求下载整个文件: 

     

    GET /test.rar HTTP/1.1 

    Connection: close 

    Host: 116.1.219.219 

    Range: bytes=0-801 //一般请求下载整个文件是bytes=0- 或不用这个头

     

    一般正常回应 

     

    HTTP/1.1 200 OK 

    Content-Length: 801      

    Content-Type: application/octet-stream 

    Content-Range: bytes 0-800/801 //801:文件总大小

     

    一个最简单的断点续传实现大概如下:

    1.客户端下载一个1024K的文件,已经下载了其中512K

    2. 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:

    Range:bytes=512000-

    这个头通知服务端从文件的512K位置开始传输文件

    3. 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:

    Content-Range:bytes 512000-/1024000

    并且此时服务端返回的HTTP状态码应该是206,而不是200。

    但是在实际场景中,会出现一种情况,即在终端发起续传请求时,URL对应的文件内容在服务端已经发生变化,此时续传的数据肯定是错误的。如何解决这个问题了?显然此时我们需要有一个标识文件唯一性的方法。在RFC2616中也有相应的定义,比如实现Last-Modified来标识文件的最后修改时间,这样即可判断出续传文件时是否已经发生过改动。同时RFC2616中还定义有一个ETag的头,可以使用ETag头来放置文件的唯一标识,比如文件的MD5值。

    终端在发起续传请求时应该在HTTP头中申明If-Match 或者If-Modified-Since 字段,帮助服务端判别文件变化。

    另外RFC2616中同时定义有一个If-Range头,终端如果在续传是使用If-Range。If-Range中的内容可以为最初收到的ETag头或者是Last-Modfied中的最后修改时候。服务端在收到续传请求时,通过If-Range中的内容进行校验,校验一致时返回206的续传回应,不一致时服务端则返回200回应,回应的内容为新的文件的全部数据。


    相关参考链接:http://blog.ncmem.com/wordpress/2019/08/09/http%e6%96%ad%e7%82%b9%e7%bb%ad%e4%bc%a0/ 
    欢迎入群一起讨论:374992201

    更多相关内容
  • webUploader Demo源码下载

    热门讨论 2017-04-17 20:21:54
    web Uploader demo (有修改) 百度云及我遇到的问题汇总: https://blog.csdn.net/wx11408115/article/details/70215714
  • 需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在500M内,因此自己需要在项目中进行文件上传部分的调整和配置,自己将大小都以501M来进行限制。 第一步: 前端修改 由于项目使用的是BJUI...

    需求:项目要支持大文件上传功能,经过讨论,初步将文件上传大小控制在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

    展开全文
  • 主要介绍了Java结合WebUploader实现文件上传功能,代码简单易懂,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • webuploader

    2018-01-16 10:39:52
    webuploader移动端文件上传功能,兼容ios、安卓,可以查看上传图片进度条
  • 前端webupload +后端 springboot 实现大文件的上传下载,可实现断点续传,秒传,亲测可用
  • webuploader图片上传下载,PHP服务传输机制,Wampserver64部署后可直接运行。
  • webUploader上传demo

    万次阅读 多人点赞 2017-04-17 20:31:10
    (若工程中,是上传文件到阿里云... 最近,要做文件上传功能,在同事推荐下,选择了webUploader插件。WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件,详情请看官...

    (若工程中,是上传文件到阿里云OSS中,可以去看这篇ossUploader
    最近,要做文件上传功能,在同事推荐下,选择了webUploader插件。WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件,详情请看官网(直接百度webUploader,应该是第一个)。挺好用的,于是小结一下。

    1. 准备工作

    1.1 先搭建服务,选用wamp/xamp或其他服务
    1.2 下载webUploader	下载地址: https://github.com/fex-team/webuploader 
    

    2. 选用demo

    这里写图片描述
    点击选择图片(其他文件也可以)就可以上传啦!
    这里写图片描述

    遇到的几个问题

    1. 上传稍微大一点(10M+)的文件可能会有点问题,文件名被改,文件也会出错。文件被重命名成file_***

    2. 限制上传文件大小等配置

    3. 上传文件至服务器地址修改 (自定义)

    4. 在上传文件前事件

    4.1 上传前文件格式检测

    5. 根据自己需求要在上传前做验证

    6. 获取已添加的所有文件对象

    7.上传时,携带自定义参数

    8.上传大图片被压缩,而其他文件没有问题

    9. uploader.removeFile( file, true )无效, 执行getFiles()删除的文件还在file数组里

    10 . 上传时,动态改变上传服务器地址

    上传稍微大一点(10M+)的文件可能会有点问题,文件名被改,文件也会出错。文件被重命名成file_*,例如:file_58f4a2fc7dde0, 这问题也困扰我很久,在github webUploader的issue里,也发现有人有同样的问题,https://github.com/fex-team/webuploader/issues/263 但是我这里是没有解决。
    后来查找官方API才找到答案,原来是大文件没有切片导致啊!!!!
    这里写图片描述
    解决办法: 在upload.js 中,uploader实例化的时候设置切片chunked: true,
    这里写图片描述
    在这位置,可以更改一些配置,如看"点击上传图片"不顺眼,想改成“上传文件”,就在pick那改。
    还有的想把上传文件的大小限制改动下,也可以根据自己需求在这里的fileSizeLimit那里改。

    fileNumLimit {int} [可选] [默认值:undefined] 验证文件总数量, 超出则不允许加入队列。
    fileSizeLimit {int} [可选] [默认值:undefined] 验证文件总大小是否超出限制, 超出则不允许加入队列。
    fileSingleSizeLimit {int} [可选] [默认值:undefined] 验证单个文件大小是否超出限制, 超出则不允许加入队列。
    

    改成切片后,再上传文件,
    这里写图片描述
    成功! 完美。
    那这里又存在一个疑问,那文件上传的位置在哪里更改呢?
    这里写图片描述

    在server/fileupload.php 中改 t a r g e t D i r 和 targetDir 和 targetDiruploadDir
    这里写图片描述
    这里写图片描述

    a. 在上传文件前事件

    //我自己的需求是,只能添加xml格式和zip格式文件 
    //webuploader.js
     input.on( 'change', function( e ) {  
                        var fn = arguments.callee,
                            clone;
                            //code                        
    
    
    /**下面检测文件格式的方法不推荐!不推荐!!! (webuploader实例化中有配置)
    	在file 对象中有个ext属性是文件格式的,可以用。
    */
    

    这里写图片描述

    上传前文件格式检测
    在webuploader实例化那里可以配置,详情看官网文档
    这里写图片描述
    我这里还有需要根据权限的不同去指定上传文件格式,我用个数组/字符串变量保存 (具体是字符串还是数组,请参看源码中怎么加,你就怎么加)
    这里写图片描述
    这里写图片描述

    实际上在这里加,只是在你点击添加文件时,那个弹框就给你过滤了其他文件,留下你指定的文件类型。
    如图。若用户吧把那个自定义文件下拉框换成全部文件,就可以添加其他文件了(刚刚自测了一把)。

    这里写图片描述

    显然,这与我们需求不符,uploader实例化配置accept只是个简单的过滤而已,
    所以还是得在文件添加到控件中,就自己检测。(个人觉得,就按我上面的那样,一旦用户添加进来了,就里面检测,添加不通过直接打回去)

    b. 根据自己需求要在上传前做验证

    //在662行左右,点击时做验证
          $upload.on('click', function() {
                if ( $(this).hasClass( 'disabled' ) ) {
                    return false;
                }
    

    这里写图片描述

    c. 获取已添加的所有文件对象

    //有时需要把所有文件做个判断啥的,就需要用到
    var fileItem = uploader.getFiles(); 
    //要文件添加进去了,才有用。在刚刚添加文件时,是无效的。
    //uploader是一个实例
    

    d. 上传时,携带自定义参数

    //见uploader实例化
    			uploader.options.formData.houseName = houseName;
                uploader.options.formData.houseType = houseType;
                uploader.options.formData.address = district; 
                //添加到实例化后就可以了,
    

    这里写图片描述
    这里写图片描述
    //地址瞎写的,
    e. 上传大图片被压缩,而其他文件没有问题
    之前自己检测过,上传大文件(非图片)到服务器上,与上传前文件对比大小,是没有问题的。 但是今天同事说,他传的图片(8M)被压缩(400kb左右)了,刚刚开始还不信,毕竟之前自己检测过,上传后的文件和原文件的大小一致。 后来查官方文档才知道真被压缩了。 文档是这么说的
    这里写图片描述
    解决办法: 在uploader实例化的时候,加个参数 compress: false;

    **9. uploader.removeFile( file, true )无效, 执行getFiles()删除的文件还在file数组里 **
    测试给我提个单,说删除有问题。
    额·····
    后来自己定位到,在点击删除时,执行到uploader.removeFile(file), 居然只是从视图中删除了? 没从file数组删除????
    什么鬼?
    这里写图片描述
    后来查官方API,说只要把removeFile()方法后面加个true就可以了。然并卵。。。。
    再去github issue查,这种问题还真有好几个,
    这里写图片描述
    不过都没有解决方法,最终找到个解决办法
    https://github.com/fex-team/webuploader/pull/2049/commits/b5461ee16deece92dbb34d2253f4c6ab3b215c1d
    但是写的我糊里糊涂,没整明白(也许是我理解能力不好),自己尝试几次,终于搞好了。所以就写下来,记录下。

    只要在webuploader.js 中加几行代码就好。

    1. 在webuploader.js 中搜到 function Queue() 方法
    2. 在里面添加 删除方法
    _delFile : function(file){
        for(var i = this._queue.length-1 ; i >= 0 ;i-- ){
          if(this._queue[i] == file){
             this._queue.splice(i,1);
             break;
          }
       }
    },
    
    1. 然后再在removeFile: function( file ) { 调用下就好了
      这里写图片描述
      最后附上一张gif,不骗你们啦~~~~
      在这里插入图片描述

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-doDypWhr-1569552244896)(https://img-blog.csdn.net/20170719164149880?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3gxMTQwODExNQ==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
    原有4个文件,删除一个,再删除一个,无压力啦~~~~~

    10 . 上传时,动态改变上传服务器地址

    我在一个实例化中,根据某种需求动态改变server地址。只要把uploader实例那个server配置改下就好了
    根据某个标记,然后动态改server地址(我在uploader实例化中,就把服务器地址给写好了,可以直接用。要是服务器地址比较多,就直接复制server地址吧。看个人)
    我是在点击上传那个事件中加的,

      $upload.on('click', function() { //700多行,搜下
    

    这里写图片描述
    demo下载地址(有删改,功能不变): 不贴了 (ps: 吐槽下csdn, 之前我自己上传这个demo,是0积分下载,貌似是上个月,它自己涨价到1积分,今天突然发现,nnd又涨价了,2积分。 奸商啊! )

    另附一个百度云下载地址:

    链接:http://pan.baidu.com/s/1boUSzhH 密码:z0l9

    另外,vue+ webuploader可以搞的。

    再次感谢百度团队贡献~~~

    展开全文
  • 近日,自己的服务器每次上传文件都感觉比较麻烦,所以想着自己动手搞一个文件上传和下载的服务. 实现的功能 大文件分片上传 文件下载 显示目录 新建文件夹 项目前的准备 技术采用了uploader 和spring的技术 ...

    原因

    近日,自己的服务器每次上传文件都感觉比较麻烦,所以想着自己动手搞一个文件上传和下载的服务.

    实现的功能

    1. 大文件分片上传
    2. 文件下载
    3. 显示目录
    4. 新建文件夹
      在这里插入图片描述

    项目前的准备

    1. 技术采用了uploader 和spring的技术
    2. uploader 相关包的下载 如下:
      在这里插入图片描述
    3. maven 相关依赖
    <build>
            <!--声明并引入子项目共有的插件-->
            <!--        <pluginManagement>-->
            <plugins>
                <!--java maven的打包插件-->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>1.5.3.RELEASE</version>
                    <configuration>
                        <mainClass>com.xiaobo.Star</mainClass>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>repackage</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.5.1</version> <!-- or newer version -->
                    <configuration>
                        <source>1.8</source> <!-- depending on your project -->
                        <target>1.8</target> <!-- depending on your project -->
                        <annotationProcessorPaths>
                            <path>
                                <groupId>org.projectlombok</groupId>
                                <artifactId>lombok</artifactId>
                                <version>1.18.12</version>
                            </path>
                            <!-- other annotation processors -->
                        </annotationProcessorPaths>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>3.2.0</version>
                    <configuration>
                        <archive>
                            <manifest>
                                <!--指定入口文件的位置-->
                                <mainClass>com.xiaobo.Star</mainClass>
                            </manifest>
                        </archive>
                        <descriptorRefs>
                            <descriptorRef>
                                jar-with-dependencies
                            </descriptorRef>
                        </descriptorRefs>
                    </configuration>
    
                </plugin>
            </plugins>
        </build>
    
        <dependencies>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-api</artifactId>
                <version>2.17.1</version>
            </dependency>
            <dependency>
                <groupId>org.apache.logging.log4j</groupId>
                <artifactId>log4j-core</artifactId>
                <version>2.17.1</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>2.3.1.RELEASE</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-logging</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-autoconfigure</artifactId>
                <version>2.3.1.RELEASE</version>
            </dependency>
    
            <dependency>
                <groupId>commons-fileupload</groupId>
                <artifactId>commons-fileupload</artifactId>
                <version>1.3.1</version>
            </dependency>
            <dependency>
                <groupId>commons-io</groupId>
                <artifactId>commons-io</artifactId>
                <version>2.4</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpcore</artifactId>
                <version>4.4.10</version>
            </dependency>
    
            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.6</version>
            </dependency>
        </dependencies>
    

    开始飙代码

    1. 前端html代码
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>webuploader</title>
    </head>
    <!--引入CSS-->
    <link rel="stylesheet" type="text/css" href="webuploader.css">
    <script src="jquery-1.11.1.js"></script>
    <script src="webuploader.js"></script>
    <style>
        #upload-container, #upload-list {
            width: 500px;
            margin: 0 auto;
        }
    
        #upload-container {
            cursor: pointer;
            border-radius: 15px;
            background: #EEEFFF;
            height: 200px;
        }
    
        #upload-list {
            height: 800px;
            border: 1px solid #EEE;
            border-radius: 5px;
            margin-top: 10px;
            padding: 10px 20px;
        }
    
        #upload-container > span {
            widows: 100%;
            text-align: center;
            color: gray;
            display: block;
            padding-top: 15%;
        }
    
        .upload-item {
            margin-top: 5px;
            padding-bottom: 5px;
            border-bottom: 1px dashed gray;
        }
    
        .percentage {
            height: 5px;
            background: green;
        }
    
        .btn-delete, .btn-retry {
            cursor: pointer;
            color: gray;
        }
    
        .btn-delete:hover {
            color: orange;
        }
    
        .btn-retry:hover {
            color: green;
        }
    
        .fileImage {
            background-image: url("images/file.png");
            background-repeat: no-repeat;
            background-size: 25px 25px;
            height: 25px;
            width: 400px;
            cursor: pointer;
            overflow: hidden visible;
        }
    
        .fileFont {
            margin-left: 30px;
            margin-top: 50px;
            overflow: hidden;
            weight: auto;
            word-break: normal;
            white-space: pre-wrap;
            word-wrap: break-word;
            overflow: hidden;
        }
    
        .directoryImage {
            background-image: url("images/directory.png");
            background-repeat: no-repeat;
            background-size: 25px 25px;
            height: 25px;
            width: 400px;
            cursor: pointer;
            overflow: hidden visible;
        }
    
        .directoryFont {
            margin-left: 30px;
            margin-top: 50px
        }
    
        .upperLevel {
            height: 40px;
            cursor: pointer;
            float: left;
        }
    
        .createFile {
            height: 40px;
            cursor: pointer;
            float: right;
        }
        .warnMessage{
            position: absolute;
            left: 42%;
            top: 20px;
            color: #00FF00;font-family: 'Georgia,Serif';
            font-style: oblique;
            display: none;
        }
    
    </style>
    <! --引入JS-->
    <body>
    <div style="clear: both;width: 80%;height:10px;margin:0 auto">
        <div style="float: left;width: 40%">
            <div id="upload-container"
            ">
            <span>点击或将文件拖拽至此上传</span>
        </div>
        <div id="upload-list">
        </div>
    </div>
    <div style="width: 40%;float: right;padding: 100px;">
        <div style="width: 400px;height: 40px;clear: both">
            <div class="upperLevel">上一级</div>
            <div class="createFile">新建文件夹</div>
        </div>
        <div id="filePath">
    
        </div>
    </div>
    </div>
    
    <button id="picker" style="display: none;">点击上传文件</button>
    
    <div class="warnMessage">
        <div>提示信息</div>
    </div>
    </body>
    
    
    <script>
        var absolutely = '/'
        getPath()
    
        function getPath(){
            $.ajax({
                type : "GET",
                url : 'http://localhost:8080/getFilePath?path='+absolutely,
                success : function(message){
                    console.log(message);
                    if (message.code == 200){
                        listFile(message)
                        showWarnMessage('获取列表成功')
                    }
    
                }
            });
        }
    
        function showWarnMessage(message){
            var warnMessage = $(".warnMessage");
            warnMessage.html("<div style='display: block'}>"+message+"<div>")
            warnMessage.slideDown(2000);
            setTimeout(function(){warnMessage.slideUp(2000);},1000);
    
        }
        function createFile(filename){
            $.ajax({
                type : "GET",
                url : 'http://localhost:8080/createFile?path='+absolutely+filename,
                success : function(message){
                    // console.log(message);
                    if (message.code == 200){
                        showWarnMessage('创建文件成功')
                    }
    
                }
    
            });
        }
        function download(filename){
            var url = 'http://localhost:8080/download'
            var form = $("<form></form>").attr("action", url).attr("method", "get");
            form.append($("<input></input>").attr("type", "hidden").attr("name", "path").attr("value", absolutely+filename));
            form.appendTo('body').submit().remove();
        }
    
        function listFile(message){
            var file = '<div id="listFile">'
            for (let filePath of message.data.files){
                file += '<div class="fileImage"> <span class="fileFont">'+filePath+'</span></div>'
    
            }
            for (let filePath of message.data.directory){
                file += '<div class="directoryImage"> <span class="directoryFont">'+filePath+'</span></div>'
            }
            file +="</div>"
            $('#filePath').html(file)
        }
    
        $('body').on('click','#filePath .directoryImage',function (evnet){
            let text = $(this).text().trim()
            absolutely +=text +'/'
            console.log(absolutely)
            var name = absolutely
            getPath()
        })
        $('body').on('click','#filePath .fileImage',function (evnet){
            let name = $(this).text()
            console.log(this.innerHTML)
            // let text = this.text();
            var r = confirm("确定下载文件: "+ name)
            if (r == true) {
                console.log("开始下载")
                download(name.trim())
            }
    
        })
    
        $('.upperLevel').click(function(event) {
            var name = absolutely.substring(absolutely.lastIndexOf('/'))
            absolutely = name
            getPath()
        });
        $('.createFile').click(function(event) {
            var txt;
            var fileName = prompt("请输入文件夹的名称:", "11");
            if (fileName != null || fileName.trim() != "") {
                createFile(fileName)
                getPath()
            }
    
        });
    
        $('#upload-container').click(function(event) {
            $("#picker").find('input').click();
        });
        var uploader = WebUploader.create({
            auto: true,// 选完文件后,是否自动上传。
            swf: 'Uploader.swf',// swf文件路径
            server: 'http://localhost:8080/upload',// 文件接收服务端。
            dnd: '#upload-container',
            pick: '#picker',// 内部根据当前运行是创建,可能是input元素,也可能是flash. 这里是div的id
            multiple: true, // 选择多个
            chunked: true,// 开启分片上传。
            threads: 20, // 上传并发数。允许同时最大上传进程数。
            method: 'POST', // 文件上传方式,POST或者GET。
            fileSizeLimit: 1024*1024*1024*10*1024, //验证文件总大小是否超出限制, 超出则不允许加入队列。
            fileSingleSizeLimit: 1024*1024*1024, //验证单个文件大小是否超出限制, 超出则不允许加入队列。
            fileVal:'upload', // [默认值:'file'] 设置文件上传域的name。
            formData: { "path": absolutely}
        });
    
        uploader.on("beforeFileQueued", function(file,data) {
            console.log(file); // 获取文件的后缀
        });
    
        uploader.on( 'uploadBeforeSend', function( block, data ) {
            // block为分块数据。
            // file为分块对应的file对象。
            var file = block.file;
            // 修改data可以控制发送哪些携带数据。
            data.path = absolutely;
        });
    
    
    
        uploader.on('fileQueued', function(file) {
            // 选中文件时要做的事情,比如在页面中显示选中的文件并添加到文件列表,获取文件的大小,文件类型等
            console.log(file.ext); // 获取文件的后缀
            console.log(file.size);// 获取文件的大小
            console.log(file.name);
            var html = '<div class="upload-item"><span>文件名:'+file.name+'</span><span data-file_id="'+file.id+'" class="btn-delete">删除</span><span data-file_id="'+file.id+'" class="btn-retry">重试</span><div class="percentage '+file.id+'" style="width: 0%;"></div></div>';
            $('#upload-list').append(html);
            uploader.md5File( file )//大文件秒传
    
                // 及时显示进度
                .progress(function(percentage) {
                    console.log('Percentage:', percentage);
                })
    
                // 完成
                .then(function(val) {
                    console.log('md5 result:', val);
                });
        });
    
        uploader.on('uploadProgress', function(file, percentage) {
            console.log(percentage * 100 + '%');
            var width = $('.upload-item').width();
            $('.'+file.id).width(width*percentage);
        });
    
        uploader.on('uploadSuccess', function(file, response) {
            console.log(file.id+"传输成功");
            getPath()
            // showWarnMessage('上传文件成功')
        });
    
        uploader.on('uploadError', function(file) {
            console.log(file);
            console.log(file.id+'upload error')
            showWarnMessage('上传文件失败')
        });
    
        $('#upload-list').on('click', '.upload-item .btn-delete', function() {
            // 从文件队列中删除某个文件id
            file_id = $(this).data('file_id');
            // uploader.removeFile(file_id); // 标记文件状态为已取消
            uploader.removeFile(file_id, true); // 从queue中删除
            console.log(uploader.getFiles());
        });
    
        $('#upload-list').on('click', '.btn-retry', function() {
            uploader.retry($(this).data('file_id'));
        });
    
        uploader.on('uploadComplete', function(file) {
            console.log(uploader.getFiles());
        });
    
    
    
    </script>
    </html>
    
    1. 后端上传代码
    @RequestMapping("/upload")
        @ResponseBody
        @CrossOrigin
        public ApiResponse upload(HttpServletRequest request, HttpServletResponse response, @RequestParam MultipartFile[] myfiles) {
    
            return fileService.upload1(request, response);
        }
    
    public ApiResponse upload1(HttpServletRequest request, HttpServletResponse response) {
    
            if (ServletFileUpload.isMultipartContent(request)) {
                String chunks = request.getParameter("chunks");
                MultipartFile uploadFile = ((MultipartHttpServletRequest) request).getFileMap().get("upload");
    
                // byte 数组
                byte[] bytes = new byte[1024];
                // 获取文件名
                String name = request.getParameter("name");
                String path = request.getParameter("path");
                // 判断是否是大文件开启 分片上传
                if (chunks == null) {
                    log.warn(" 文件: " + name + "开始上传");
                    System.out.println(" 文件: " + name + "开始上传");
                    InputStream inputStream = null;
                    File file = null;
                    BufferedOutputStream bw = null;
                    try {
                        inputStream = uploadFile.getInputStream();
                        file = new File(filePath + path + "\\" + name);
                        System.out.println(filePath + path + "\\" + name);
                        if (!file.exists()) {
                            bw = new BufferedOutputStream(new FileOutputStream(file));
                            file.createNewFile();
                            int temp = 0;
                            while ((temp = inputStream.read(bytes)) != -1) {
                                bw.write(bytes, 0, temp);
                                bw.flush();
                            }
                            bw.flush();
                            log.warn(filePath + path + "\\" + name + ": 文件上传成功");
                            System.out.println(filePath + path + "\\" + name + ": 文件上传成功");
                        } else {
                            // 存在抛出异常
                            response.getWriter().write("文件名已存在" + name);
                            response.reset();
                            log.error("文件名已存在" + name);
                            System.out.println("文件名已存在" + name);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                            if (bw != null) {
                                bw.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                } else {
                    String chunk = request.getParameter("chunk");
                    InputStream inputStream = null;
                    File file = null;
                    BufferedOutputStream bw = null;
                    String[] fileNames = name.split("\\.");
                    StringBuilder fileName = new StringBuilder();
                    for (int i = 0; i < fileNames.length - 1; i++) {
                        fileName.append(fileNames[i]);
                        if (i < fileNames.length - 2) {
                            fileName.append(".");
                        }
                    }
                    String fileFuffix = fileNames[fileNames.length - 1];
                    String tempName = filetemp + "\\" + fileName;
                    try {
                        inputStream = uploadFile.getInputStream();
                        file = new File(tempName + "$%" + chunk);
                        log.warn(" 文件: " + tempName + "$%" + chunk + "开始上传");
                        System.out.println(" 文件: " + tempName + "$%" + chunk + "开始上传");
                        if (!file.exists()) {
                            bw = new BufferedOutputStream(new FileOutputStream(file));
                            file.createNewFile();
                            int temp = 0;
                            while ((temp = inputStream.read(bytes)) != -1) {
                                bw.write(bytes, 0, temp);
                                bw.flush();
                            }
                            bw.flush();
                        } else {
                            // 存在抛出异常
    //                        log.warn("临时文件已存在" + tempName + "$%" + chunk);
                            System.out.println("临时文件已存在" + tempName + "$%" + chunk);
                        }
                        if (Integer.parseInt(chunks) - 1 == Integer.parseInt(chunk)) {
                            log.warn(filePath + "\\" + fileName + "." + fileFuffix + ": 开始合并");
                            System.out.println(filePath + "\\" + fileName + "." + fileFuffix + ": 开始合并");
                            if (mergeFile(filePath, chunks, path, fileName.toString(), fileFuffix).equals("合并失败")) {
                                log.error("上传文件: " + name + "失败");
                                System.out.println("上传文件: " + name + "失败");
                                return ApiResponse.FAIL("合并失败");
                            }
                            log.warn(filePath + name + ": 文件上传成功");
                            System.out.println(filePath + name + ": 文件上传成功");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        log.error("上传文件: " + name + "失败");
                        System.out.println("上传文件: " + name + "失败");
                    } finally {
                        try {
                            if (inputStream != null) {
                                inputStream.close();
                            }
                            if (bw != null) {
                                bw.close();
                            }
                        } catch (IOException e) {
                            e.printStackTrace();
                            log.error("上传文件: " + name + "中 流关闭失败");
                            System.out.println("上传文件: " + name + "中 流关闭失败");
                        }
                    }
    
                }
    
            }
            return ApiResponse.OK("上传成功");
        }
    
    1. 后台下载接口
    @RequestMapping("/download")
        @ResponseBody
        @CrossOrigin
        public void download(HttpServletRequest request, HttpServletResponse response) {
            fileService.download1(request, response);
        }
    
    public void download1(HttpServletRequest request, HttpServletResponse response) {
            String path = request.getParameter("path");
            response.setCharacterEncoding("utf-8");
            InputStream inputStream = null;
            File file = null;
            BufferedOutputStream bw = null;
    
            try {
                file = new File(filePath + path);
                log.warn("开始下载文件: " + filePath + path);
                System.out.println("开始下载文件: " + filePath + path);
                // 分片下载
                long fSize = file.length();
                // 应中文可能会出翔的乱码
                String fileName = URLEncoder.encode(file.getName(), utf8);
                response.setContentType("application/x-download");
                // 让用户选择下载到的地址
                response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
                // 查看客户端是否支持分片下载
                response.addHeader("Accept-Ranges", "bytes");
                response.addHeader("fSize", String.valueOf(fSize));
                response.addHeader("fName", "IDEA.zip");
                long pos = 0, last = fSize - 1, sum = 0;
                long rangeLength = last - pos + 1;
                String contentRange = new StringBuffer("bytes ")
                        .append(pos)
                        .append("-")
                        .append(last)
                        .append("/")
                        .append(fSize)
                        .toString();
    
                response.setHeader("Content-Range", contentRange);
                response.setHeader("Content-Length", String.valueOf(rangeLength));
                bw = new BufferedOutputStream(response.getOutputStream());
                inputStream = new BufferedInputStream(new FileInputStream(file));
                byte[] bytes = new byte[1024];
                int temp = 0;
                while (sum < rangeLength) {
                    temp = inputStream.read(bytes);
                    sum += temp;
                    bw.write(bytes, 0, temp);
                    bw.flush();
                }
                log.warn("下载完成");
                System.out.println("下载完成");
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                    if (bw != null) {
                        bw.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
    
    
        }
    

    后端获取文件列表和创建文件,删除文件

    @RequestMapping("/getFilePath")
        @ResponseBody
        @CrossOrigin
        public ApiResponse getFilePath(HttpServletRequest request, HttpServletResponse response) {
            HashMap<String, Object> filePath = fileService.getFilePath(request, response);
            return ApiResponse.OK(filePath);
        }
    
        @RequestMapping("/createFile")
        @ResponseBody
        @CrossOrigin
        public ApiResponse createFile(HttpServletRequest request, HttpServletResponse response) {
            return fileService.createFile(request, response);
        }
    
        @RequestMapping("/deleteFile")
        @ResponseBody
        @CrossOrigin
        public ApiResponse deleteFile(HttpServletRequest request, HttpServletResponse response) throws InterruptedException, UnsupportedEncodingException {
            return fileService.deleteFile(request, response);
        }
    

    项目到此顺利完成.

    展开全文
  • 可以使用的webuploader上传实例,服务器返回值已可以打印出来
  • 支持文件和文件夹的批量下载,断点续传。刷新页面后继续传输。关闭浏览器后保留进度信息。 支持文件夹批量上传下载,服务器端保留文件夹层级结构,服务器端文件夹层级结构与本地相同。 支持大文件批量上传(20G)...
  • webuploader.zip

    2020-04-08 16:55:12
    webuploader 插件资源 包含了swf,css,js ,你们页可以去官网下载最新的:http://fex.baidu.com/webuploader/download.html 我这是权当存储了,哈哈哈
  • webuploader.js大概4880行代码左右,在动态生成的input组件的下面(也可以直接搜索input),增加webkitdirectory属性。 function FileUploader(fileLoc, mgr) { var _this = this; this.id = fileLoc.id; this....
  • 该篇是webuploader 同步上传教程,这个插件使用需要配置的蛮多的,可以考虑使用插件BootStrap-FileInput 本篇涉及到该插件文件上传、自定义参数、图片删除 先看效果 我在结尾总结下,图片怎么跟当前信息绑定...
  • 主要介绍了Vue2.0结合webuploader实现文件分片上传功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
  • 亲自编写,但也是多方面参考。编写过程:简单明了,附有图片说明。加载即可实现功能。如有不明之处,请致电QQ7784187
  • 本文介绍了webuploader分片上传的实现代码(前后端分离),分享给大家,具体如下: WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现代文件上传组件。在现代的浏览器里面能充分发挥...
  • 在网上找了一个,自己重新组合了下,两个主要的文件,再加上官方下载的文件。其中有几个重要的点。 1.上传存放视频目录为了测试 直接777 2.fileupload.php 给执行权限 3.finfo_open 需要php环境支持二进制,我用的...
  • webuploader.js大概4880行代码左右,在动态生成的input组件的下面(也可以直接搜索input),增加webkitdirectory属性。 function FileUploader(fileLoc, mgr) { var _this = this; this.id = fileLoc.id; this....
  • 有pom 的全部依赖文件,有完整的css、js,以及demo脚本,我的后端是smm的框架,只贴出了相关的全部代码示例,一看就懂。在配置过程中,如果使用springMVC,需要配置 springMultipartFile的bean, ...
  • WebUploader目前支持web端和移动端flash的方式多上传功能,还完成了删除和下载的方法,但是需要根据自己的需求小改动下即可。首先声明没有美工样式。谢谢支持
  • WebUploader插件使用常见问题

    千次阅读 2017-12-18 19:43:14
    WebUploader插件上传图片常见问题
  • webuploader上传组件

    2018-06-20 22:00:56
    很好用的一个上传组件,支持上传回显,功能强大,是做图片、文件上传的好帮手
  • 断点续传,springboot+webuploader +mysql 实现断点续传功能
  • 单纯实现大文件分片上传 分为前后端 前端jsp页面 后端java 项目使用maven构建可以直接导入工具运行
  • springboot-webuploader.zip

    2019-07-26 17:11:36
    基于java,springboot框架简单的大文件上传demo,包含断点续传,仅供学习……
  • 最近遇见一个需要上传超大大文件的需求,调研了七牛和腾讯云的切片分段上传功能,因此在此整理前端大文件上传相关功能的实现。 在某些业务中,大文件上传是一个比较重要的交互场景,如上传入库比较大的Excel表格...
  • WebUploader 图片上传三种实例,基于ASP.NET 环境写了三个DEMO,分别为 直接上传,简单上传,模态框上传
  • 之前有使用过SWFUpload 做过上传图片功能,在本次实现过程中,有人推荐WebUploader 上传组件,因此采用web-Uploader 来实现文件上传功能。 WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH...
  • 上传演示(包括下载) 由分片上传大文件,由Flask和WebUploader支持。 通过流下载文件。目的前端采用分片方式上传大文件给合并,然后接收全部分片后,将其组合成一个文件支持多用户同时上传,互不干扰支持流式下载...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,936
精华内容 1,174
关键字:

webuploader下载