该文档针对于springMVC上传功能详解(一)的总结
1.在上一篇文章中,主要介绍了Spirng MVC环境下的上传功能实现(已经经过完善的版本)。在实际开发的时候,还会涉及到上传文件大小和类型的限制,接下来就会对Spirng MVC环境下文件上传大小和类型的限制进行介绍,还会讲解到文件上传大小tomcat服务器bug问题及解决方案。
一、文件上传大小限制
这里还是接着上篇文章先介绍Spring MVC下的文件上传大小限制,文件上传大小的限制在springmvc-config.xml中配置文件解析器CommonsMultipartResolver时即可配置,示例如下:
<!-- SpringMVC上传文件时,需要配置MultipartResolver处理器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!--
指定所上传文件的总大小不能超过1M(单位为字节),注意maxUploadSize属性的限制不是针对单个文件,而是所有文件的容量之和
-->
<property name="maxUploadSize" value="#{3*1024*1024}"></property>
<!-- 单位为字节 -->
<!--resolveLazily属性启用是为了推迟文件解析,以便在UploadController 中捕获文件大小异常-->
<property name="resolveLazily" value="true"></property>
</bean>
关于Spring MVC中文件上传大小的限制就这么简单,然后在利用注解处理异常如下:
//异常处理
@ExceptionHandler
public String exHandle(Exception ex, HttpServletRequest request){
if(ex instanceof MaxUploadSizeExceededException){
//long maxSize = ((MaxUploadSizeExceededException) ex).getMaxUploadSize();//允许上传文件的最大值
request.setAttribute("errorMsg", "文件总内容超过了3 M");
return "error/error";
}else{
return "error/system_error";
}
}
此种方式存在一个bug,当文件大于2M的时候会抛出一个异常MaxUploadSizeExceededException,且该异常不会在该注解中进行处理,直接抛出:
可能出现关于MaxUploadSizeExceededException 死循环状态,此时页面直接崩溃(如上)。
关于这个异常问题,在市面书籍、课程资料中都没有提及这一点,都有意避之(因为开发中可能更多的使用插件进行文件上传和下载,而不是用框架自带的,另外这个bug问题目前也未能有效解决)。针对这个问题,查询了官方文档以及相关资料都没有明确的解决方案和问题说明。不过在一篇老外的bug报告中提及到这个bug问题,在文章中说明了这可能是tomcat服务器的bug问题,而非Spring MVC框架问题,如果使用tomcat7.0.39版本的话,这个问题就不存在了。
所以针对Spring MVC文件上传大小限制出现的这个问题,可以换用tomcat7.0.39版本的tomcat服务器;或者使用另一种思路。
目前可行的解决方案:
首先在配置文件解析器时,不使用Spring MVC提供的文件上传大小限制属性<property name="maxUploadSize" value="#{3*1024*1024}" />,只配置一个单独的bean就可以了,示例如下:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
然后自定义一个拦截器来限定文件上传大小,并模拟抛出MaxUploadSizeExceededException异常:
package interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.servlet.ServletRequestContext;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 上传文件过大的拦截器(拦截异常MaxUploadSizeExceededException)
* 这样就可以完成在Spring MVC环境下文件上传大小的限制以及异常正确捕获了。
* @author 王庆
*
*/
public class MaxUploadInterceptor implements HandlerInterceptor{
private long maxSize;//上传文件的大小B(字节)
public void setMaxSize(long maxSize) {
this.maxSize = maxSize;
}
public long getMaxSize() {
return maxSize;
}
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
if(request != null && ServletFileUpload.isMultipartContent(request)) {
ServletRequestContext ctx = new ServletRequestContext(request);
long requestSize = ctx.getContentLength();
if (requestSize > maxSize) {
throw new MaxUploadSizeExceededException(maxSize);
}
}
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
记得在spring配置文件中配置拦截器,注入拦截所需的参数(允许最大文件字节):
<!-- 配置处理上传文件过大的拦截器(拦截该异常MaxUploadSizeExceededException)-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="interceptor.MaxUploadInterceptor">
<property name="maxSize" value="#{3*1024*1024}"/><!-- 不超过3M -->
</bean>
</mvc:interceptor>
</mvc:interceptors>
这样就可以完成在Spring MVC环境下文件上传大小的限制以及异常正确捕获了。在springMVC上传功能详解(一)中就是这样处理的
所以有两种方法进行处理:
1.修改tomcat版本为7.0.39,经过本人测试有效,这样就可以不用配置拦截器,因为tomcat默认2M,超过抛异常,但7.0.39版本不存在这个问题,没有限制
2.把maxUploadSize 设置大一点,属性<property name="maxUploadSize" value="#{300*1024*1024}" />(此处设置了300M),这样的话,在300M以内都不会抛出异常,若要求限制文件上传大小5M,则该方法不适用,且该方法在文件超过300M时候仍会页面崩溃(对上传文件大小没有限制的话可以使用,但尽量不用)
3.使用拦截器,将异常抛出,到如下代码处理:
//异常处理
@ExceptionHandler
public String exHandle(Exception ex, HttpServletRequest request){
if(ex instanceof MaxUploadSizeExceededException){
//long maxSize = ((MaxUploadSizeExceededException) ex).getMaxUploadSize();//允许上传文件的最大值
request.setAttribute("errorMsg", "文件总内容超过了3 M");
return "error/error";
}else{
return "error/system_error";
}
}
---------------------------------------------------------------------------------------------
案例说明:
一、本文并没有限制上传文件的类型,只是限制了上传文件的大小,在上传页面要求至少选中一个文件,若有两个上传input,客户只上传了一个文件,此处在前台进行了js校验(至少有一个文件),提交表单之前的校验,提交表单后,在多文件上传这个功能上,后台还需要对fielName进行校验,若不存在,如刚才所说,只上传了一个文件,这时候另一个文件的fileName为空字符串,for循环中则不进行该文件的上传,使用continue来处理
二、本案例使用的tomcat为7.0.81版本
三、若已经存在文件a,再次上传后会做替换操作
四、在上传方法中,其中使用MultipartFile来接受form表单传过来的file文件,MultipartFile有几个核心的api,可以供我们使用,比如 boolean isEmpty(),用来判断文件是否为空。void transferTo( File file),把文件写入目标路径地址,案例中采用的是js中判断文件存在,后台就不需要再判断了,也可在后台判断,将判断结果传入前端,显示提示
---------------------------------------------------------------------------------------------
补充知识如下:如何限制文件的类型
文件上传类型的限制
在这里讲解之前必须要声明的是,在Spring MVC配置下,并没有像Struts2配置文件中那样配置一个拦截器就可以同时限定上传文件大小和类型。同时在官方文档以及其相关资料中也没有提出在Spring MVC环境中限制文件上传类型的解决方案,不过这里我们仍然可以使用自定义拦截器来限制文件上传类型。
首先自定义一个文件上传类型限制的拦截器,示例如下:
/**
* 全局文件类型拦截器
*/
public class FileTypeInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)throws Exception {
boolean flag= true;
// 判断是否为文件上传请求
if (request instanceof MultipartHttpServletRequest) {
MultipartHttpServletRequest multipartRequest =
(MultipartHttpServletRequest) request;
Map<String, MultipartFile> files =
multipartRequest.getFileMap();
Iterator<String> iterator = files.keySet().iterator();
//对多部件请求资源进行遍历
while (iterator.hasNext()) {
String formKey = (String) iterator.next();
MultipartFile multipartFile =
multipartRequest.getFile(formKey);
String filename=multipartFile.getOriginalFilename();
//判断是否为限制文件类型
if (! checkFile(filename)) {
//限制文件类型,请求转发到原始请求页面,并携带错误提示信息
request.setAttribute("errormessage", "不支持的文件类型!");
request.getRequestDispatcher("/WEB-INF/jsp/userEdit.jsp")
.forward(request, response);
flag= false;
}
}
}
return flag;
}
/**
* 判断是否为允许的上传文件类型,true表示允许
*/
private boolean checkFile(String fileName) {
//设置允许上传文件类型
String suffixList = "jpg,gif,png,ico,bmp,jpeg";
// 获取文件后缀
String suffix = fileName.substring(fileName.lastIndexOf(".")
+ 1, fileName.length());
if (suffixList.contains(suffix.trim().toLowerCase())) {
return true;
}
return false;
}
}
在上述示例中,自定义的拦截器限制了文件上传类型为:String suffixList = "jpg,gif,png,ico,bmp,jpeg";当拦截成功后会重回远请求页面,并携带错误信息。
然后在spring-config.xml中配置自定义拦截器,示例如下:
<mvc:interceptors>
<!-- 如果有多个拦截器,则按照顺序进行配置 -->
<mvc:interceptor>
<!-- /**表示所有URL和子URL路径 -->
<mvc:mapping path="/**" />
<!-- 配置自定义的文件上传类型限制拦截器 -->
<bean class="com.itheima.interceptor.FileTypeInterceptor" />
</mvc:interceptor>
</mvc:interceptors>