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在转换过程中做了什么其他操作呢?

查看源码,或者直接看(https://www.cnblogs.com/tengyunhao/p/7670293.html)

发现 有个resolveLazily 是判断是否要延迟解析文件(通过XML可以设置)。当 resolveLazily 为 flase 时,会立即调用 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"));
    }

第1,2条日志很快打印,第3条日志仍是文件上传完后才打印。简单分析下,应该是后台一直在接收数据,HTTP首部很快就能获取到并解析出来(首部和正文之间有一个空行),但请求正文部分必须在请求数据完全接收后才能解析,因此线程一直阻塞直到数据接收完成才打印第3条日志。因此解决方案是,把controller函数中的@RequestParam("description") String description也注释掉,这样页面提交后,会立即进入controller中。

 

总结下最终的解决方案:

1、springmvc-config.xml增加一项配置:

<property name="resolveLazily ">
            <value>true</value>
        </property>

2、在controller的方法参数中,不能附加请求参数,应在函数中自己解析参数。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值