?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
Spring支持web應(yīng)用中的分段文件上傳。這種支持是由即插即用的MultipartResolver
來實現(xiàn)。
這些解析器都定義在org.springframework.web.multipart
包里。
Spring提供了現(xiàn)成的MultipartResolver
可以支持Commons FileUpload(http://jakarta.apache.org/commons/fileupload)和
COS FileUpload(http://www.servlets.com/cos)。
本章后面的部分描述了Spring是如何支持文件上傳的。
通常情況下,Spring是不處理文件上傳的,因為一些開發(fā)者想要自己處理它們。
如果想使用Spring的這個功能,需要在web應(yīng)用的上下文中添加分段文件解析器。
這樣,每個請求就會被檢查是否包含文件上傳。如果沒有,這個請求就被正常的處理,
否則,應(yīng)用上下文中已經(jīng)定義的MultipartResolver
就會被調(diào)用。
然后,請求中的文件屬性就會像其它屬性一樣被處理。
下面的例子說明了如何使用CommonsMultipartResolver
:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
下面這個例子使用CosMultipartResolver
:
<bean id="multipartResolver" class="org.springframework.web.multipart.cos.CosMultipartResolver">
<!-- one of the properties available; the maximum file size in bytes -->
<property name="maxUploadSize" value="100000"/>
</bean>
當(dāng)然,需要在classpath中為分段文件解析器提供正確的jar文件。
如果是CommonsMultipartResolver
,
需要使用commons-fileupload.jar
,如果是CosMultipartResolver
,
則使用cos.jar
。
已經(jīng)看到如何設(shè)置Spring處理文件上傳請求,接下來我們看看如何使用它。
當(dāng)Spring的DispatcherServlet
發(fā)現(xiàn)文件上傳請求時,它會激活定義在上下文中的解析器來處理請求。
這個解析器隨后是將當(dāng)前的HttpServletRequest
封裝成MultipartHttpServletRequest
,后者支持分段文件上傳。
使用MultipartHttpServletRequest
,可以獲取請求所包含的上傳信息,甚至可以在控制器中獲取分段文件的內(nèi)容。
在MultipartResolver
完成分段文件解析后,這個請求就會和其它請求一樣被處理。
為了使用文件上傳,你需要創(chuàng)建一個帶文件上傳域(upload field)的(HTML)表單,讓Spring將文件綁定到你的表單上(如下所示):
<html> <head> <title>Upload a file please</title> </head> <body> <h1>Please upload a file</h1> <form method="post" action="upload.form" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit"/> </form> </body> </html>
可以看到,在上面這個表單里有一個input元素,這個元素的名字(“file”)和服務(wù)器端處理這個表單的bean(在下面將會提到)中類型為byte[]
的屬性名相同。
在這個表單里我們也聲明了編碼參數(shù)(enctype="multipart/form-data"
)以便讓瀏覽器知道如何對這個文件上傳表單進行編碼(千萬不要忘記這么做?。?。
和其它不能自動轉(zhuǎn)為字符串類型或者基本類型(primitive type)的屬性一樣,為了將上傳的二進制數(shù)據(jù)存成bean的屬性,
必須通過ServletRequestDatabinder
注冊一個屬性編輯器。
Spring中內(nèi)置了幾個這樣的編輯器,它們可以處理文件,然后將結(jié)果存成bean的屬性。
比如,StringMultipartEditor
可以將文件轉(zhuǎn)換成一個字符串(使用用戶聲明的字符集)。
ByteArrayMultipartEditor
可以以將文件轉(zhuǎn)換為byte數(shù)組。
他們的功能和CustomDateEditor
相似。
總而言之,為了使用(HTML)表單上傳文件,需要聲明一個解析器,一個控制器,再將文件上傳的URL映射到控制器來處理這個請求。 下面是這幾個bean的聲明。
<beans>
<!-- lets use the Commons-based implementation of the MultipartResolver interface -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/upload.form=fileUploadController
</value>
</property>
</bean>
<bean id="fileUploadController" class="examples.FileUploadController">
<property name="commandClass" value="examples.FileUploadBean"/>
<property name="formView" value="fileuploadform"/>
<property name="successView" value="confirmation"/>
</bean>
</beans>
下面的代碼定義了控制器和用來存放文件的那個bean。
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there byte[] file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws ServletException { // to actually be able to convert Multipart instance to byte[] // we have to register a custom editor binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor()); // now Spring knows how to handle multipart object and convert them } } public class FileUploadBean { private byte[] file; public void setFile(byte[] file) { this.file = file; } public byte[] getFile() { return file; } }
FileUploadBean
用一個byte[]
類型的屬性來存放文件。
前面已經(jīng)提到過,通??刂破髯砸粋€自定義的編輯器以便讓Spring知道如何將解析器找到的multipart對象轉(zhuǎn)換成bean指定的屬性,
但在上面的例子中,我們除了將byte數(shù)組記錄下來以外,沒有對這個文件進行任何操作,
在實際的應(yīng)用程序中你可以做任何你想做的事情(比如將文件存儲在數(shù)據(jù)庫中,通過電子郵件發(fā)送給某人等等)。
在下面這個例子里,上傳的文件被綁定為(表單支持的)對象(form backing)的String屬性:
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there String file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws ServletException { // to actually be able to convert Multipart instance to a String // we have to register a custom editor binder.registerCustomEditor(String.class, new StringMultipartFileEditor()); // now Spring knows how to handle multipart object and convert them } } public class FileUploadBean { private String file; public void setFile(String file) { this.file = file; } public String getFile() { return file; } }
如果僅僅是處理一個文本文件的上傳,上面這個例子的做法還是合理的(但如果上傳的是一張圖片, 那段代碼就會出問題)。
最后的解決方法就是將表單支持對象(form backing)的相關(guān)屬性設(shè)成MultipartFile
類型。
這樣的話,沒有類型轉(zhuǎn)換的需要,我們也就不需要聲明任何屬性編輯器(PropertyEditor
)。
public class FileUploadController extends SimpleFormController { protected ModelAndView onSubmit( HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws ServletException, IOException { // cast the bean FileUploadBean bean = (FileUploadBean) command; let's see if there's content there MultipartFile file = bean.getFile(); if (file == null) { // hmm, that's strange, the user did not upload anything } // well, let's do nothing with the bean for now and return return super.onSubmit(request, response, command, errors); } } public class FileUploadBean { private MultipartFile file; public void setFile(MultipartFile file) { this.file = file; } public MultipartFile getFile() { return file; } }