?
This document uses PHP Chinese website manual Release
Spring Portlet MVC和Web MVC一樣,也支持multipart來處理portlet中的文件上傳。
插件式的PortletMultipartResolver
提供了對multipart的支持,
它在org.springframework.web.portlet.multipart
包里。
Spring提供了PortletMultipartResolver
來和
Commons FileUpload
一起使用。余下的篇幅會介紹文件上傳的支持。
缺省情況下,Spring Portlet是不會處理multipart的,如果開發(fā)人員需要處理multipart,
就必須在web應用的context里添加一個multipart解析器,然后,
DispatcherPortlet
會在每個請求里檢查是否帶有multipart。
如果沒找到,請求會繼續(xù),如果找到了multipart,在context中聲明的
PortletMultipartResolver
會被調用。接著,
在請求里的multipart屬性會和其它的屬性一樣被處理。
任何已配置的PortletMultipartResolver
bean必須
使用下列id(或名稱):"PortletMultipartResolver
" 。
如果你已經(jīng)定義了你的PortletMultipartResolver
為任何其他名稱,
哪么DispatcherPortlet
將找不到你的
PortletMultipartResolver
,并因此沒有multipart的支持。
下面的例子介紹了
CommonsPortletMultipartResolver
的使用:
<bean id="portletMultipartResolver"
class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver">
<!-- 一個屬性;以byte為單位的最大文件長度 -->
<property name="maxUploadSize" value="100000"/>
</bean>
當然為了使multipart解析器能夠工作,必須把合適的jar放到類路徑里。對于
CommonsMultipartResolver
來說,需要
commons-fileupload.jar
。注意,必須使用至少1.1
版本的Commons FileUpload,因為以前的版本不支持JSR-168應用。
現(xiàn)在你已經(jīng)看到如何設置Portlet MVC來處理multipart請求,接下來我們
討論它的使用。當DispatcherPortlet
檢測到
multipart時,它會激活在context里聲明的解析器,并把請求交給它。然后解析器
把當前的ActionRequest
放到支持文件上傳的
MultipartActionRequest
中。通過
MultipartActionRequest
,可以得到
請求包含的multipart信息,并且在控制器里訪問multipart文件。
注意,不能從RenderRequest
接收到multipart
文件,而只能從ActionRequest
里。
在 PortletMultipartResolver
處理完后,
請求會繼續(xù)被處理。你需要創(chuàng)建一個帶有上傳字段的表單來使用它(見下面),Spring會
把文件綁定在你的表單上(支持對象)。為了讓用戶上傳文件,必須創(chuàng)建一個(JSP/HTML)的表單:
<h1>Please upload a file</h1> <form method="post" action="<portlet:actionURL/>" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit"/> </form>
如你所見,我們在bean的屬性后面創(chuàng)建名為“File”的字段
用來容納 byte[]
。加上了編碼屬性( enctype="multipart/form-data"
),
讓瀏覽器知道怎樣來編碼multipart字段(切記?。?/p>
和其它那些不會自動轉化為字符串或原始類型的屬性一樣,為了把二進制數(shù)據(jù)放到對象
里,必須注冊一個使用 PortletRequestDataBinder
的自定義的編輯器。現(xiàn)成有好幾個編輯器可以用來處理文件并把結果放到對象上。
StringMultipartFileEditor
能夠把文件轉換成字符串
(使用用戶定義的字符集),ByteArrayMultipartFileEditor
能夠把文件轉換成字節(jié)數(shù)據(jù)。他們的功能和
CustomDateEditor
一樣。
所以,為了能夠使用表單來上傳文件,需要聲明解析器,映射到處理這個bean的控制器的映射以及控制器。
<bean id="portletMultipartResolver" class="org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver"/> <bean id="portletModeHandlerMapping" class="org.springframework.web.portlet.handler.PortletModeHandlerMapping"> <property name="portletModeMap"> <map> <entry key="view" value-ref="fileUploadController"/> </map> </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>
接著,創(chuàng)建控制器以及實際容納這個文件屬性的類。
public class FileUploadController extends SimpleFormController { public void onSubmitAction( ActionRequest request, ActionResponse response, Object command, BindException errors) throws Exception { // 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 } // do something with the file here } protected void initBinder( PortletRequest request, PortletRequestDataBinder binder) throws Exception { // 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 } } public class FileUploadBean { private byte[] file; public void setFile(byte[] file) { this.file = file; } public byte[] getFile() { return file; } }
如你所見,FileUploadBean
有一個類型是
byte[]
的屬性來容納文件。控制器注冊了一個自定義編輯器來
讓Spring知道如何把解析器發(fā)現(xiàn)的multipart轉換成指定的屬性。在這個例子里,
沒有對bean的 byte[]
屬性進行任何操作,但實際上,你可以做任
何操作(把它存到數(shù)據(jù)庫里,把它電郵出去,或其它)
下面是一個例子,文件直接綁定在的一個(表單支持)對象上的字符串類型屬性上面:
public class FileUploadController extends SimpleFormController { public void onSubmitAction( ActionRequest request, ActionResponse response, Object command, BindException errors) throws Exception { // 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 } // do something with the file here } protected void initBinder( PortletRequest request, PortletRequestDataBinder binder) throws Exception { // 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 objects and convert } } public class FileUploadBean { private String file; public void setFile(String file) { this.file = file; } public String getFile() { return file; } }
當然,最后的例子在上傳文本文件時才有(邏輯上的)意義(在上傳圖像文件時,它不會工作)。
第三個(也是最后一個)選項是,什么情況下需要直接綁定在(表單支持)對象的
MultipartFile
屬性上。在以下的情況,不需要注冊自定義的屬性編輯器,因為不需要類型轉換。
public class FileUploadController extends SimpleFormController { public void onSubmitAction( ActionRequest request, ActionResponse response, Object command, BindException errors) throws Exception { // 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 } // do something with the file here } } public class FileUploadBean { private MultipartFile file; public void setFile(MultipartFile file) { this.file = file; } public MultipartFile getFile() { return file; } }