1. 程式人生 > >利用 Commons-Fileupload 實現檔案上傳

利用 Commons-Fileupload 實現檔案上傳

Apache FileUpload檔案上傳元件API解析(轉)

Java Web開發人員可以使用Apache檔案上傳元件來接收瀏覽器上傳的檔案,該元件由多個類共同組成,但是,對於使用該元件來編寫檔案上傳功能的Java Web開發人員來說,只需要瞭解和使用其中的三個類:DiskFileUpload、FileItem和FileUploadException。這三個類全部位於org.apache.commons.fileupload包中。


   檢視API文件

在準備實驗環境時獲得的commons-fileupload-1.0.zip檔案的解壓縮目錄中可以看到一個docs的子目錄,其中包含了Apache檔案上傳元件中的各個API類的幫助文件,從這個文件中可以瞭解到各個API類的使用幫助資訊。開啟檔案上傳元件API幫助文件中的index.html頁面,在左側分欄視窗頁面中列出了檔案上傳元件中的各個API類的名稱,在右側分欄視窗頁面的底部列出了一段示例程式碼,如圖1.2所示。

圖1.2

讀者不需要逐個去閱讀圖1.2中列出的各個API類的幫助文件,而應該以圖1.2中的示例程式碼為線索,以其中所使用到的類為入口點,按圖索驥地進行閱讀,對於示例程式碼中呼叫到的各個API類的方法則應重點掌握。



1. DiskFileUpload類

DiskFileUpload類是Apache檔案上傳元件的核心類,應用程式開發人員通過這個類來與Apache檔案上傳元件進行互動。但現在Apache建議使用ServletFileUpload類,兩個類的方法類似。下面介紹DiskFileUpload類中的幾個常用的重要方法。

1.1.setSizeMax方法

setSizeMax方法用於設定請求訊息實體內容的最大允許大小,以防止客戶端故意通過上傳特大的檔案來塞滿伺服器端的儲存空間,單位為位元組。其完整語法定義如下:

     public void setSizeMax(long sizeMax)

如果請求訊息中的實體內容的大小超過了setSizeMax方法的設定值,該方法將會丟擲FileUploadException異常。

1.2.setSizeThreshold方法

Apache檔案上傳元件在解析和處理上傳資料中的每個欄位內容時,需要臨時儲存解析出的資料。因為Java虛擬機器預設可以使用的記憶體空間是有限的(筆者測試不大於100M),超出限制時將會發生“java.lang.OutOfMemoryError”錯誤,如果上傳的檔案很大,例如上傳800M的檔案,在記憶體中將無法儲存該檔案內容,Apache檔案上傳元件將用臨時檔案來儲存這些資料;但如果上傳的檔案很小,例如上傳600個位元組的檔案,顯然將其直接儲存在記憶體中更加有效。setSizeThreshold方法用於設定是否使用臨時檔案儲存解析出的資料的那個臨界值,該方法傳入的引數的單位是位元組。其完整語法定義如下:

public void setSizeThreshold(int sizeThreshold)

1.3. setRepositoryPath方法

setRepositoryPath方法用於設定setSizeThreshold方法中提到的臨時檔案的存放目錄,這裡要求使用絕對路徑。其完整語法定義如下:

public void setRepositoryPath(String repositoryPath)

如果不設定存放路徑,那麼臨時檔案將被儲存在"java.io.tmpdir"這個JVM環境屬性所指定的目錄中,tomcat 5.5.9將這個屬性設定為了“<tomcat安裝目錄>/temp/”目錄。

1.4. parseRequest方法

parseRequest 方法是DiskFileUpload類的重要方法,它是對HTTP請求訊息進行解析的入口方法,如果請求訊息中的實體內容的型別不是“multipart/form-data”,該方法將丟擲FileUploadException異常。parseRequest 方法解析出FORM表單中的每個欄位的資料,並將它們分別包裝成獨立的FileItem物件,然後將這些FileItem物件加入進一個List型別的集合物件中返回。parseRequest 方法的完整語法定義如下:

public List parseRequest(HttpServletRequest req)

parseRequest 方法還有一個過載方法,該方法集中處理上述所有方法的功能,其完整語法定義如下:

parseRequest(HttpServletRequest req,int sizeThreshold,long sizeMax,

             String path)

這兩個parseRequest方法都會丟擲FileUploadException異常。

1.5. isMultipartContent方法

