Spring MVC上传文件原理和resolveLazily说明
问题:使用Spring MVC上传大文件,发现从页面提交,到进入后台controller,时间很长。怀疑是文件上传完成后,才进入。由于在HTTP首部自定义了“Token”字段用于权限校验,Token的有效时间很短,因此上传大文件时,就会验证Token失败。
示例代码:
前端:
<form action="upload" enctype="multipart/form-data" method="post">
<table>
<tr>
<td>文件描述:</td>
<td><input type="text" name="description"></td>
</tr>
<tr>
<td>请选择文件:</td>
<td><input type="file" name="file"></td>
</tr>
<tr>
<td><input type="submit" value="上传"></td>
</tr>
</table>
</form>
controller:
@RequestMapping(value="/upload",method=RequestMethod.POST)
public String upload(HttpServletRequest request,
@RequestParam("description") String description,
@RequestParam("file") MultipartFile file) throws Exception {
System.out.println("enter controller."); // 文件上传完才打印
}
springmvc-config.xml配置:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>524288000</value>
</property>
<property name="defaultEncoding">
<value>UTF-8</value>
</property>
</bean>
Spring MVC上传文件使用了Commons FileUpload类库,即CommonsMultipartResolver使用commons Fileupload来处理 multipart请求,将Commons FileUpload的对象转换成了Spring MVC的对象。
那如果直接使用Commons FileUpload来进行文件上传下载呢?
示例代码:
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("enter servlet"); // 页面提交后,立马打印
// 省略获取上传文件的逻辑
// ...
}
发现从页面提交,很快就进入了servlet。
既然Spring也是使用了Commons FileUpload类库,但为什么差别这么大呢?Spring在转换过程中做了什么其他操作呢?
查看源码,或者直接看([Java] SpringMVC工作原理之四:MultipartResolver)
发现有个resolveLazily参数是判断是否要延迟解析文件(通过XML可以设置)。当 resolveLazily为false(默认)时,会立即调用 parseRequest() 方法对请求数据进行解析,然后将解析结果封装到 DefaultMultipartHttpServletRequest中;而当resolveLazily为 true时,会在DefaultMultipartHttpServletRequest的initializeMultipart()方法调用parseRequest()方法对请求数据进行解析,而initializeMultipart()方法又是被getMultipartFiles()方法调用,即当需要获取文件信息时才会去解析请求数据,这种方式用了懒加载的思想。
再次修改代码:
1、在springmvc-config.xml增加一个配置resolveLazily,设置true(如何配置见文末);
2、将controller方法中将@RequestParam("file") MultipartFile file注释
再次测试,发现还是不对。。增加打印日志后发现:
@RequestMapping(value="/upload",method=RequestMethod.POST)
public String upload(HttpServletRequest request,
@RequestParam("description") String description
/*@RequestParam("file") MultipartFile file*/) throws Exception {
System.out.println("enter controller."); // 还是文件上传完后,才打印
System.out.println(request.getHeader("Accept"));
System.out.println(request.getParam("description"));
// 省略获取上传文件的逻辑
}
再注释@RequestParam("description") String description
@RequestMapping(value="/upload",method=RequestMethod.POST)
public String upload(HttpServletRequest request
/*@RequestParam("description") String description, */
/*@RequestParam("file") MultipartFile file*/) throws Exception {
System.out.println("enter controller."); // 页面提交后,立刻打印
System.out.println(request.getHeader("Accept")); // 几乎也是立刻打印
System.out.println(request.getParam("description")); // 文件上传完,才打印
// 省略获取上传文件的逻辑
}
这次,第1,2条日志很快打印,第3条日志仍是文件上传完后才打印。简单分析下,应该是后台一直在接收数据,HTTP首部很快就能获取到并解析出来(首部和正文之间有一个空行),但请求正文部分必须在请求数据完全接收后才能解析,因此线程一直阻塞直到数据接收完成才打印第3条日志。因此解决方案是,把controller函数中的@RequestParam("description") String description也注释掉,这样页面提交后,会立即进入controller中。
总结下最终的解决方案:
1、springmvc-config.xml增加一项配置:
<property name="resolveLazily ">
<value>true</value>
</property>
2、在controller的方法参数中,不能附加请求参数,应在函数中自己解析参数。
Spring MVC上传文件原理和resolveLazily说明的更多相关文章
- Spring MVC上传文件
Spring MVC上传文件 1.Web.xml中加入 <servlet> <servlet-name>springmvc</servlet-name> <s ...
- Spring MVC 上传文件
Spring MVC上传文件需要如下步骤: 1.前台页面,form属性 method设置为post,enctype="multipart/form-data" input的typ ...
- 解析Spring MVC上传文件
新建一个普通的maven工程 在pom.xml文件中引入相应的坐标 <?xml version="1.0" encoding="UTF-8"?> & ...
- spring MVC上传文件演示
//相比smartUpload功能上感觉确实有点心有意力不足的感觉,就安全性判断后缀,smartUpload就非常方便. public ModelAndView addFileUp(HttpServl ...
- Spring Mvc 上传文件Demo 实例
返得利购物. 淘宝.京东500家商城合作,包括全面的商城返利网.注冊就送5元,购物就有返利.随时提现. 同学们,新一轮的返利大潮正在慢慢靠近,让购物都认为自己在赚钱.购物,机票.游戏.酒店旅游,地方特 ...
- Spring框架学习(8)spring mvc上传下载
内容源自:spring mvc上传下载 如下示例: 页面: web.xml: <?xml version="1.0" encoding="UTF-8"?& ...
- MVC上传文件
ASP.NET MVC上传文件是必段撑握的知识.加强训练才是.以前Insus.NET曾使用第三方MyAjaxForm.js :http://www.cnblogs.com/insus/p/378548 ...
- springboot(十七):使用Spring Boot上传文件
上传文件是互联网中常常应用的场景之一,最典型的情况就是上传头像等,今天就带着带着大家做一个Spring Boot上传文件的小案例. 1.pom包配置 我们使用Spring Boot最新版本1.5.9. ...
- asp.net MVC 上传文件 System.Web.HttpException: 超过了最大请求长度
APS.NET MVC 上传文件出现 System.Web.HttpException: 超过了最大请求长度 这个问题 原因是 默认最大上传文件大小为4096,而我提交的文件太大了. 解决方案:修改 ...
随机推荐
- 8.1 NOIP模拟11
8.1 NOIP模拟 11 今天上午返校之后,颓了一会,然后下午就开始考试,中午睡着了,然后刚开始考试的时候就困的一匹,我一看T1,woc,这不是之前线段树专题的题啊,和那道题差不多,所以我..... ...
- Linux Shell | 解析xml节点
01 xml文件 # user.xml <user> <name>Toy</name> <sex>man</sex> <room/&g ...
- Linux 常用命令 | free 详解
free命令可以显示Linux系统中空闲的.已用的物理内存及swap内存,及被内核使用的buffer.在Linux系统监控的工具中,free命令是最经常使用的命令之一.本文介绍free命令的使用方法和 ...
- java中继承,子类是否继承父类的构造函数
java中继承,子类是否继承父类的构造函数 java继承中子类是不会继承父类的构造函数的,只是必须调用(隐式或者显式) 下面来看例子: public class TestExtends { publi ...
- mysql查询不重复的行内容,不重复的记录数.count,distinct
有这么一个表 记录了id, p_id, p_name , p_content , p_time 1 343 aaa aaaaaa 2012-09-01 2 ...
- [spark程序]统计人口平均年龄(HDFS文件)(详细过程)
一.题目描述 (1)请编写Spark应用程序,该程序可以在分布式文件系统HDFS中生成一个数据文件peopleage.txt,数据文件包含若干行(比如1000行,或者100万行等等)记录,每行记录只包 ...
- PowerMock学习(三)之Mock局部变量
编写powermock用例步骤: 类上面先写这两个注解@RunWith(PowerMockRunner.class).@PrepareForTest(StudentService.class) 先模拟 ...
- ArcGIS API For Javascript :读取 CSV 文件的方法
我们临时会遇到一些测试数据,通常从数据库中以 CSV 格式导出.最简单实用的方法就是使用 ajax 去读取文件,记得引入 jQuery . 例如,在<ArcGIS JS API :新增一个热力图 ...
- 力扣(LeetCode)键盘行 个人题解
给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词.键盘如下图所示. 示例: 输入: ["Hello", "Alaska", "Dad& ...
- Flex调用JavaScript获取文件路径
Flex的Web中有FileReference的类可以对文件操作,实现上传.下载的功能,但是没有办法获取到文件的路径. 普遍的方法是Flex调用JavaScript的文件浏览功能来获取文件路径. 1. ...