在WEB開發中,上傳文件的操做時必不可少的一項功能。那麼,在Jfinal中,關於文件上傳的操做,他到底都作了些什麼呢?又有什麼須要注意的了?今天咱們就來看看關於文件上傳的那些個故事。java
關於上傳文件,他和普通的表單提交不同,有啥不同,爲什麼不同,怎麼就不同了?我想這個應該不用我多少吧,作WEB應用的同窗們都應該知道,在有附件提交的那種表單裏面,必定要加一個屬性「enctype="multipart/form-data"」加了這個之後,咱們就能夠經過POST請求的方式將全部相關信息提交到咱們的後臺去了!!可是,在使用JFinal的時候,咱們必定要注意一點,就是在咱們後臺接收這個POST數據的時候,咱們必定要注意一點的就是,假如咱們的POST請求中有上傳附件的表單元素,也就是<input type=」file」 name=」filename」>的時候,咱們必定要將框架
<!-- lang: java --> UploadFile uf = getFile("filename","code/");
這個東西放在方法的第一行,由於這樣的話,纔可以接收表單元素中的非上傳附件的元素的值,至於他爲何要這麼去作,咱們再後面會詳細的介紹,先告訴你們怎麼去使用,而後在去理解原理,我認爲這個是在軟件開發領域中廣泛的學習方法吧,由於我寫的這些基本上應該是屬於內功,和江湖上所說的那些個「《九陰真經》」之類的書籍屬於一個性質,嘿嘿,開始有點飄了!!學習
廢話不說,進入正題: 一、若是要使用Jfinal的文件上傳的話,他必定是有依賴包的,記住,必定是有依賴包,不然,你的上傳操做是會出現未知的錯誤的,那麼這個依賴包是啥?從哪兒下。 答案:依賴包是「cos.jar」至少個人是這個,若是版本有更新的話,你均可以從Jfinal的那個官網上面去下載下來,這樣的,你就能夠下載到最新的那個jar包了,不過應該不會常常變吧,不然就用戶會受不了的編碼
好了第一個問題解決,在咱們假如jar包之後,咱們就能夠來進行文件上傳了。code
按照我剛剛說的那個,在你要處理的方法的第一行 寫上上述的那一句接收的方法,那麼你的文件上傳基本算做完了,是的,就是這樣,此時的文件已經到了你的默認上傳文件的目錄項目下面了,只是此時,他的名稱和你本地的名稱同樣,不過這只是第一步,也就是所,他的文件是不會放到一個臨時的文件夾或者之類的地方,而是直接給弄過去到一個他默認的位置的。文件夾的名稱叫作「upload」,如今咱們就看看這個過程orm
因爲咱們再Controller中使用getFile()這個方法來接收相關的文件,因此咱們就從這個地方下手,看看Jfinal框架的自己對這個過程都作了什麼樣的操做。對象
打開Controller這個類,找到getFile這個方法,咱們看看都有些啥:事件
<!-- lang: java --> public UploadFile getFile(String parameterName, String saveDirectory) { getFiles(saveDirectory); return getFile(parameterName); } public UploadFile getFile(String parameterName, String saveDirectory, Integer maxPostSize, String encoding) { getFiles(saveDirectory, maxPostSize, encoding); return getFile(parameterName); } public UploadFile getFile(String parameterName) { List<UploadFile> uploadFiles = getFiles(); for (UploadFile uploadFile : uploadFiles) { if (uploadFile.getParameterName().equals(parameterName)) { return uploadFile; } } return null; }
以上是列舉了一些getFile的方法,咱們看看他們有什麼不一樣,ip
第一個GetFile 他接收的參數是parameter和SaveDirectory Parameter是表單裏面的file對應的name屬性值,你們應該都明白吧,就是去接收誰的參數 第二個參數就是savedirectory,這個主要是表示當前接收的文件存放在什麼位置;舉個例子;假如咱們的文件上傳的根路徑是upload(Jfinal默認的),那麼咱們假如使用這個方法的話,填寫了saveDirectory,假如是「a」,那麼文件就會被放在「upload/a/」這個路徑下面,請注意的是,假如咱們的savedirectory的文件夾不存在的話。Jfinal會自動建立出這個文件夾。開發
而後再往下看,第二行調用了getfiles()參數神馬的我就不說了,一看就可以明白是什麼意思。無非就是寫編碼,最大容許上傳之類的參數一看就應該明白
而後調用getFile(Param)去處理文件,其實若是你細心的話你能夠看到,他的處理過程是把一個上傳文件看作是多個上傳文件的一個特例,經過循環迭代出來處理各個上傳文件的。至此 咱們第一個問題算是解決了,就是在getFile的過程當中,他的底層是怎麼去處理的,若是你看到這裏,若是仍是隻知其一;不知其二的話,我強烈的建議你去看看這個JFinal框架的源代碼。寫得仍是比較的容易懂的。
好了,咱們來解決下一個問題,那就是,爲何在有上傳文件的過程中,他必定要將getFile這個方法寫在最前面,不然無論怎麼樣都會不能能接受的非上傳文件的參數,我相信,初次用JFinal框架作WEB項目的時候確定,必定以及絕對的遇到過這個問題。不過這個問題的說明在文檔中有提到過的,不過我第一次使用這個框架的時候,確實沒有好好看過這方面的東西,因此遇到這個問題的時候,我足足搞了一天,在網上各類搜索,沒有任何結果,心中有一萬匹草泥馬在心中奔騰,檢查各類配置都沒有問題,尼瑪拿到是個靈異事件。後來看文檔,才煥然大悟。原來必定要這麼幹纔可以拿到想要的東西,框架麼,確定有本身的一套規矩。因此走走彎路,有時候收穫的東西會更加多。 因此,之後再遇到這種尼瑪各項配置都OK的,又有文件上傳的狀況,你先看看getFIle這個東西是否是在你要處理方法的第一行,若是沒有的話,問題可能就出在這裏,你要問爲何,也許一下子會有答案,不過你能夠先記住一點就是,框架要求這樣作的,也許這可以給你一點點內心安慰,但假如你是把這個做爲完美解決方案的話,那麼接下來至關有養分的東西,你可能就要錯過了。
首先說說,爲何JFinal在沒有配置上傳文件根目錄的狀況下,他會在項目中建立一個叫upload的文件夾
<!-- lang: java --> private void initOreillyCos() { Constants ct = constants; if (OreillyCos.isMultipartSupported()) { String uploadedFileSaveDirectory = ct.getUploadedFileSaveDirectory(); if (uploadedFileSaveDirectory == null || "".equals(uploadedFileSaveDirectory.trim())) { uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator; ct.setUploadedFileSaveDirectory(uploadedFileSaveDirectory); /*File file = new File(uploadedFileSaveDirectory); if (!file.exists()) file.mkdirs();*/ } OreillyCos.init(uploadedFileSaveDirectory, ct.getMaxPostSize(), ct.getEncoding()); } }
在Jfinal類中,你找到一個叫initOreillyCos()的方法,別說你不會找方法的快捷鍵啊「ctrl+o」,不解釋,只要你使用的是默認的配置。這個確定管用的。 其中有一句話就是說明咱們剛剛的這個問題的:
<!-- lang: java --> uploadedFileSaveDirectory = PathKit.getWebRootPath() + File.separator + "upload" + File.separator;
喏,啥也不說了,在Jfinal初始化的時候,請注意他的判斷條件,他就會創建一個默認的文件夾,格式就是「項目根路徑」+upload+」/」。記住這個過程是在你沒有配置上傳文件根路徑的時候,系統默認的,不過這個路徑會有個問題,有啥問題,咱們一下子討論,不過若是你要使用上傳的話 我我的是不建議使用系統默認的這個,由於很悲劇。沒錯,確實是很悲劇的。 好了,咱們討論了默認上傳路徑之後,咱們須要繼續前進,而後解決其餘相關的問題。
第二個問題,在上傳文件的時候,爲何要把GetFile放在處理方法的第一行。 在咱們剛剛提到的處理上傳文件的過程當中,假如了enctype="multipart/form-data, 之後 此時的request對象就不是咱們使用普通表單提交的request對象了,咱們假設加了剛剛的那個屬性的方式的request對象叫作MutipartRequest對象,那麼咱們以getMOdel()這樣的方法的舉例
<!-- lang: java --> public <T> T getModel(Class<T> modelClass) { return (T)ModelInjector.inject(modelClass, request, false); }
在調用這個方法的時候,咱們看到 他執行了inject這個方法,正好這個方法裏面有request對象,按照咱們普通表單提交之後產生的這個request對象,咱們是可以經過反射創建這個model實例,而後遍歷其中的屬性爲咱們的model實例進行相應的賦值操做,不過咱們假設咱們提交了這個帶有附件上傳的表單,那麼咱們產生的request對象就不是咱們日常見到那個request對象,而是經過以下代碼產生的request對象:
<!-- lang: java --> public List<UploadFile> getFiles(String saveDirectory, Integer maxPostSize, String encoding) { if (multipartRequest == null) { multipartRequest = new MultipartRequest(request, saveDirectory, maxPostSize, encoding); request = multipartRequest; } return multipartRequest.getFiles(); }
經過如上的代碼,咱們能夠看到,request對象已經變成mutipartRequest對象了,這個對象裏面,我猜,他包含了原來普通request對象內容和咱們上傳附件裏面的一些個內容,這樣的話,再將這個mutipartRequest對象傳入getModel裏面,這樣經過遍歷這裏面的相應內容,從而就可以獲得咱們想要的文件相應的數據和咱們非上傳文件中的內容了,這也就可以解釋,爲何咱們再不使用getfile這個方法在最開始的時候,獲得model中的全部屬性值都爲null,由於咱們model實例是被反射建立的,而這賦值的過程但中,他並無拿到相應的值,全部所有爲NULL; 簡單總結一下: 就是在咱們進行非附件表單提交的時候,獲得的request對象時咱們JavaServlet的中的request對象,而在咱們進行帶附件上傳的時候獲得的對象實際上是包含了這個標準的Request對象內容的MutipartRequest對象,至少
<!-- lang: java --> multipartRequest = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);
request = multipartRequest;
這個證實了我剛剛說的觀點,此時的request對象非彼時的request對象。 歡迎拍磚指正啊!!