在 GWA2Java 中處理文件上傳的HTML表單被稱爲是“客貨混裝”的HTTP請求處理。
文件上傳處理是HTTP Web開發中較爲特殊的應用,對開發者有一定的要求。無論是流行的PHP,Aspx或者JSP都需要一定的處理技巧。由於實在想不起來10多年前是如何赤手純代碼來處理客貨混裝的HTML文件上傳表單,這次還是詳細地記錄一次,以備再過些時日忘卻了而備查。
還有一層考慮是,在處理HTML的文件上傳表單時,需要考慮與 GWA2Java的融合,涉及到GWA2 的文件處理的核心模塊,因此也需要或者也是檢視GWA2架構設計的一次極好的機會。
對此前的 GWA2 Java項目的巡視,我們發現已經有一些項目涉及到文件上傳,但基本上多數是使用Ajax異步上次等,回避了“客貨混裝”模式,某個HTML表單只負責文件上傳,而另外一個表單再收集其他數據。
所以,這次要在 GWA2Java 中更好的整合進文件上傳,并且是客貨混裝模式——處理一個表單,裏面同時包括兩個字段:張三的姓名文字和張三的頭像圖片。
1. 瀏覽器客戶端 HTML表單中enctype
如果需要在瀏覽器客戶端的HTML表單中進行文件上傳,需要明確顯式地指定 Form元素的 enctype 屬性為 multipart/form-data 。
2. 服務器端接收處理文件上傳的第三方組件
基於 Apache Tomcat的 Java Web Server,進行服務器端的文件上傳處理,推薦使用的組件是 Apache commons-fileupload-1.4.jar , 一并的也要引入 Apache commons-io-2.7.jar。
3. HTTP Request.getParameter 失效
儅客戶端使用文件上傳的表單遞交數據時,Java Web Server中常規的 Servlet 對象 HTTPRequest的主要方法 request.getParameter 就失效。這也是普通程序無法處理客貨混裝的原因之一。
取而代之的,儅 enctype=multipart/form-data , 需要通過第三方組件獲取到相應的表單參數。
在 GWA2 中,其中的路由模塊嚴重依賴HTTP Request的參數,這時候,需要將主要路由參數放入Form的Action屬性中。
可以改進的另外一個方法是,通過引入 Apache commons-fileupload 的相關對象,便利 FormItems 對象,從而獲得表單中的常規非文件字段,文本文件字段的名稱和值。
遍歷FormItems獲得HTTP Request請求參數之後,再通過 request.setAttribute寫回到當前Request對象,如此即可巧妙地彌補 request.getParameter 失效的問題。
由於在 GWA2Java 中,獲取外部參數通常由 Wht.get 的方法進行,這個方法除了調用 request.getParameter 之外,還會進一步地的訪問 request.getAttribute , 從而實現了對 request.setAttribute 的訪問。再進一步地的 Wht.get 還會對訪問數據做一些基本的安全檢查。
樣例代碼:
ServletFileUpload sfileupld = new ServletFileUpload((new DiskFileItemFactory()));
formItems = sfileupld.parseRequest(request); // can only be parsed once!
if (formItems != null && formItems.size() > 0){
String iname, ivalue; byte[] bytes;
for (FileItem item : formItems){
// processes only fields that are common form fields
if (item.isFormField()){
bytes = item.getFieldName().getBytes(“ISO-8859-1”); // why 8859?
iname = new String(bytes, “UTF-8”);
bytes = item.getString().getBytes(“ISO-8859-1”);
ivalue = new String(bytes, “UTF-8”);
request.setAttribute(iname, ivalue);
//debug(“ctrl/item: iname:”+iname+”, ivalue:”+ivalue);
}
}
}
4. HTML表單上傳request 能且僅能被parse一次
上文中提到的獲取 FormItems 需要從 HTTP Request中提取,
List
這裏的Request,只能被 parseRequest 執行一次,如果在同一次請求處理程序中,再次對這個 request 執行 parseRequest 時,就會返回異常為空的錯誤。
因此,儅我們需要在程序頂部通過便利 FormItems 設置 request.setAttribute 時,還需要保留 FormItems 作爲全局對象,在後面這裏處理實際上傳文件時使用,避免再次調用 parseRequest 產生爲空的錯誤異常。
5. 揮之不去的字符轉碼: 從 ISO-8859-1 到 UTF-8
從心裏上,我們是抗拒在代碼中進行字符集轉碼的,所以從一開始,我們在 GWA2Java 中進行了前後端統一全流程一貫地使用UTF-8字符集,從而避免在系統程序内做無謂的轉碼工作。(參考:-GWA2 Java版本的i18n/中文编码/乱码问题,https://ufqi.com/blog/gwa2-java-i18n/ )
偏偏這裏儅使用客貨混裝模式進行文件上傳時,通過parseRequest出來的 FormItem 其中的非ASCII字符的編碼是 ISO-8859-1 ,對於像 GWA2Java 這樣默認的 UTF-8 環境,字符集轉碼成爲迫不得已的事情。
6. 文件上傳處理方法的歸置
在 GWA2 的架構設計中,文件上傳功能,歸屬于文件模塊,引入系統的接口文件是 inc/FileA , 針對不同的文件系統,有不同的文件類來實現 inc/FileDirver , 如 默認的文件處理是 Linux 的 inc/FileSystem .
在歸屬上,這些 inc 目錄下的類及其方法是“大家閨秀”,一般不參與到具體業務處理程序的,只能通過統一界面接口 inc/WebApp 來調用。因此理想的是調用文件上傳的邏輯流程大致為:
ctrl/a.jsp –> mod/ModA –> inc/WebApp –> inc/FileA –> inc/FileSystem .
由於文件上傳,屬於非常規的“操作”需求,另外一種非標準的捷徑是,在 mod/ModA 中直接實例化 inc/FileSystem , 從而便利地觸發對 upload 方法的運用。但這只針對具體的項目可行,且不需要可移植性。比如如果宿主系統不是 Linux, 那就不能實例化 inc/FileSystem , 相應地可能需要實例化 inc/WindowsFileSystem 來處理宿主環境是 Windows 的文件上傳。
7. 有進有出,文件刪除的操作
在此之前,核心接口類 inc/WebApp 中定義了 readObject/writeObject 用來讀寫非數據庫源的數據。其中 inc/FileA 中相應地定義了 read/write 方法,只是還沒有對應的刪除方法 rm 的實現。
接著這個機會,我們歸置並實現了 inc/FileA, inc/FileDriver 和 inc/FileSystem 三個類的 rm 方法,同時改造 inc/WebApp.rmBy 方法,將上述方法進行對接。
inc/WebApp.rmBy(“file:Path_To_File”) –> inc/FileA.rm –> inc/FileSystem.rm .
GWA2Java, GWA2 就是這樣通過一個又一個項目實踐,不斷豐富完善,日益健壯强大,儅融合和沉澱足夠多的智慧和精華,一定能取得更大的成就。我們在 UfqiWork 有福工坊 ( https://ufqi.com/work/ )上首先實現了 GWA2Java 處理文件上傳的客貨混裝模式。
-GWA2 吉娃兔 是”通用网络应用架构( General Web Application Architeture, https://ufqi.com/dev/gwa2/ )”,基于 -GWA2 可以轻便构建各种网络应用程序,
包括复杂的在线购物商城、在线医疗、在线教育、 旅游交易平台、社群或者社交网站和新闻资讯网站等,
也包括各种企事业单位网上门户,在线交互及服务作业系统等.
还可以包括为NativeApp做服务器端支持, 甚至是WebApp的全部.
-GWA2 是为数不多的支持跨开发语言的应用框架,目前支持 -Java, -PHP, -Perl, -Aspx and -Python .
-GWA2 is a “General Web Application Architecture” and based on -GWA2 developers can easily build a variety of network applications,
including complex online shopping malls, online medical services, online teaching, travel trading platforms, community or social networking sites and news information sites, etc.
Also the applications include various online portals of enterprises and institutions, online interaction and service operations systems.
Moreover it contains server-side support for NativeApp, or even all of the WebApp.
-GWA2 is one of the web frameworks which provide cross-language support for -Java, -PHP, -Perl, -Aspx and -Python at present.
-GWA2 is E.A.S.Y
**Easy Along, Swift Yield
**轻松启动, 快速产出.
有福工坊UfqiWork 是一个在线服务交易平台。( https://ufqi.com/work/ )
有福工坊提供在线分类服务信息,致力于在线撮合服务交易的买方和卖方,并为买方、卖方提供“行准”服务,居间担保服务交易。行准服务的提供方为居间交易的第三方。有福工坊的服务交易平台为整个服务交易流程的第四方。