最近家里的网出现了莫名其妙的问题,连不上码云了,所以把示例迁到了 github 上。本示例见这个项目的 master 分支的 ZestMultipartController.java。
Spring 的内置 multipart 支持用于处理 Web 应用程序中的文件上传。你可以通过使用插件化的MultipartResolver
对象来启用 multipart 支持,它定义在包org.springframework.web.multipart
中。Spring 提供了一个MultipartResolver
的实现,使用了 Apache 的 Commons FileUpload 和一些其他的东西,用于对 Servlet 3.0 的 multipart 请求的解析。
默认地,Spring 不进行 multipart 处理,因为很多开发者想要自己处理。你可以通过在 Web 应用程序上下文中添加一个 multipart 解析器来启用 Spring 的 multipart 处理。每一个请求都要被检查,看看是否包含一个 multipart。如果没有发现 multipart,请求就正常继续啦;如果有的话,你在上下文中声明的MultipartResolver
就会开始工作啦。之后嘞,你就可以像访问其他请求属性那样访问 multipart 属性啦。
和 Commons FileUpload 一起使用MultipartResolver
下面的例子展示了怎样使用CommonsMultipartResolver
,快来看看吧:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 最大上传大小,单位:字节(byte) -->
<property name="maxUploadSize" value="100000"/>
<!-- 你也可以在这里提供其他的属性 -->
</bean>
当然啦,你也需要在类路径下放上合适的 Jar 文件来保证 multipart 解析器工作。对于上面的例子嘞,你需要使用 commons-fileupload.jar。
当 Spring 的DispatcherServlet
检测到一个 multi-part 请求时,它会激活你声明好的解析器,然后把这个解析器转交给请求。解析器会把当前的HttpServletRequest
扭曲(wrap?)为 一个支持 multipart 文件上传的MultipartHttpServletRequest
。使用这个MultipartHttpServletRequest
,你就可以获取这个请求中的 multipart 的信息了, 同时也可以在你的控制器中访问这些 multipart 文件。
在表单中处理文件上传
在MultipartResolver
完成自己的工作之后,你就可以像处理其他请求那样处理当前请求了。首先,创建一个带有<input type="file"/>
的表单,这样用户就可以通过这个表单上传文件了。为表单添加编码属性(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>
下一步是创建一个控制器来处理文件上传。这个控制器和之前那种正常的控制器很像,不过我们在方法参数上使用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();
// store the bytes somewhere
return "redirect:uploadSuccess";
}
return "redirect:uploadFailure";
}
}
注意@RequestParam
方法参数是怎样映射到表单的 input 元素中的。在这个例子中,并没有使用byte[]
做任何事,但是在实践中,你可以把它保存到数据库中,也可以保存到文件系统上等,随你咯。
上传文件之后不进行页面跳转
有时,想在上传完页面之后,页面还保持在这里,不去跳转。这时,可以借助<iframe/>
。把上面的表单改成下面那样就行啦:
···
<form method="post" action="/form" enctype="multipart/form-data" target="myframe">
<input type="text" name="name"/>
<input type="file" name="file"/>
<input type="submit" value="上传"/>
</form>
<iframe name="myframe"></iframe>
···