最近做了一個下載文檔的功能,於是聯想到了上傳功能,於是自己研究了一下后台語言是java的情況下怎樣實現將文件上傳到指定的目錄,以下是項目的語言:
1、后台用jfinal框架
2、前台用jquery提交
3、樣式用了bootstrap和jquery
中間還因為需求發現了一個不錯的jquery庫,后面會有講解,不多啰嗦了,下面直接開始吧:
一、前端
1、先添加一個上傳文件的按鈕:
<button id="upload_blog" type="button" class="btn btn-info btn-lg" > <span class="glyphicon glyphicon-upload">上傳</span> </button>
注意:button和span中的class都是bootstrap中的樣式,直接拿過來用,不過用之前是要引入bootstrap相關樣式的!!!
2、點擊上傳文件的按鈕彈出一個選擇上傳文件的modal(模態框):
<div class="modal fade" id="myModal" role="dialog"> <div class="modal-dialog"> <!-- Modal content--> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" id="close">×</button> <h4 class="modal-title">上傳文件</h4> </div> <div class="modal-body"> <div id="sizecheck" class="alert alert-danger"> 提示:上傳文件大小不能超過50M! </div> <form action="" enctype="multipart/form-data" id="upload_file_form" accept="application/msword"> <span style="display: inline;margin-left: 50px;">請選擇上傳文件:</span><input id="file1" type="file" name="up_blog" style="display: inline;"> <div id="filecheck" class="alert alert-danger"><strong>Warning!</strong>只能上傳pdf和word兩種類型的文件</div> </form> </div> <div class="modal-footer"> <button id="yes_blog" type="button" class="btn btn-info">確定</button> <button id="no_blog" type="button" class="btn btn-info" data-dismiss="modal">取消</button> </div> </div> </div> </div>
上面是彈出的選擇文件的模態框,點擊確定按鈕會向后台發送上傳文件的請求:
3、提交表單,將上傳請求發送到服務器:
$("#upload_blog").click(function(){ $("#myModal").modal(); $("#filecheck").attr("hidden","hidden"); $("#sizecheck").attr("hidden","hidden"); $("#yes_blog").click(function(){ $("#upload_file_form").ajaxSubmit({ url:"/blog/uploadFile", type:"POST", dataType:"json", async:false, data:{}, beforeSubmit:function(){ //先判斷文件類型--只能上傳word、pdf或txt等文本類型的文件 var fileName = $("#file1").val(); var extension = fileName.substr(fileName.lastIndexOf(".")); if(extension==".pdf" || extension==".doc" || extension==".docx"){ $("#filecheck").attr("hidden","hidden"); }else{ $("#filecheck").removeAttr("hidden"); return false; } //判斷上傳文件的大小 var fileSize = $("#file1")[0].files[0].size; //獲取的文件大小單位是比特byte if((fileSize/(1024*1024))>50){ $("#sizecheck").removeAttr("hidden"); return false; }else{ $("#sizecheck").attr("hidden","hidden"); } }, success:function(m){ if(m.error=="1"){ alert(m.message); clearFile(); return false; }else{ $("#close").trigger("click"); toastr.success("文件上傳成功!"); clearFile(); return true; } } }); }); });
上面的JS代碼就會將上傳文件的表單提交到后台,在提交表單之前進行了一系列的驗證:
第一:判斷文件類型,只能上傳word、pdf和txt等文本類型,否則會有提示並阻止表單的提交;
第二:判斷文件的大小是否超過50M,否則會有提示並阻止表單的提交;
二、后台:
1、jfinal的controller中完成uploadFile方法:
/** * 上傳文件 * @throws IOException * @throws FileNotFoundException */ public void uploadFile(){ /*String fileDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());*/ UploadFile uploadFile = this.getFile(); JSONObject jsonObj = new JSONObject(); String fileName = uploadFile.getFileName(); File file = uploadFile.getFile(); String extension = fileName.substring(fileName.lastIndexOf(".")); String prefix; if(extension.equals(".jpg")||extension.equals(".png")||extension.equals(".gif")){ prefix = "images"; }else{ prefix = "docs"; } String filePath = file.getAbsolutePath(); File targetDir = new File(filePath.substring(0,filePath.indexOf(fileName))+prefix); File targetFile = new File(targetDir.getPath()+"/"+fileName); if(!targetDir.exists()){ targetDir.mkdir(); } //字節數組方式上傳文件 //jsonObj = BlogService.sevice.uploadByByte(filePath, fileName, file, targetFile); //通道方式上傳文件 jsonObj = BlogService.sevice.uploadByChanel(filePath, fileName, file, targetFile); renderJson(jsonObj.toJSONString()); }
注意:在上面的代碼中可以看到有【字節數組方式上傳文件】和【通道方式上傳文件】,這是我在實現過程中發現的,並對這兩種方法都做了實現:
2、在service中編寫業務邏輯,有兩種方式:
第一種方式:字節數組方式

/** * 使用字節的方式上傳文件 * @param filePath * @param fileName * @param sourceFile * @param targetFile * @return */ public JSONObject uploadByByte(String filePath,String fileName,File sourceFile,File targetFile){ FileInputStream fis = null; FileOutputStream fos = null; JSONObject jsonObj = new JSONObject(); try { fis = new FileInputStream(sourceFile); int fileSize = fis.available(); fos = new FileOutputStream(targetFile); byte[] file_byte = new byte[fileSize]; if(fis.read(file_byte,0, fileSize)!=-1){ fos.write(file_byte, 0, fileSize); } jsonObj.put("error", 0); sourceFile.delete(); } catch (FileNotFoundException e) { jsonObj.put("error", 1); jsonObj.put("message", "上傳出現錯誤,請稍后再上傳"); }catch (Exception e) { jsonObj.put("error", 1); jsonObj.put("message", "文件寫入服務器出現錯誤,請稍后再上傳"); }finally{ try { fis.close(); fos.close(); deleteAllFile(new File(filePath.substring(0,filePath.indexOf(fileName)))); } catch (IOException e) { e.printStackTrace(); } } return jsonObj; }
第二種方式:通道方式

/** * 使用通道的方式上傳文件 * @param filePath * @param fileName * @param sourceFile * @param targetFile * @return */ public JSONObject uploadByChanel(String filePath,String fileName,File sourceFile,File targetFile){ JSONObject jsonObj = new JSONObject(); FileInputStream fis = null; FileOutputStream fos = null; FileChannel in = null; FileChannel out = null; try { targetFile.createNewFile(); fis = new FileInputStream(sourceFile); fos = new FileOutputStream(targetFile); in = fis.getChannel();//得到對應的文件通道 out = fos.getChannel(); in.transferTo(0,in.size(),out);//連接兩個通道,並且從in通道讀取后寫入out通道 jsonObj.put("error", "0"); } catch (IOException e) { jsonObj.put("error", "1"); jsonObj.put("message", "文件寫入服務器出錯,請稍后再傳!"); }finally{ try { fis.close(); fos.close(); in.close(); out.close(); deleteAllFile(new File(filePath.substring(0,filePath.indexOf(fileName)))); } catch (IOException e) { e.printStackTrace(); } } return jsonObj; }
其實兩種方式的差別不是特別大,大家可以自己研究一下!!
注意:在controller中對文件上傳的位置進行了自定義:
首先Jfinal默認保存路徑是webroot下的upload文件夾,要想保存在自己定義的文件夾中,先要在jfinal中進行配置,如果我要保存在webroot下的/static/upload中就要進行下面的配置:
me.setBaseUploadPath(PathKit.getWebRootPath()+"/static/upload");
然后要根據文件的類型,在自定義路徑下分類創建不同的文件夾保存文件。controller中調用service之前的代碼就是做了這個功能:
UploadFile uploadFile = this.getFile(); JSONObject jsonObj = new JSONObject(); String fileName = uploadFile.getFileName(); File file = uploadFile.getFile(); String extension = fileName.substring(fileName.lastIndexOf(".")); String prefix; if(extension.equals(".jpg")||extension.equals(".png")||extension.equals(".gif")){ prefix = "images"; }else{ prefix = "docs"; } String filePath = file.getAbsolutePath(); File targetDir = new File(filePath.substring(0,filePath.indexOf(fileName))+prefix); File targetFile = new File(targetDir.getPath()+"/"+fileName); if(!targetDir.exists()){ targetDir.mkdir(); }
最后,會發現即便是自己根據文件類型在默認路徑下定義了新的文件夾,而且文件也會分類保存在相應的文件夾下,但是jfinal還是會在默認路徑下保存一份文件,這樣同一份文件,在默認路徑下和默認路徑下的自定義路徑中都
保存了一份,如下圖所示:
所以為了上文件只保存在指定的目錄中,就要做一個刪除upload目錄下的冗余文件的操作,就是service中調用的deleteAllFile(new File(filePath.substring(0,filePath.indexOf(fileName))));這部分,實現如下:
/** * 刪除默認路徑下的文件 * @param file */ public void deleteAllFile(File file){ File[] files = file.listFiles(); for(int i=0;i<files.length;i++){ File filei = files[i]; if(filei.isFile()){ filei.delete(); } } }
以上所有步驟就完成了一次上傳文件到指定目錄的功能,下面說一下剛開始說的發現的有趣的jquery庫,可以在提交表單的代碼中看到這么一句:
toastr.success("文件上傳成功!");
其實這是一個提示框,而且可以設置自動消失,避免用戶知道自己操作成功之后還要手動關閉提示框的操作,下面說一下這個技術的實現:
第一步:下載相關的包,並引入相關文件:
只要搜索toastr.js下載就會找到github資源路徑,下載壓縮包,解壓后找到這幾個文件:
不一定都能用到,但是都放在lib里,以備不時之需,我在這里只用到了這幾個:
<link rel="stylesheet" type="stylesheet" href="../../static/js/lib/bootstrap/css/message/toastr.min.css"> <link rel="stylesheet" type="stylesheet" href="../../static/js/lib/bootstrap/css/message/messenger.css"> <script type="text/javascript" src="../../static/js/lib/bootstrap/js/message/messenger.min.js?v=${version}"></script> <script type="text/javascript" src="../../static/js/lib/bootstrap/js/message/messenger-theme-future.js?v=${version}"></script>
第二步:使用前進行配置:
/*提示框配置 */ toastr.options = { /* closeButton:false,//是否配置關閉按鈕 debug:false,//是否開啟debug模式 neweastOnTop:false,//新消息是否排在最上面 progressBar:false,//是否顯示進度條 preventDuplicates:false,//是否阻止彈出多個消息框 onclick:null,//點擊回調函數 showDuration:"300",//顯示動作時間 hideDuration:"300",//隱藏動作時間 */ positionClass: "toast-center",//消息框的顯示的位置 timeOut:"1000",//自動關閉的超時時間,即1秒后關閉 /* extentedTimeOut:"1000", showEasing:"swing", hideEasing:"liner", showMethod:"fadeIn",//顯示的方式 hideMethod: "fadeOut",//關閉的方式 */ }
上面是所有配置信息以及作用的解釋,值得注意的是,positionClasss屬性,默認的值有:
可以看到,這些屬性值中,提示框的位置都是在邊緣,沒有在中間的,所以我就自定義了一個處於中間位置的class:toaster-center
大家也可以根據自己的頁面屬性自定義 !!
配置完之后就是使用了,其實使用起來很簡單,就一句代碼的事:
toastr.success("文件上傳成功!");
success方式只是定義了彈出框的背景顏色,總共有四種方式:
1、success成功:綠色
2、info信息:藍色
3、warning警告:橙色
4、error錯誤:深紅色
這個顏色的標准跟bootstrap中是一樣的!
以上就是本次文件上傳的所有代碼,以及延伸jquery庫的介紹,下次會介紹后台語言選擇PHP的情況下的文件上傳,今天就到此為止吧,抬頭發現,人都走了,我也該下班去鍛煉身體了!