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”