论坛首页 Java企业应用论坛

基于SpringMVC文件上传服务器端进度条实现

浏览 9078 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-04-06   最后修改:2012-04-06

        文件上传应该大部分人都接触过,一般都是基于commons-fileupload组件来实现,SpringMVC的文件上传功能也是在commons-fileupload组件提供的功能上面做了一些包装功能,使文件上传开发更容易方便。
        首先来看看我们系统对于文件上传功能提出来的需求:
        1、能同时上传多个文件;
        2、单个文件大小不超过2G;
        3、要有进度条可以实时显示上传进度;
        4、可以取消正在上传的文件;
        5、文件上传到分布式存储系统,保证上传的效率。

        一、实现普通文件上传
        我们知道,类DispatcherServlet是SpringMVC的入口,在其doDispatch方法里面,我们可以看到它会先去检查有没配置multipartResolver 

        如果有的话会先执行它的resolveMultipart方法:

        因此,我们在配置文件中添加:
                则可使用SpringMVC自带的CommonsMultipartResolver实现多个文件上传的功能。

        二、实现进度条
        现在实现带进度条的文件上传一般都是在客户端用flash上传组件计算,或者是通过客户端插件的方式。前者上传组件有大小的限制,后者对于我们系统来说实现过于复杂,开发难度稍大。因此我们采用服务器端计算文件上传进度,客户端轮询的方式。
        Commons-fileupload组件自带了文件上传进度的监听器,类FileUploadBase提供了它的set方法:        
        
        ProgressListener是一个接口,我们需要自己实现它的update方法,参数pBytesRead表示已经上传到服务器的字节数,pContentLength表示所有文件的总大小,pItems表示第几个文件:
        
        SpringMVC没有实现监听器,所以如果要监听的话得自己扩展CommonsMultipartResolver类,在newFileUpload里面加入代码设置自己实现的监听器:

        ServletFileUploadExt是对ServletFileUpload类进行的扩展,后面会提到。这样在文件上传的过程中,监听器将得到通知已上传的字节数:
        
        


        三、上传到分布式存储系统
        通过阅读commons-fileupload的源码我们知道实际文件上传发生在FileUploadBase类parseRequest(RequestContext ctx)方法里面:
         

        因此我们可以通过继承ServletFileUpload(该类继承自FileUpload)类重写parseRequest方法来实现我们自己的存储方式。这里有个地方需要注意的,一般文件保存到分布式存储系统中,为了减少IO次数,需要实现本地的buffer,等buffer满了后再上传上去:
        
         但是因为commons-fileupload组件本身有个buffer,而且buffer大小为4096:
         
        
        因此按照上面实现的话不管自己定义多大的buffer,一次IO传上去的实际不到4096字节(减去http头信息等),我们需要用扩展了BufferedInputStream的类包装下:
        
        BufferedInputStreamExt主要对read方法做了一些修改:
        
        去掉了BufferedInputStream类该方法的几条语句,因为在上传组件自带buffer的情况下,读一次后input.available()会为0,此处会导致提前返回而不能把自定义的buffer读满:
        

        四、取消文件上传
        取消文件上传实现方式为上传时保存上传输入流的引用,取消时关闭流,让输入流产生IO异常或者数组越界异常,同时捕获这些异常,则可取消文件上传。

        五、总结&改进
        由于SpringMVC上传的时候并不能得到单个文件的大小,配置文件限制的大小也是所有文件的大小,非单个文件大小,监听的也是整体文件上传的进度。所以在客户端可以做一些改进,比如模拟一次可以上传多个文件,但实际上传时只上传单个文件,等第一个文件上传完毕后再依次发请求上传第二第三个文件。

 

        欢迎对本文提出的实现方式进行讨论和指导,如有更好的实现方式,亦欢迎指教,谢谢!

 

  • 大小: 13.1 KB
  • 大小: 19.4 KB
  • 大小: 8.8 KB
  • 大小: 7 KB
  • 大小: 15.5 KB
  • 大小: 10 KB
  • 大小: 10.5 KB
  • 大小: 5.8 KB
  • 大小: 25.1 KB
  • 大小: 8.1 KB
  • 大小: 5.2 KB
  • 大小: 4.8 KB
  • 大小: 3.2 KB
  • 大小: 16.7 KB
  • 大小: 4.3 KB
   发表时间:2012-04-06  
周五果然很冷清
0 请登录后投票
   发表时间:2012-04-09  
上传很大文件总是没有太好的解决方案,要不插件,要不传统http
0 请登录后投票
   发表时间:2012-04-09  
无图无真相
0 请登录后投票
   发表时间:2012-04-09  
有代码么,这么看着实在手痒啊,能运行一下就好了
0 请登录后投票
   发表时间:2012-04-09  
很详细,要是有运行代码就更好了
0 请登录后投票
   发表时间:2012-04-09  
guxinghanshe 写道
很详细,要是有运行代码就更好了


因为公司对代码管理比较严格,虽然是基于开源框架的实现,但还是不方便给出,见谅!
理论的东西和主要的切入点都给出来了,发出来主要是给大家参考和大家讨论,希望大家能给出自己的见解。
如果有更好的解决方案,那就太好了 
0 请登录后投票
   发表时间:2012-04-09   最后修改:2012-04-09
支持断点续传吗?支持的话发一下代码
0 请登录后投票
   发表时间:2012-04-09  
hbmzzl 写道
支持断点续传吗?支持的话发一下代码


这个真没支持
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics