JSP WEB項目大文件上傳下載解決方案

javaweb上傳文件

上傳文件的jsp中的部分

上傳文件同樣可以使用form表單向后端發請求,也可以使用 ajax向后端發請求

?1.通過form表單向后端發送請求

?Save

改進后的代碼不需要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。在使用前需要配置一下數據庫,詳細源碼可以直接百度搜索“up6”

歡迎入群一起討論“374992201”

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容