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,而我提交的文件太大了. 解决方案:修改 ...
随机推荐
- 『题解』BZOJ3172 [TJOI2013]单词
原文地址 Problem Portal Portal1:BZOJ Portal2:Luogu Description 某人读论文,一篇论文是由许多单词组成.但他发现一个单词会在论文中出现很多次,现在想 ...
- .NET手撸绘制TypeScript类图——上篇
.NET手撸绘制TypeScript类图--上篇 近年来随着交互界面的精细化,TypeScript越来越流行,前端的设计也越来复杂,而类图正是用简单的箭头和方块,反映对象与对象之间关系/依赖的好方式. ...
- 使用requests实现人人网登录,并做cookie维持
import requests import re,time s = requests.Session() def doLogin(): login_url = 'http://www.renren. ...
- 创建python的虚拟环境
为什么需要虚拟环境?如果你现在用Django 1.10.x写了个网站,然后你的领导跟你说,之前有一个旧项目是用Django 0.9开发的,让你来维护,但是Django 1.10不再兼容Django 0 ...
- Jquery EasyUI 中ValidateBox验证框使用讲解
来源素文宅博客:http://blog.yoodb.com/ Validatebox(验证框)的设计目的是为了验证输入的表单字段是否有效.如果用户输入了无效的值,它将会更改输入框的背景颜色,并且显示警 ...
- R画图——分屏
最近项目需求,用R画了一个九宫格的图,第一次画,将简化后的脚本呈现一下,不是有人说,既然做了,那就摆出来吧. *中文行为说明: args <- commandArgs(T) 调用命令行读取 fi ...
- 区块链原理、设计与应用pdf电子版下载
链接:https://pan.baidu.com/s/1koShkDjEYOXxLOewZJU2Rw 提取码:8ycx 内容简介 · · · · · · 本书由专业区块链开发者撰写,是区块链开发起步 ...
- hdu 1251 统计难题 (字典树(Trie)<PS:C++提交不得爆内存>)
统计难题Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131070/65535 K (Java/Others)Total Submis ...
- 自制反汇编工具使用实例 其二(使用xmm寄存器初始化对象,以及空的成员函数指针)
在反汇编代码中,当看到xmm寄存器,第一反应是将要进行浮点操作或访问,但是更加多的情况是在使用xmm寄存器初始化局部对象. 下面是自制反汇编工具翻译出来的代码: // -[CALayer setAll ...
- Linux安装telnet C/S 【白话文】
1.安装telnet 和telnet-server yum -y install telnet yum -y install telnet-server 注意:在此安装过程中,会依赖解决xinetd的 ...