©
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
Spring Portlet MVC和Web MVC一样,也支持multipart来处理portlet中的文件上传。
插件式的PortletMultipartResolver
提供了对multipart的支持,
它在org.springframework.web.portlet.multipart
包里。
Spring提供了PortletMultipartResolver
来和
Commons FileUpload
一起使用。余下的篇幅会介绍文件上传的支持。
缺省情况下,Spring Portlet是不会处理multipart的,如果开发人员需要处理multipart,
就必须在web应用的context里添加一个multipart解析器,然后,
DispatcherPortlet
会在每个请求里检查是否带有multipart。
如果没找到,请求会继续,如果找到了multipart,在context中声明的
PortletMultipartResolver
会被调用。接着,
在请求里的multipart属性会和其它的属性一样被处理。
任何已配置的PortletMultipartResolver
bean必须
使用下列id(或名称):"PortletMultipartResolver
" 。
如果你已经定义了你的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应用。
现在你已经看到如何设置Portlet MVC来处理multipart请求,接下来我们
讨论它的使用。当DispatcherPortlet
检测到
multipart时,它会激活在context里声明的解析器,并把请求交给它。然后解析器
把当前的ActionRequest
放到支持文件上传的
MultipartActionRequest
中。通过
MultipartActionRequest
,可以得到
请求包含的multipart信息,并且在控制器里访问multipart文件。
注意,不能从RenderRequest
接收到multipart
文件,而只能从ActionRequest
里。
在 PortletMultipartResolver
处理完后,
请求会继续被处理。你需要创建一个带有上传字段的表单来使用它(见下面),Spring会
把文件绑定在你的表单上(支持对象)。为了让用户上传文件,必须创建一个(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的属性后面创建名为“File”的字段
用来容纳 byte[]
。加上了编码属性( enctype="multipart/form-data"
),
让浏览器知道怎样来编码multipart字段(切记!)。
和其它那些不会自动转化为字符串或原始类型的属性一样,为了把二进制数据放到对象
里,必须注册一个使用 PortletRequestDataBinder
的自定义的编辑器。现成有好几个编辑器可以用来处理文件并把结果放到对象上。
StringMultipartFileEditor
能够把文件转换成字符串
(使用用户定义的字符集),ByteArrayMultipartFileEditor
能够把文件转换成字节数据。他们的功能和
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>
接着,创建控制器以及实际容纳这个文件属性的类。
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知道如何把解析器发现的multipart转换成指定的属性。在这个例子里,
没有对bean的 byte[]
属性进行任何操作,但实际上,你可以做任
何操作(把它存到数据库里,把它电邮出去,或其它)
下面是一个例子,文件直接绑定在的一个(表单支持)对象上的字符串类型属性上面:
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; } }