zoukankan      html  css  js  c++  java
  • JavaScript 大文件分片上传处理

    javaweb上传文件

    上传文件的jsp中的部分

    上传文件同样可以使用form表单向后端发请求,也可以使用 ajax向后端发请求

        1.通过form表单向后端发送请求

             <form id="postForm" action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">

                <div class="bbxx wrap">

                    <inputtype="text" id="side-profile-name" name="username" class="form-control">

                    <inputtype="file" id="example-file-input" name="avatar">

                    <button type="submit" class="btn btn-effect-ripple btn-primary">Save</button>

                </div>

            </form>

    改进后的代码不需要form标签,直接由控件来实现。开发人员只需要关注业务逻辑即可。JS中已经帮我们封闭好了

        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 });

        };

    通过监控工具可以看到控件提交的数据,非常的清晰,调试也非常的简单。

    2.通过ajax向后端发送请求

                $.ajax({

                     url : "${pageContext.request.contextPath}/UploadServlet",

                     type : "POST",

                     data : $( '#postForm').serialize(),

                     success : function(data) {

                          $( '#serverResponse').html(data);

                     },

                     error : function(data) {

                          $( '#serverResponse').html(data.status + " : " + data.statusText + " : " + data.responseText);

                     }

                });

    ajax分为两部分,一部分是初始化,文件在上传前通过AJAX请求通知服务端进行初始化操作

        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.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; }

            });

        };

     

    这里需要处理一个MD5秒传的逻辑,当服务器存在相同文件时,不需要用户再上传,而是直接通知用户秒传

        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);//触发事件

        };

    这里可以看到秒传的逻辑是非常 简单的,并不是特别的复杂。

                var form = new FormData();

                form.append("username","zxj");

                form.append("avatar",file);

                //var form = new FormData($("#postForm")[0]);

                $.ajax({

                    url:"${pageContext.request.contextPath}/UploadServlet",

                    type:"post",

                    data:form,

                    processData:false,

                    contentType:false,

                    success:function(data){

            

                        console.log(data);

                    }

                });

    java部分

    文件初始化的逻辑,主要代码如下

    FileInf fileSvr= new FileInf();

    fileSvr.id = id;

    fileSvr.fdChild = false;

    fileSvr.uid = Integer.parseInt(uid);

    fileSvr.nameLoc = PathTool.getName(pathLoc);

    fileSvr.pathLoc = pathLoc;

    fileSvr.lenLoc = Long.parseLong(lenLoc);

    fileSvr.sizeLoc = sizeLoc;

    fileSvr.deleted = false;

    fileSvr.md5 = md5;

    fileSvr.nameSvr = fileSvr.nameLoc;

     

    //所有单个文件均以uuid/file方式存储

    PathBuilderUuid pb = new PathBuilderUuid();

    fileSvr.pathSvr = pb.genFile(fileSvr.uid,fileSvr);

    fileSvr.pathSvr = fileSvr.pathSvr.replace("\","/");

     

    DBConfig cfg = new DBConfig();

    DBFile db = cfg.db();

    FileInf fileExist = new FileInf();

        

    boolean exist = db.exist_file(md5,fileExist);

    //数据库已存在相同文件,且有上传进度,则直接使用此信息

    if(exist && fileExist.lenSvr > 1)

    {

         fileSvr.nameSvr             = fileExist.nameSvr;

         fileSvr.pathSvr        = fileExist.pathSvr;

         fileSvr.perSvr              = fileExist.perSvr;

         fileSvr.lenSvr              = fileExist.lenSvr;

         fileSvr.complete       = fileExist.complete;

         db.Add(fileSvr);

        

         //触发事件

        up6_biz_event.file_create_same(fileSvr);

    }//此文件不存在

    else

    {

         db.Add(fileSvr);

         //触发事件

        up6_biz_event.file_create(fileSvr);

        

         FileBlockWriter fr = new FileBlockWriter();

         fr.CreateFile(fileSvr.pathSvr,fileSvr.lenLoc);

    }

    接收文件块数据,在这个逻辑中我们接收文件块数据。控件对数据进行了优化,可以方便调试。如果用监控工具可以看到控件提交的数据。

    boolean isMultipart = ServletFileUpload.isMultipartContent(request);

    FileItemFactory factory = new DiskFileItemFactory();  

    ServletFileUpload upload = new ServletFileUpload(factory);

    List files = null;

    try

    {

         files = upload.parseRequest(request);

    }

    catch (FileUploadException e)

    {// 解析文件数据错误 

        out.println("read file data error:" + e.toString());

        return;

      

    }

     

    FileItem rangeFile = null;

    // 得到所有上传的文件

    Iterator fileItr = files.iterator();

    // 循环处理所有文件

    while (fileItr.hasNext())

    {

         // 得到当前文件

         rangeFile = (FileItem) fileItr.next();

         if(StringUtils.equals( rangeFile.getFieldName(),"pathSvr"))

         {

             pathSvr = rangeFile.getString();

             pathSvr = PathTool.url_decode(pathSvr);

         }

    }

     

    boolean verify = false;

    String msg = "";

    String md5Svr = "";

    long blockSizeSvr = rangeFile.getSize();

    if(!StringUtils.isBlank(blockMd5))

    {

         md5Svr = Md5Tool.fileToMD5(rangeFile.getInputStream());

    }

     

    verify = Integer.parseInt(blockSize) == blockSizeSvr;

    if(!verify)

    {

         msg = "block size error sizeSvr:" + blockSizeSvr + "sizeLoc:" + blockSize;

    }

     

    if(verify && !StringUtils.isBlank(blockMd5))

    {

         verify = md5Svr.equals(blockMd5);

         if(!verify) msg = "block md5 error";

    }

     

    if(verify)

    {

         //保存文件块数据

         FileBlockWriter res = new FileBlockWriter();

         //仅第一块创建

         if( Integer.parseInt(blockIndex)==1) res.CreateFile(pathSvr,Long.parseLong(lenLoc));

         res.write( Long.parseLong(blockOffset),pathSvr,rangeFile);

         up6_biz_event.file_post_block(id,Integer.parseInt(blockIndex));

        

         JSONObject o = new JSONObject();

         o.put("msg""ok");

         o.put("md5", md5Svr); 

         o.put("offset", blockOffset);//基于文件的块偏移位置

         msg = o.toString();

    }

    rangeFile.delete();

    out.write(msg);

     

    注:

    1. 上面的java部分的代码可以直接使用,只需要将上传的图片路径及收集数据并将数据写入到数据库即可

    2. 上面上传文件使用到了字节流,其实还可以使用别的流,这个需要读者自己在下面完善测试

    3. BeanUtils是一个工具 便于将实体对应的属性赋给实体

    4. 上传文件不能使用 request.getParameter("")获取参数了,而是直接将request解析,通过判断每一项是文件还是非文件,然后进行相应的操作(文件的话就是用流来读取,非文件的话,暂时保存到一个map中。)

    后端代码逻辑大部分是相同的,目前能够支持MySQL,Oracle,SQL。在使用前需要配置一下数据库,可以参考我写的这篇文章:http://blog.ncmem.com/wordpress/2019/08/12/java-http%E5%A4%A7%E6%96%87%E4%BB%B6%E6%96%AD%E7%82%B9%E7%BB%AD%E4%BC%A0%E4%B8%8A%E4%BC%A0/


  • 相关阅读:
    10. Regular Expression Matching
    9. Palindrome Number
    6. ZigZag Conversion
    5. Longest Palindromic Substring
    4. Median of Two Sorted Arrays
    3. Longest Substring Without Repeating Characters
    2. Add Two Numbers
    链式表的按序号查找
    可持久化线段树——区间更新hdu4348
    主席树——树链上第k大spoj COT
  • 原文地址:https://www.cnblogs.com/songsu/p/12204970.html
Copyright © 2011-2022 走看看