isMultipartContent方法方法用於判斷請求訊息中的內容是否是“multipart/form-data”型別,是則返回true,否則返回false。isMultipartContent方法是一個靜態方法,不用建立DiskFileUpload類的例項物件即可被呼叫,其完整語法定義如下:

public static final boolean isMultipartContent(HttpServletRequest req)

1.6. setHeaderEncoding方法

由於瀏覽器在提交FORM表單時,會將普通表單中填寫的文字內容傳遞給伺服器,對於檔案上傳欄位,除了傳遞原始的檔案內容外,還要傳遞其檔案路徑名等資訊,如後面的圖1.3所示。不管FORM表單採用的是“application/x-www-form-urlencoded”編碼,還是“multipart/form-data”編碼,它們僅僅是將各個FORM表單欄位元素內容組織到一起的一種格式,而這些內容又是由某種字符集編碼來表示的。關於瀏覽器採用何種字符集來編碼FORM表單欄位中的內容,請參看筆者編著的《深入體驗java Web開發內幕——核心基礎》一書中的第6.9.2的講解,“multipart/form-data”型別的表單為表單欄位內容選擇字符集編碼的原理和方式與“application/x-www-form-urlencoded”型別的表單是相同的。FORM表單中填寫的文字內容和檔案上傳欄位中的檔案路徑名在記憶體中就是它們的某種字符集編碼的位元組陣列形式,Apache檔案上傳元件在讀取這些內容時,必須知道它們所採用的字符集編碼,才能將它們轉換成正確的字元文字返回。

對於瀏覽器上傳給WEB伺服器的各個表單欄位的描述頭內容,Apache檔案上傳元件都需要將它們轉換成字串形式返回,setHeaderEncoding 方法用於設定轉換時所使用的字符集編碼,其原理與筆者編著的《深入體驗java Web開發內幕——核心基礎》一書中的第6.9.4節講解的ServletRequest.setCharacterEncoding方法相同。setHeaderEncoding 方法的完整語法定義如下:

public void setHeaderEncoding(String encoding)

其中,encoding引數用於指定將各個表單欄位的描述頭內容轉換成字串時所使用的字符集編碼。

注意:如果讀者在使用Apache檔案上傳元件時遇到了中文字元的亂碼問題,一般都是沒有正確呼叫setHeaderEncoding方法的原因。



2. FileItem類

FileItem類用來封裝單個表單欄位元素的資料,一個表單欄位元素對應一個FileItem物件,通過呼叫FileItem物件的方法可以獲得相關表單欄位元素的資料。FileItem是一個介面,在應用程式中使用的實際上是該介面一個實現類,該實現類的名稱並不重要,程式可以採用FileItem介面型別來對它進行引用和訪問,為了便於講解,這裡將FileItem實現類稱之為FileItem類。FileItem類還實現了Serializable介面,以支援序列化操作。

對於“multipart/form-data”型別的FORM表單,瀏覽器上傳的實體內容中的每個表單欄位元素的資料之間用欄位分隔界線進行分割,兩個分隔界線間的內容稱為一個分割槽,每個分割槽中的內容可以被看作兩部分,一部分是對錶單欄位元素進行描述的描述頭,另外一部是表單欄位元素的主體內容,如圖1.3所示。

圖 1.3

主體部分有兩種可能性,要麼是使用者填寫的表單內容,要麼是檔案內容。FileItem類物件實際上就是對圖1.3中的一個分割槽的資料進行封裝的物件,它內部用了兩個成員變數來分別儲存描述頭和主體內容,其中儲存主體內容的變數是一個輸出流型別的物件。當主體內容的大小小於DiskFileUpload.setSizeThreshold方法設定的臨界值大小時,這個流物件關聯到一片記憶體,主體內容將會被儲存在記憶體中。當主體內容的資料超過DiskFileUpload.setSizeThreshold方法設定的臨界值大小時,這個流物件關聯到硬碟上的一個臨時檔案,主體內容將被儲存到該臨時檔案中。臨時檔案的儲存目錄由DiskFileUpload.setRepositoryPath方法設定,臨時檔名的格式為“upload_00000005(八位或八位以上的數字).tmp”這種形式,FileItem類內部提供了維護臨時檔名中的數值不重複的機制,以保證了臨時檔名的唯一性。當應用程式將主體內容儲存到一個指定的檔案中時,或者在FileItem物件被垃圾回收器回收時,或者Java虛擬機器結束時,Apache檔案上傳元件都會嘗試刪除臨時檔案,以儘量保證臨時檔案能被及時清除。

