1. 程式人生 > 其它 >JAVA支援HTTP斷點續傳

JAVA支援HTTP斷點續傳

 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/ 
歡迎入群一起討論“374992201”