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,而我提交的文件太大了. 解决方案:修改 ...
随机推荐
- P3665 [USACO17OPEN]Switch Grass
题目描述 N个点M条边的无向图,每个点有一个初始颜色,每次改变一个点的颜色,求改变后整张图上颜色不同的点之间的距离最小值. 思路 考虑整张图的距离最小值一定是一条边,而不可能是一条路径,那么显然这条边 ...
- 【建站03】WordPress网站如何去除RSS功能
哈喽,大家好,我是帝哥,最近有小伙伴问我,如何去掉WordPress上的RSS功能,这个功能呢,说实话,我们很少会用到. 但是如果有点强迫症的话看着会很不舒服,所以,今天和大家分享一下如何去掉Word ...
- 零基础Linux入门之《Linux就该这么学》
本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的高质量Linux技术自学教程,极其适合用于Linux技术入门教程或讲课辅助教材,目前是国内最值得去读的Linux教材,也是最有价值 ...
- Python基本数据结构之文件操作
用word操作一个文件的流程如下: 1.找到文件,双击打开 2.读或修改 3.保存&关闭 用python操作文件也差不多: f=open(filename) # 打开文件 f.write(&q ...
- 模块参数,系统调用,字符设备编程重要数据结构,设备号的申请与注册,关于cdev的API
1.模块参数 应用编程: int main(int argc, char *argv[]) { } ./a.out xxx yyy zzz ...
- python——float()函数用法
float()函数是python中一个比较常用的内建函数,我们要详细掌握它的使用方法,避免在编写代码的过程中错误使用. float()函数返回一个十进制浮点型数值(小数). float()括号内只能是 ...
- php sublime常用插件
php sublime常用插件 1 Sublime Text的默认设置是不开启显示编码的,如果想开启,可通过菜单Perference → Settings – User,在打开的配置文件里 ,在大括号 ...
- html5 微信真机调试方法vConsole
html5 微信真机调试方法 vConsolehttps://blog.csdn.net/weixin_36934930/article/details/79870240
- Windows对python文件加密
最近项目需要对部分python文件加密,调研了部分方法都觉得不可行,最后采用了将python转换成so文件.pyd文件的方法.so文件,为liunx下的动态链接库文件,在windows下为dll文件, ...
- DNS服务反向解析及过程中一些小问题解决
在此需要了解一下,反向解析的作用是根据IP地址查找到对应的主机名(域名),在区域文件(named.rfc1912.zones)中默认已存在一些注释内容与区域信息,可不需要删除上面实验及默认区域信息,直 ...