springMVC的文件上传
上传文件是一个web应用很常用的一个功能,比如在一些社交网站上传些图片、视频等。下面我们来看一下,如何在内置tomcat整合springMVC的环境下,利用配置类和注解方式完成文件上传。
第一步:导入依赖,在配置类中完成上传文件组件的注册。
先创建一个maven工程,导入tomcat、spring、springMVC的依赖(详见之前的博文),另外,导入上传文件相关的依赖:
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.3</version>
</dependency>
在配置类中,添加上传文件类组件的注册:
@Configuration @EnableWebMvc @ComponentScan(basePackageClasses = WebApplicationConfig.class) public class WebApplicationConfig implements WebMvcConfigurer { @Bean public MultipartResolver multipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); //设置上传文件大小限制 multipartResolver.setMaxUploadSize(10240000); return multipartResolver; } }
这里需要注意,方法名只能是multipartResolver。
第二步,编写客户端html页面。
在resources目录下的static/html中,新建文件夹image,用于存放上传文件。新建html页面:upload.html,创建上传文件表单。创建表单时,需要注意两点:
1、该表单必须以POST方式提交,因为只有POST方式才支持客户端二进制方式的传输。
2、在form表单标签中,需要添加enctype="multipart/form-data" 属性。
添加enctype="multipart/form-data" 属性的原因是:默认情况下,form表单提交给服务器的数据是以“application/x-www-form-urlencoded”方式提交的。这样的格式在请求信息的消息体中,数据格式为“name=tom&tel=13029382329&password=123”。这样,如果在表单中有文件表单,那么,提交给服务器的只是文件表单选中文件的文件名:“face=1.jpg”。很明显,这样的数据是无法完成文件上传的,上传文件需将客户端的文件以二进制方式提交给服务器。
加上enctype="multipart/form-data"属性后,消息体的格式就不再是键值对方式了,格式为:
------WebKitFormBoundaryqgkaBn8IHJCuNmiW Content-Disposition: form-data; name="password" letmein01 ------WebKitFormBoundaryqgkaBn8IHJCuNmiW Content-Disposition: form-data; name="profilePicture"; filename="me.jpg" Content-Type: image/jpeg …… …… ------WebKitFormBoundaryqgkaBn8IHJCuNmiW--
这样,才能将客户端文件的二进制数据提交给服务器。
update.html完整的代码为:
<form action="/upload/add" method="post" enctype="multipart/form-data"> 姓名:<input type="text" name="name"><br> 头像:<input type="file" name="face"><br> <input type="submit" value="提交"> </form>
第三步,创建应用控制器,处理客户端上传文件的数据。
在这里,需要注意,由于使用的是内置tomcat,所以上传的文件应该在static/html/image目录中,对于该路径的物理路径的获取,可以通过线程来实现。
应用控制器代码如下:
@RestController @RequestMapping("upload") public class UploadController { @RequestMapping("add") public String add(String name,@RequestParam("face") MultipartFile mf) throws Exception { //得到上传文件名 String fileName = mf.getOriginalFilename(); //通过当前线程,得到上传文件存放目录的真实路径 URL url = Thread.currentThread().getContextClassLoader() .getResources("static/html/image").nextElement(); String filePath = URLDecoder.decode(url.getFile(), "utf-8"); //将上传文件的二进制数据,写入指定的文件 mf.transferTo(new File(filePath + "/" + fileName)); return "姓名:"+name+" 上传文件名:"+fileName; } }
考虑到每次上传文件不能同名,如果同名会造成上传文件的彼些覆盖。所以,需要对上传的文件进行重命名。另外,在项目中,可能会有多个应用控制器都有上传文件的业务。所以,可以将上传文件封装成工具类,便于代码重用。
public class UploadUtil { /** * 上传文件 * @param mf 上传文件对象 * @param dirPath 上传文件存放的目录 * @return 重命名后的上传文件名 */ public static String upload(MultipartFile mf,String dirPath){ //得到上传文件名 String fileName = mf.getOriginalFilename(); try { //重命名文件 fileName = System.currentTimeMillis() + fileName.substring(fileName.lastIndexOf(".")); //得到上传文件存放目录的真实路径 URL url = Thread.currentThread().getContextClassLoader() .getResources(dirPath).nextElement(); String filePath = URLDecoder.decode(url.getFile(), "utf-8"); //将上传文件的二进制数据,写入指定的文件 mf.transferTo(new File(filePath + "/" + fileName)); }catch (Exception e){ e.printStackTrace(); } return fileName; } }
这样,在应用控制器中,通过简单的调用,就能实现文件上传:
@RestController @RequestMapping("upload") public class UploadController { @RequestMapping("add") public String add(String name,@RequestParam("face") MultipartFile mf) throws Exception { String fileName = UploadUtil.upload(mf, "static/html/image"); return "姓名:"+name+" 上传文件名:"+fileName; } }
好了,现在启动服务器,打开浏览器访问upload.html页面,填写姓名,选择上传文件,提交表单。就可以完成文件上传。注意,上传的文件在maven工程的target目录下(这才是maven工程的运行环境)。在target/classes/static/html/image目录,可以看到上传的文件。
另外,还有个地方需要注意。如果上传文件和表单中的其他数据需要封装成实体对象时,实体类中存放的上传文件通常是以字符串方式存放文件名的。所以,不能把上传文件的表单名和实体类相关的属性名定义成一样。因为实体类的属性名是字符串,而上传文件后服务器必须以MultipartFile类型来接收上传文件。由于类型不一致,会抛出异常。

浙公网安备 33010602011771号