JSP-超大文件上傳-如何上傳文件-大文件上傳

咱們平時常常作的是上傳文件,上傳文件夾與上傳文件相似,但也有一些不一樣之處,此次作了上傳文件夾就記錄下以備後用。java

首先咱們須要瞭解的是上傳文件三要素:web

1.表單提交方式:post (get方式提交有大小限制,post沒有)chrome

2.表單的enctype屬性:必須設置爲multipart/form-data.數據庫

3.表單必須有文件上傳項:file,且文件項須要給定name值json

上傳文件夾須要增長一個屬性webkitdirectory,像這樣:後端

<input id="fileFolder" name="fileFolder" type="file"  webkitdirectory>瀏覽器

不過webkitdirectory屬性有個問題,只能支持高版本的chrome,不能支持低版本的IE,如ie6,ie7,ie8,不能作到全瀏覽器適配,運行環境比較單一。服務器

js中能夠判斷文件夾中文件數量及文件夾大小是否符合要求,不符合要求不能向後臺提交:app

前臺HTML模板ide

this.GetHtmlFiles = function()

{

     var acx = "";

     acx += '<div class="file-item" id="tmpFile" name="fileItem">\

                <div class="img-box"><img name="file" src="js/file.png"/></div>\

                   <div class="area-l">\

                       <div class="file-head">\

                            <div name="fileName" class="name">HttpUploader程序開發.pdf</div>\

                            <div name="percent" class="percent">(35%)</div>\

                            <div name="fileSize" class="size" child="1">1000.23MB</div>\

                    </div>\

                       <div class="process-border"><div name="process" class="process"></div></div>\

                       <div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

                   </div>\

                   <div class="area-r">\

                    <span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

                    <span class="btn-box hide" name="post" title="繼續"><img name="post" src="js/post.png"/><div>繼續</div></span>\

                       <span class="btn-box hide" name="stop" title="中止"><img name="stop" src="js/stop.png"/><div>中止</div></span>\

                       <span class="btn-box hide" name="del" title="刪除"><img name="del" src="js/del.png"/><div>刪除</div></span>\

                   </div>';

     acx += '</div>';

     //文件夾模板

     acx += '<div class="file-item" name="folderItem">\

                   <div class="img-box"><img name="folder" src="js/folder.png"/></div>\

                   <div class="area-l">\

                       <div class="file-head">\

                            <div name="fileName" class="name">HttpUploader程序開發.pdf</div>\

                            <div name="percent" class="percent">(35%)</div>\

                            <div name="fileSize" class="size" child="1">1000.23MB</div>\

                    </div>\

                       <div class="process-border top-space"><div name="process" class="process"></div></div>\

                       <div name="msg" class="msg top-space">15.3MB 20KB/S 10:02:00</div>\

                   </div>\

                   <div class="area-r">\

                    <span class="btn-box" name="cancel" title="取消"><img name="stop" src="js/stop.png"/><div>取消</div></span>\

                    <span class="btn-box hide" name="post" title="繼續"><img name="post" src="js/post.png"/><div>繼續</div></span>\

                       <span class="btn-box hide" name="stop" title="中止"><img name="stop" src="js/stop.png"/><div>中止</div></span>\

                       <span class="btn-box hide" name="del" title="刪除"><img name="del" src="js/del.png"/><div>刪除</div></span>\

                   </div>';

     acx += '</div>';

     //上傳列表

     acx += '<div class="files-panel" name="post_panel">\

                   <div name="post_head" class="toolbar">\

                       <span class="btn" name="btnAddFiles">選擇多個文件</span>\

                       <span class="btn" name="btnAddFolder">選擇文件夾</span>\

                       <span class="btn" name="btnPasteFile">粘貼文件和目錄</span>\

                       <span class="btn" name="btnSetup">安裝控件</span>\

                   </div>\

                   <div class="content" name="post_content">\

                       <div name="post_body" class="file-post-view"></div>\

                   </div>\

                   <div class="footer" name="post_footer">\

                       <span class="btn-footer" name="btnClear">清除已完成文件</span>\

                   </div>\

              </div>';

     return acx;

};

選擇文件,選擇文件夾,粘貼文件和文件夾的邏輯

this.open_files = function (json)

{

     for (var i = 0, l = json.files.length; i < l; ++i)

    {

         this.addFileLoc(json.files[i]);

     }

     setTimeout(function () { _this.PostFirst(); },500);

};

this.open_folders = function (json)

{

    for (var i = 0, l = json.folders.length; i < l; ++i) {

        this.addFolderLoc(json.folders[i]);

    }

     setTimeout(function () { _this.PostFirst(); }, 500);

};

this.paste_files = function (json)

{

     for (var i = 0, l = json.files.length; i < l; ++i)

     {

         this.addFileLoc(json.files[i]);

     }

};

後臺在接收文件夾時不一樣之處在須要用MultipartHttpServletRequest

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

     }

}

 

server端的包和類

 

 

文件塊處頁面,驗證代碼部分

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

 

生成文件名稱的邏輯

public String genFile(int uid, String md5,String nameLoc) throws IOException

