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,而我提交的文件太大了. 解决方案:修改 ...
随机推荐
- 参观路线——并查集+dfs
题目描述 Lambdaland由N个城市组成,任两个城市间都有一条道路相连. 下个月TBL准备参观Lambdaland.他将从城市1开始,以深度优先搜索顺序参观能所有遍历到的城市. 由于TBL是一位 ...
- 中文企业云操作系统 CecOS
CecOS介绍 CecOS(原中文企业云操作系统.第一个版本基于oVirt 3.0,后续在此基础上不断升级迭代拓展至今,已形成基于基础底层和应用功能拓展集成在内的10款产品和四大平台),旨在通过先进的 ...
- Consul安装集群搭建
1 consul的安装和配置 1.1 consul agent 命令介绍 下载consul_1.0.0_linux_amd64.zip解压,里面只有一个consul可执行文件,其中,consul最常用 ...
- Machine Learning in Action ---- kNN
------------恢复内容开始------------ # -*- coding: utf-8 -*- """ Created on Thu Nov 14 19:2 ...
- js的split()和join()的用法
split() 方法用于把一个字符串分割成字符串数组.split[splɪt]:vt. 分离:使分离:劈开:离开:分解 stringObject.split(separator,howmany) se ...
- Web前端JS实现轮播图原理
实现轮播图有很多方式,但是html的结构都是一样的.本文使用了Jquery框架,Dom操作更加方便灵活 html部分: <div class="banner"> < ...
- 利用GitHub Pages + jekyll快速搭建个人博客
前言 想搭建自己博客很久了(虽然搭了也不见得能产出多频繁). 最初萌生想写自己博客的想法,想象中,是自己一行一行码出来的成品,对众多快速构建+模板式搭建不屑一顾,也是那段时间给闲的,从前后端选型.数据 ...
- MySQL/MariaDB读写分离配置
DB读写分离描述 数据库的读写分离其实就是为了加减少数据库的压力:数据库的写入操作由主数据库来进行,读取操作由从数据库来进行操作.实现数据库读写分离技术是有很多方法的,在这里我就用一个比较简单的mys ...
- 开始逆向objc基础准备(二)我的平台是simulator-x86_64
建项目运行中断调试,lldb中显示寄存器看到有rax-r15, stm0-stm7, xmm0-xmm15, ymm0-ymm15,即为x64体系支持sse4. 再在lldb中查看寄存器别名得到以下对 ...
- mac如何开启两个vmware虚拟机
转载链接:https://blog.csdn.net/aifore/article/details/87833088