上傳功能是一個web應用很常用的一個功能,比如在一些社交網站上傳些圖檔、視訊等。本篇文章主要研究了spring mvc是如何實作檔案上傳功能的,在具體講解spring mvc如何實作處理檔案上傳之前,必須弄明白與檔案上傳相關的multipart請求。
我們傳統的表單送出的一般都是文本類型的資料,比如我們的系統資料庫單,當送出表單時,表單中的“屬性-值”對會被拼接成一個字元串:
這種處理方式很簡單也很有效,但是對于圖檔、視訊等二進制資料就不能這麼處理了,這裡就要用到multipart表單了。multipart表單和上面介紹的普通表單不同,它會把表單分割成塊,表單中的每個字段對應一個塊,每個塊都有自己的資料類型。也就是說,對于上傳字段對應的塊,它的資料類型就可以是二進制了:
在上面這個請求就是mutipart 請求,最後一個字段<code>profilepicture</code>有自己的<code>content-type</code>,值是<code>image/jpeg</code>,而其它字段都是簡單的文本類型。
雖然mutipart請求看起來比較複雜,但是在spring mvc中處理起來是非常簡單的。在寫我們處理上傳檔案的controller之前,我們得先配置一個mutipart resolver來告訴<code>dispatchservlet</code>如何解析一個mutipart 請求。
實作檔案上傳,其實就是解析一個mutipart請求。dispatchservlet自己并不負責去解析mutipart 請求,而是委托一個實作了<code>multipartresolver</code>接口的類來解析mutipart請求。在spring3.1之後spring提供了兩個現成的multipartresolver接口的實作類:
<code>commonmutipartresolver</code>:通過利用<code>jakarta commons fileupload</code>來解析mutipart 請求
<code>standardservletmutipartresolver</code>:依賴<code>servlet3.0</code>來解析mutipart請求
是以要實作檔案上傳功能,隻需在我們的項目中配置好這兩個bean中的任何一個即可。其實這兩個都很好用,如果我們部署的容器支援servlet3.0,我們完全可以使用<code>standardservletmutipartresolver</code>。但是如果我們的應用部署的容器不支援servlet3.0或者用到的spring版本是3.1以前的,那麼我們就需要用到<code>commonmutipartresolver</code>了。下面就具體介紹一下兩種bean的配置,當然也是實作檔案上傳的兩種配置。
方式一: 通過standardservletmutipartresolver解析mutipart 請求
1.配置multipartresolver的bean
2.配置mutipartresolver相關屬性
<code>standardservletmutipartresolver</code>依賴于servlet3.0,是以要想使用<code>standardservletmutipartresolver</code>,我們還必須在dispatchservlet配置裡面 注冊一個 <code>multipartconfigelement</code>元素,具體配置方式如下:
<code>mutipart-config</code>裡面有三個配置項:
location:上傳檔案用到的臨時檔案夾,是一個絕對路徑,需要注意,這個屬性是必填的
max-file-size:上傳檔案的最大值,機關是byte,預設沒有限制
max-request-size:整個mutipart請求的最大值,機關是byte,預設沒有限制
方式二:通過commonmutipartresolver 解析mutipart 請求
當然,如果我們部署的容器不是servlet3.0,我們還可以使用<code>commonmutipartresolver</code>,不過這個需要依賴apache的<code>commons-fileupload</code>第三方類庫。
1.配置第三方依賴
2.配置multipartresolver的bean
使用<code>commonmutipartresolver</code>不需要在servlet中配置<code>multipartconfigelement</code>元素,上傳檔案的location屬性也是可選的。
大家可能有個小疑問,上面兩種方式都配置了一個id=”multipartresolver”的bean,那麼dispatchservlet是如何找到這個bean的呢?我們可以看一下dispatchservlet的源碼,裡面有這麼一個方法:
這個方法會預設從spring的上下文中擷取id為multipartresolver的bean作為它的mutipartresolver。
按照上面的任何一種方式配置好,spring就已經準備好接受mutipart請求了,下面就需要寫一個controller來接收上傳的檔案了,請看代碼:
<code>uploadfilehandler</code>方法中有一個參數file,它的類型是mutipartfile,也就是說spring 會自動把mutipart請求中的二進制檔案轉換成mutipartfile類型的對象,這麼做有什麼好處呢?我們具體看一下mutipartfile這個接口:
我們可以看到mutipartfile接口提供了很多方法,諸如擷取上傳檔案的名稱、内容類型、大小等等,甚至還提供了轉換成file類型檔案的方法。想想如果我們接收到僅僅是一個位元組數組,那用起來該多麼麻煩,感激這個mutipartfile吧。
我們的頁面代碼:
其中隻有一點需要注意,就是表單的<code>enctype</code>屬性,這個屬性值<code>multipart/form-data</code>會告訴浏覽器我們送出的是一個mutipart請求而不是一個普通的form請求。
看一下頁面效果:

運作程式,試着上傳一個檔案吧。