{

     SimpleDateFormat fmtDD = new SimpleDateFormat("dd");

     SimpleDateFormat fmtMM = new SimpleDateFormat("MM");

     SimpleDateFormat fmtYY = new SimpleDateFormat("yyyy");

    

     Date date = new Date();

     String strDD = fmtDD.format(date);

     String strMM = fmtMM.format(date);

     String strYY = fmtYY.format(date);

    

     String path = this.getRoot() + "/";

     path = path.concat(strYY);

     path = path.concat("/");

     path = path.concat(strMM);

     path = path.concat("/");

     path = path.concat(strDD);

     path = path.concat("/");

     path = path.concat(md5);

     path = path.concat(".");

     path = path.concat(PathTool.getExtention(nameLoc));

        

    

     File fl = new File(path);

    

     return fl.getCanonicalPath();//

}

 

如下是service層作的處理:

總體模塊劃分以下:

 

其中數據類實體邏輯處理以下

public class FileInf {

 

     public FileInf(){}

     public String id="";

     public String pid="";

    public String pidRoot="";   

     /**  * 表示當前項是不是一個文件夾項。    */

     public boolean fdTask=false;        

     //   /// 是不是文件夾中的子文件  /// </summary>

     public boolean fdChild=false;

     /**  * 用戶ID。與第三方系統整合使用。    */

     public int uid=0;

     /**  * 文件在本地電腦中的名稱   */

     public String nameLoc="";

     /**  * 文件在服務器中的名稱。   */

     public String nameSvr="";

     /**  * 文件在本地電腦中的完整路徑。示例:D:\Soft\QQ2012.exe */

     public String pathLoc="";  

     /**  * 文件在服務器中的完整路徑。示例:F:\\ftp\\uer\\md5.exe     */

     public String pathSvr="";

     /**  * 文件在服務器中的相對路徑。示例:/www/web/upload/md5.exe   */

     public String pathRel="";

     /**  * 文件MD5    */

     public String md5="";

     /**  * 數字化的文件長度。以字節爲單位,示例:120125    */

     public long lenLoc=0;

     /**  * 格式化的文件尺寸。示例:10.03MB   */

     public String sizeLoc="";

     /**  * 文件續傳位置。  */

     public long offset=0;

     /**  * 已上傳大小。以字節爲單位 */

     public long lenSvr=0;

     /**  * 已上傳百分比。示例:10%  */

     public String perSvr="0%";

     public boolean complete=false;

     public Date PostedTime = new Date();

     public boolean deleted=false;

     /**  * 是否已經掃描完畢,提供給大型文件夾使用,大型文件夾上傳完畢後開始掃描。  */

     public boolean scaned=false;

}

後臺數據庫中的邏輯基本上都用到了上面的實體類

文件數據表操做類以下

加載全部未完成的文件列表

public String GetAllUnComplete(int f_uid)

{

     StringBuilder sb = new StringBuilder();

     sb.append("select ");

     sb.append(" f_id");

     sb.append(",f_fdTask");    

     sb.append(",f_nameLoc");

     sb.append(",f_pathLoc");

     sb.append(",f_md5");

     sb.append(",f_lenLoc");

     sb.append(",f_sizeLoc");

     sb.append(",f_pos");

     sb.append(",f_lenSvr");

     sb.append(",f_perSvr");

     sb.append(",f_complete");

     sb.append(",f_pathSvr");//fix(2015-03-16):修復沒法續傳文件的問題。

     sb.append(" from up6_files ");//change(2015-03-18):聯合查詢文件夾數據

     sb.append(" where f_uid=? and f_deleted=0 and f_fdChild=0 and f_complete=0 and f_scan=0");//fix(2015-03-18):只加載未完成列表

 

     ArrayList<FileInf> files = new ArrayList<FileInf>();

     DbHelper db = new DbHelper();

     PreparedStatement cmd = db.GetCommand(sb.toString());

     try {

         cmd.setInt(1, f_uid);

         ResultSet r = db.ExecuteDataSet(cmd);

         while(r.next())

         {

              FileInf f          = new FileInf();

              f.uid              = f_uid;

              f.id               = r.getString(1);

              f.fdTask      = r.getBoolean(2);              

              f.nameLoc          = r.getString(3);

              f.pathLoc          = r.getString(4);

              f.md5              = r.getString(5);

              f.lenLoc      = r.getLong(6);

              f.sizeLoc          = r.getString(7);

              f.offset      = r.getLong(8);

              f.lenSvr      = r.getLong(9);

              f.perSvr      = r.getString(10);

              f.complete         = r.getBoolean(11);

              f.pathSvr     = r.getString(12);//fix(2015-03-19):修復沒法續傳文件的問題。

              files.add(f);

             

         }

         r.close();

         cmd.getConnection().close();

         cmd.close();

     } catch (SQLException e) {

         // TODO Auto-generated catch block

         e.printStackTrace();

     }

    

     if(files.size() < 1) return null;

    

     Gson g = new Gson();

    return g.toJson( files);//bug:arrFiles爲空時,此行代碼有異常

}

實現後的總體效果以下

 

文件夾上傳完後的效果

 

服務器保存的文件夾數據,並且層級結構與本地客戶端是一致的。這在OA系統中,或者網盤系統中使用時是很是有用的

 

後端代碼邏輯大部分是相同的,目前可以支持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」

相關文章
相關標籤/搜索