Project(5)——基于SpringMVC的文件上传
1、创建项目
创建Maven Project,Group Id值为cn.tedu.spring,Artifact Id为SPRINGMVC-UPLOAD,在配置依赖时,此次需要spring-webmvc
依赖,另外,还需要commons-fileupload
依赖:
<!-- spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.1.RELEASE</version>
</dependency>
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
在 web.xml 中配置 Servlet:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>SMVCU</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>MyBatis</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-*.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyBatis</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
2、设计界面
在webapp下创建index.html,作为用户选择文件上传的界面,该界面中,上传控件必须是<input type="file"/>
,控件所在的表单必须使用POST
方式提交请求,且必须配置enctype="multipart/form-data"
,其它部分可以自行设计,例如:
<h1>基于SpringMVC的文件上传</h1>
<form action="" method="post" enctype="multipart/form-data">
<p>请选择要上传的文件</p>
<input type="file" name="file"> <input type="submit"
value="上传">
</form>
3、配置MultipartResolver
在Spring的配置文件applicationContext.xml
中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
</beans>
添加CommonsMultipartResolver
配置:
<!-- 组件扫描 -->
<context:component-scan base-package="cn.tedu.spring"></context:component-scan>
<!-- 配置ViewResolver-视图解析器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 注解驱动 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- CommonsMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
添加以上配置后,暂时可以不用添加更多配置。
4、通过控制器接受并处理请求
创建cn.tedu.spring.UploadController
控制器类,为控制器类添加@Controller
注解:
@Controller
public class UploadController{
}
检查Spring的配置文件,其中的组件扫描应该设置为cn.tedu.spring
。
然后在控制器类中添加处理请求的方法,该方法中必须添加MultipartFile file
参数,该参数名需要与前端页面的控件中使用的name
属性的值保持一致,另外,需要添加@RequestParam("file")
注解,使用注解后,需要保持一致的名称就是注解中使用的名称:
@Controller
public class UploadController{
@RequestMapping("upload.do")
public String handleUpload(@RequestParam("file") MultipartFile file){
return null;
}
}
参数对象表示的就是客户端提交的需要上传的文件,只需要调用参数对象transferTo(File dest)
方法即可实现文件上传!
另外,在前端页面中,还要设置表单提交到upload.do路径。
5、关于上传后在服务器端的文件名
保存到服务器端后使用的文件名必须不能发生冲突,否则,后续上传的文件,会覆盖前序上传的文件!
关于File
类,使用1个String
作为构造方法参数时,表示目标文件的完整路径,也可以使用2个String
作为构造方法的参数,第1个表示文件夹,第2个表示文件名,所以,也可以是:
// 确定上传到服务器,保存到的目标文件
File dest = new File("D:/","baidu.png");
接下来,应该将第2个参数设置为变量,以保证各上传的文件名不发生冲突!
关于文件名的设置策略,可以自行决定,使用时间、随机数等元素作为文件名的一部分,就可以保证文件名不会发生冲突!
// 确定文件名
String filename = UUID.randomUUID().toString() + suffix;
// 确定上传到服务器,保存到的目标文件
File dest = new File("D:/",filename);
另外,还需要保证文件有正确的扩展名,应该取决于上传时,该文件在客户端计算机中保存时使用的名称,通过参数对象file
的String getoriginalFilename()
方法可以获取文件的原名,然后查询最后一个小数点的位置,并截取出扩展名即可:
// 获取文件原名
String originalFilename = file.getOriginalFilename();
System.out.println("originalFilename = " + originalFilename);
// 获取扩展名
String suffix = "";
int beginIndex = originalFilename.lastIndexOf(".");
// 对于没有 . 的文件,要进行判断,如果没有 . 则lastIndexOf的值为-1,只需拼接空字符串即可。
if(beginIndex != -1) {
suffix = originalFilename.substring(beginIndex);
}
// 利用随机数确定文件名
String filename = UUID.randomUUID().toString() + suffix;
6、文件夹
文件必须上传到部署的Tomcat中,当上传后,才可以保证后续的使用或下载,可以通过HttpServletRequest
对象的getServletContext().getRealPath("upload")
获取指定的文件夹的实际路径。再添加一个HttpServletRequest参数:
@RequestMapping(value = "upload.do", method = RequestMethod.POST)
public String upload(@RequestParam("file") MultipartFile file, HttpServletRequest request)
...
..
..
..
// 确定上传的文件夹
String dirPath = request.getServletContext().getRealPath("upload");
File dir = new File(dirPath);
if (!dir.exists()) {
dir.mkdirs();
}
System.out.println("dir = " + dir);
// ...
// ...
// ...
// 确定上传到服务器,保存到的目标文件
File dest = new File(dir, filename);
基于该文件夹确定最终上传的文件位置:
// 确定上传到服务器,保存到的目标文件
File dest = new File(dir, filename);
7、MultipartFile相关API
7.1.boolean isEmpty()
该方法用于判断上传的文件是否为空,当用户没有选择上传的文件,或选中的文件是空文件(0字节)时,该方法返回true,可用于验证:
// 判断上传文件是否为空文件
boolean isEmpty = file.isEmpty();
System.out.println("isEmpty = " + isEmpty);
if(isEmpty) {
return "error";
}
7.2.long getSize()
该方法用于获取文件的大小,以字节为单位,通常,用于限制上传的文件大小:
long size = file.getSize();
System.out.println("size = " + size);
if(size > 10 * 1024 * 1024) {
return "error";
}
7.3.String getContentType()
该方法用于获取文件的MIME类型,通常,用于限制上传的文件的类型:
String contentType = file.getContentType();
System.out.println("contentType = " + contentType);
List<String> types = new ArrayList<String>();
types.add("image/jpeg");
types.add("image/gif");
types.add("image/png");
if(!types.contains(contentType)) {
return "error";
}
关于各种文件扩展名对应的MIME类型,可以上网查阅,也可以在Tomcat目录中的conf/web.xml文件中查找。MIME的值,完全取决于文件的扩展名,如果文件的扩展名被修改,MIME也可能发生变化。
7.4.String getOriginalFilename()
获取文件的原名,即该文件在客户端的文件全名,典型的用途就是获取文件的扩展名。
// 获取文件原名
String originalFilename = file.getOriginalFilename();
System.out.println("originalFilename = " + originalFilename);
7.5. void transferTo(File dest)
执行保存所上传的文件。
// 确定上传到服务器,保存到的目标文件
File dest = new File(dir, filename);
System.out.println("将文件保存到:" + dest);
// 执行保存
file.transferTo(dest);
7.6.InputStream getInputStream()
获取输入字节流,用于自定义接收所上传的文件的数据。
注意:该方法与以上transferTo()
不可以同时使用,对于每个请求,只能选取其中1个方法来获取数据并保存文件。
8、关于MultipartResolver的配置
8.1. maxUploadSize
用于配置上传的文件的最大大小,例如:当设置值为10M时,则上传的文件均不可以超过10M,即使一次性上传10个文件,则10个文件的大小总和不允许超过10M。
例如可以配置最大大小为10M为:
在XML中的配置是全局配置,
<!-- CommonsMultipartResolver -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10485760"></property>
</bean>
以上7.2.的配置为具体功能的配置:
long size = file.getSize();
System.out.println("size = " + size);
if(size > 10 * 1024 * 1024) {
return "error";
}
8.2.maxUploadSizePerFile
用于配置上传的每个文件的最大大小,例如:当设置值为10M时,如果一次性上传10个文件,则每个文件都不允许超过10M,但是总大小可以接近100M。
8.3.defaultEncoding
用于配置默认编码,上传的文件本身是不考虑编码问题的,只要文件的内容(表示文件内容信息含义的二进制序列)是正确的就可以了!由于上传过程中,会通过CommonsMultipartResolver
去组织上传时表单中的数据,表单中可能包括例如输入框等控件,则同一个表单中还可能提交例如用户名等文本信息,这些信息都需要使用正确的编码来进行传递!