1. 程式人生 > >SpringMVC(14) - spring的多部件(檔案上傳)支援

SpringMVC(14) - spring的多部件(檔案上傳)支援

參考:https://docs.spring.io/spring/docs/4.3.20.RELEASE/spring-framework-reference/htmlsingle/#mvc-multipart

 

1. 簡介
Spring的內建多部件支援處理Web應用程式中的檔案上傳。可以使用org.springframework.web.multipart包中定義的可插入的MultipartResolver物件啟用此多部件支援。 Spring提供了一個用於Commons FileUpload的MultipartResolver實現,另一個用於Servlet 3.0多部件請求解析。

預設情況下,Spring不進行多部件處理,因為一些開發人員希望自己處理多部件。可以通過向Web應用程式的上下文新增多部件解析器來啟用Spring多部件處理。檢查每個請求以檢視它是否包含多部件。如果未找到任何多部件,則請求將按預期繼續執行。如果在請求中找到了多部件,則將會使用已在上下文中宣告的MultipartResolver。之後,請求中的multipart屬性將被視為任意其他屬性。

 

2. 將MultipartResolver與Commons FileUpload一起使用
以下示例顯示如何使用CommonsMultipartResolver:

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <!-- 最大檔案大小,單位位元組 -->
    <property name="maxUploadSize" value="100000"/>
</bean>

當然,還需要在類路徑中放置適當的jar,以使多部件解析器工作。對於CommonsMultipartResolver,需要使用commons-fileupload.jar。

當Spring DispatcherServlet檢測到多部件請求時,它會啟用已在上下文中宣告的解析器並移交請求。解析器然後將當前的HttpServletRequest包裝到支援多部分檔案上傳的MultipartHttpServletRequest中。使用MultipartHttpServletRequest,可以獲取有關此請求包含的多部件的資訊,並實際訪問控制器中的多部件檔案。

 

3. 將MultipartResolver與Servlet 3.0一起使用
為了使用基於Servlet 3.0的多部件解析,需要在web.xml中使用“multipart-config”部分標記DispatcherServlet,或在Servlet中通過程式碼方式使用javax.servlet.MultipartConfigElement註冊,或者在自定義Servlet的類上有一個javax.servlet.annotation.MultipartConfig註解。由於Servlet 3.0不允許從MultipartResolver完成這些設定,因此需要在該Servlet註冊級別應用配置設定(如最大大小或儲存位置)。

一旦以上述方式之一啟用了Servlet 3.0多部件解析,就可以將StandardServletMultipartResolver新增到Spring配置中:

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver">
</bean>

 

4. 處理表單中的檔案上傳
MultipartResolver完成其任務後,將像處理其他任何請求一樣處理該請求。 首先,建立一個帶有檔案輸入的表單,允許使用者上傳表單。 encoding屬性(enctype="multipart/form-data")讓瀏覽器知道如何將表單編碼為multipart請求:

<html>
    <head>
        <title>Upload a file please</title>
    </head>
    <body>
        <h1>Please upload a file</h1>
        <form method="post" action="/form" enctype="multipart/form-data">
            <input type="text" name="name"/>
            <input type="file" name="file"/>
            <input type="submit"/>
        </form>
    </body>
</html>

下一步是建立一個處理檔案上傳的控制器。 這個控制器非常類似於普通的帶註解的@Controller,除了我們在方法引數中使用MultipartHttpServletRequest或MultipartFile:

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") MultipartFile file) {

        if (!file.isEmpty()) {
            byte[] bytes = file.getBytes();
            // 將bytes儲存在某處,如資料庫,本地檔案
            return "redirect:uploadSuccess";
        }

        return "redirect:uploadFailure";
    }

}

注意@RequestParam方法引數如何對映到表單中宣告的輸入元素。 在此示例中,byte[]沒有任何操作,但實際上可以將其儲存在資料庫中,將其儲存在檔案系統中,等等。

使用Servlet 3.0多部件解析時,還可以使用javax.servlet.http.Part作為方法引數:

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(@RequestParam("name") String name, @RequestParam("file") Part file) {

        InputStream inputStream = file.getInputStream();
        // store bytes from uploaded file somewhere

        return "redirect:uploadSuccess";
    }

}

 

5. 處理程式客戶端的檔案上傳請求
還可以在RESTful服務方案中從非瀏覽器客戶端提交多部件請求。所有上述示例和配置也適用於此處。但是,與通常提交檔案和簡單表單欄位的瀏覽器不同,程式設計客戶端還可以傳送特定內容型別的更復雜資料 --- 例如,帶有檔案的多部件請求和帶有JSON格式資料的第二部分:

POST /someUrl
Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit
{
    "name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...

可以使用 @RequestParam("meta-data") String metadata 控制器方法引數訪問名為“meta-data”的部分。但是,可能更願意接受從請求部分體中的JSON格式資料初始化強型別物件,這與@RequestBody藉助一個HttpMessageConverter將非多部件請求體轉換為目標物件的方式非常相似。

為此,可以使用@RequestPart註解而不是@RequestParam註解。它允許通過HttpMessageConverter傳遞特定多部件的內容,同時考慮到multipart的'Content-Type'頭:

@PostMapping("/someUrl")
public String onSubmit(@RequestPart("meta-data") MetaData metadata, @RequestPart("file-data") MultipartFile file) {
    // ...
}

請注意如何使用@RequestParam或@RequestPart可以互換地訪問MultipartFile方法引數。 但是,本案例中的@RequestPart("meta-data") MetaData 方法引數基於其“Content-Type”頭讀取為JSON內容,並在MappingJackson2HttpMessageConverter的幫助下進行轉換。