下面介紹FileItem類中的幾個常用的方法:

2.1. isFormField方法

isFormField方法用於判斷FileItem類物件封裝的資料是否屬於一個普通表單欄位,還是屬於一個檔案表單欄位,如果是普通表單欄位則返回true,否則返回false。該方法的完整語法定義如下:

public boolean isFormField()

2.2. getName方法

getName方法用於獲得檔案上傳欄位中的檔名,對於圖1.3中的第三個分割槽所示的描述頭,getName方法返回的結果為字串“C:\bg.gif”。如果FileItem類物件對應的是普通表單欄位,getName方法將返回null。即使使用者沒有通過網頁表單中的檔案欄位傳遞任何檔案,但只要設定了檔案表單欄位的name屬性,瀏覽器也會將檔案欄位的資訊傳遞給伺服器,只是檔名和檔案內容部分都為空,但這個表單欄位仍然對應一個FileItem物件,此時,getName方法返回結果為空字串"",讀者在呼叫Apache檔案上傳元件時要注意考慮這個情況。getName方法的完整語法定義如下:

public String getName()

注意:如果使用者使用Windows系統上傳檔案,瀏覽器將傳遞該檔案的完整路徑,如果使用者使用Linux或者Unix系統上傳檔案,瀏覽器將只傳遞該檔案的名稱部分。

2.3.getFieldName方法

getFieldName方法用於返回表單欄位元素的name屬性值,也就是返回圖1.3中的各個描述頭部分中的name屬性值,例如“name=p1”中的“p1”。getFieldName方法的完整語法定義如下:

public String getFieldName()

2.4. write方法

write方法用於將FileItem物件中儲存的主體內容儲存到某個指定的檔案中。如果FileItem物件中的主體內容是儲存在某個臨時檔案中,該方法順利完成後,臨時檔案有可能會被清除。該方法也可將普通表單欄位內容寫入到一個檔案中,但它主要用途是將上傳的檔案內容儲存在本地檔案系統中。其完整語法定義如下:

public void write(File file)

2.5.getString方法

    getString方法用於將FileItem物件中儲存的主體內容作為一個字串返回,它有兩個過載的定義形式:

public java.lang.String getString()

public java.lang.String getString(java.lang.String encoding)

     throws java.io.UnsupportedEncodingException

前者使用預設的字符集編碼將主體內容轉換成字串,後者使用引數指定的字符集編碼將主體內容轉換成字串。如果在讀取普通表單欄位元素的內容時出現了中文亂碼現象,請呼叫第二個getString方法,併為之傳遞正確的字符集編碼名稱。

2.6. getContentType方法

getContentType 方法用於獲得上傳檔案的型別,對於圖1.3中的第三個分割槽所示的描述頭,getContentType方法返回的結果為字串“image/gif”,即“Content-Type”欄位的值部分。如果FileItem類物件對應的是普通表單欄位,該方法將返回null。getContentType 方法的完整語法定義如下:

public String getContentType()

2.7. isInMemory方法

isInMemory方法用來判斷FileItem類物件封裝的主體內容是儲存在記憶體中,還是儲存在臨時檔案中,如果儲存在記憶體中則返回true,否則返回false。其完整語法定義如下:

public boolean isInMemory()

2.8. delete方法

delete方法用來清空FileItem類物件中存放的主體內容,如果主體內容被儲存在臨時檔案中,delete方法將刪除該臨時檔案。儘管Apache元件使用了多種方式來儘量及時清理臨時檔案,但系統出現異常時,仍有可能造成有的臨時檔案被永久儲存在了硬碟中。在有些情況下,可以呼叫這個方法來及時刪除臨時檔案。其完整語法定義如下:

public void delete()



3. FileUploadException類

在檔案上傳過程中,可能發生各種各樣的異常,例如網路中斷、資料丟失等等。為了對不同異常進行合適的處理,Apache檔案上傳元件還開發了四個異常類,其中FileUploadException是其他異常類的父類,其他幾個類只是被間接呼叫的底層類,對於Apache元件呼叫人員來說,只需對FileUploadException異常類進行捕獲和處理即可



4. ServletRequestContext

ServletRequestContext類提供訪問request的方法。實現RequestContext介面。