在以前的处理上传文件的时候我都是将文件标签单独置于一个 form 标签中,每次提交表单,先提交文件的表单,然后上传文件成功后返回一个文件的id,再将文件的id绑定到外层的表单上。其实并不需要这么麻烦,文件可以和其他属性通过一次提交全部将数据交给控制器。下面我将实现一个 在一个表单通过一次请求 提交一个实体对象以及文件到控制器,并实现数据的持久化。
1 首先配置是spring支持MultipartFile 文件上传
1.1 在spring配置文件里注册一个解析Multipart请求的bean
//配置bean解析Multipart请求
@Bean
public MultipartResolver multipartResolver(){
return new StandardServletMultipartResolver();
}
1.2.1 如果使用javaConfig配置:在配置DispatcherSevlet的servlet的初始化类(通常为继承了AbstractAnnotationConfigDispatcherServletInitializer或者继承了AbstractDispatcherServletInitializer的子类,请参照我前面的博文 《用java Config代替xml搭建SpringMVC项目》中的第二步创建的类。)中重写
customizeRegistration(ServletRegistration.Dynamic registration)方法,并在这个方法里配置 解析Multipart请求 的相关参数。
//配置bean解析Multipart请求所需要的参数
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration){
//MultipartConfigElement的参数依次为 文件上传临时路径,限制文件的大小,整个请求的数据大小,最大的内存大小
registration.setMultipartConfig(new MultipartConfigElement("/tem/spitr/upload",1024*1024*2,1024*1024*4,0));
}
1.2.2如果是使用xml配置则在传统的创建DispatcherServlet这个servlet的时候添加相应的参数如下
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring-mvc*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<multipart-config>
<location>/temp/spittr/upload</location> <!-- 文件上传临时路径, -->
<max-file-size>1024*1024</max-file-size><!-- 限制文件的大小 -->
<max-request-size>1024*1024*2</max-request-size> <!-- 整个请求的数据大小 -->
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2 新建一个User实体类,其中包含一个personalPicture属性
public class User {
private String name;
private String password;
private int age;
private String email;
private String blogUrl;
private byte[] personPicture;
//省略setter getter
}
3 使用spring form标签创建一个表单
<sf:form method="POST" action="login" commandName="user" enctype="multipart/form-data">
用户名2:<sf:input path="name" />
<sf:errors path="name" /><br/>
密码:<sf:password path="password" />
<sf:errors path="password" /><br/>
年龄:<sf:input path="age" />
<sf:errors path="age" /><br/>
邮箱:<sf:input path="email" type="email"/>
<sf:errors path="email" /><br/>
博客:<sf:input path="blogUrl" />
<sf:errors path="blogUrl" /><br/>
<sf:input path="personPicture" type="file" />
<input type="submit" value="提交">
</sf:form>
4 新建一个控制器以及一个 处理方法来处理表单提交的数据 (下面的参数 pesonPicture需要和表单里面的 标签path 一致 )
@Controller
public class LoginController{
@RequestMapping("login")
public String login(@RequestPart("personPicture") MultipartFile personPicture,
User user,Model model){
System.out.println(personPicture.getName());
System.out.println(personPicture.getSize());
//下面这个方法是MultipartFile接口提供的方法,用于将personPicture文件写入到磁盘
personPicture.transferTo(new File("E:\\eclipseweb\\"+personPicture.getOriginalFilename()));
}
}
当然 上面我们是通过 MultipartFile 这个接口来接收上传的文件的,我们也可以用 byte[] 、javax.servlet.http.Part来接收 personPicture .但是MultipartFile 提供了许多常用的方法使我们很方便地处理文件。下面是MultipartFile 提供的方法。
public interface MultipartFile {
String getName();
//将获取文件原名称
String getOriginalFilename();
String getContentType();
boolean isEmpty();
//将获取文件大小
long getSize();
byte[] getBytes() throws IOException;
InputStream getInputStream() throws IOException;
//将文件持久化到磁盘
void transferTo(File dest) throws IOException, IllegalStateException;
}
通过在同一次请求中提交数据,可以很方便地同时处理文件以及实体类。对于头像等特殊文件(要在项目中使用,一般地需要将图片保存到项目能访问到的目录下),我们可以在数据库保存图像的字节数组。要访问图片的时候,从数据库读取字节数组,并将字节数组写成File持久化到项目能访问到的目录下,然后在项目中访问。