本作品採用知識共享署名-非商業性使用-相同方式共享 2.5 中國大陸許可協議進行許可。
當客戶端瀏覽器指定enctype爲multipart/form-data提交表單時,HTTP服務器上與該請求對應的servlet(Servlet類或JSP網頁)將無法通過request對象的getParameter()方法取得表單域的屬性值。如果對HTTP協議熟悉的話,我們可以對multipart/form-data數據流進行分析,取出其中有用的信息。但這樣做完全沒有必要,Apache的Commons FileUpload程序包已經替我們完成了這項複雜的工作。
基本用法
FileUpload API提供了兩種核心處理類:PortletFileUpload和ServletFileUpload,本文不對PortletFileUpload做詳細描述。ServletFileUpload類有一個判斷Content-Type是否爲multipart/form-data的方法。同時提供了兩種讀取multipart/form-data數據的方式:數據流讀取方式和臨時文件讀取方式。
判斷是否是multipart/form-data
利用ServletFileUpload類的靜態方法可以判斷一個request的Content-Type是否是multipart/form-data。例:
數據流讀取方式
通過無參構造器生成的ServletFileUpload對象使用的是數據流讀取方式,可通過getItemIterator()方法取得每一個表單域的數據。如:
數據流讀取方式是一種一次性的讀取方式。一方面,upload對象只能對request的數據做一次性分析。也就是說,上文第5行只在第一次調用時有效。另一方面,分析數據只能讀取一次,第二次讀取時數據不存在。也就是說,上文第5行取到的FileItemIterator對象只能遍歷一次,第二次遍歷該對象時就無法取到數據了。
臨時文件讀取方式
通過有參構造器生成的ServletFileUpload對象使用的是臨時文件讀取方式,可通過parseRequest()方法取得表單域數據列表。如:
同樣,upload對象只能對request的數據做一次性分析。但與數據流讀取方式相對應的是,臨時文件讀取方式中解析出來的數據被緩存到緩衝文件中,可對緩存數據多次讀取,並且在必要的情況下可以修改緩存的內容。
FileUpload API出於下面的考慮實現了臨時文件讀取方式
- 如果上傳內容比較小,則將其直接放入到內存中進行管理;
- 較大的上傳內容將保存到磁盤上的一個臨時文件夾中;
- 非常大的上傳內容將被忽視。
默認情況下,FileUpload對數據大小的要求是:
- 小於10K的數據直接放到內存中管理;
- 大於10K的數據保存到系統臨時目錄中(系統臨時目錄是System.getProperty("java.io.tmpdir")的返回值);
- 所有的數據都不被忽視,即使這個數據非常大。
如何改變這些默認值呢?
如何控制FileUpload
作爲核心應用對象,ServletFileUpload可以設置以下屬性:
sizeMax
限制整個multipart/form-data數據的字節大小。默認值-1,表示無限制。
fileSizeMax
限制每個文件表單域中數據的字節大小。默認值-1,表示無限制。
headerEncoding
指定每個multipart頭部信息的編碼方式。默認爲NULL,如果該值爲NULL,則使用request中的characterEncoding值,如果characterEncoding爲NULL,則使用系統默認的字符集編碼方式。
設置屬性的樣例如下:
如果FileUpload使用臨時文件讀取方式,還可以爲工廠類設置以下屬性:
sizeThreshold
限制將文件表單域中的數據保存到內存的臨界字節大小。默認爲10K字節長度,數據小於10K字節則直接保存在內存中;數據大於10K字節則保存在臨時文件夾中。
repository
臨時文件夾的位置。默認爲System.getProperty("java.io.tmpdir")的返回值。
例如改變臨時文件夾的位置到“C:/tmp”的方法如下:
附1:FileUpload附加信息
官方網站
http://commons.apache.org/fileupload/
核心JAR包
commons-fileupload-1.2.1.jar
依賴JAR包
commons-io-1.4.jar
附2:HTTP請求數據結構
當客戶端瀏覽器使用GBK編碼提交了下面這樣一個表單時...
一個數據內容如下的HTTP請求將會發送到HTTP服務器上。
POST /test/hello.html HTTP/1.1
Referer: http://localhost:9000/test/
Accept-Language: zh-cn
Content-Type: multipart/form-data; boundary=---------------------------7d91f4b304fc
Accept-Encoding: gzip, deflate
Host: localhost:9000
Content-Length: 301
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=763D1C03A83AE30CCFBA88F42465F598
-----------------------------7d91f4b304fc
Content-Disposition: form-data; name="name"
中國
-----------------------------7d91f4b304fc
Content-Disposition: form-data; name="file"; filename="C:/test.txt"
Content-Type: text/plain
這是測試文檔的內容
-----------------------------7d91f4b304fc--[end]
每一個multipart的頭部信息用紅字表示;其編碼所用的字符集是表單所在網頁在瀏覽器上顯示時所使用的字符集。
如果multipart是一般表單域,如上例中的name表單域,其內容一般爲字符串,字符串編碼所用的字符集與multipart的頭部信息相同。
如果multipart是文件表單域,如上例中的file表單域,其內容爲文件數據的二進制表現形成,內容格式由multipart的頭部信息指定。