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

        文件上传应该大部分人都接触过,一般都是基于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上传的时候并不能得到单个文件的大小,配置文件限制的大小也是所有文件的大小,非单个文件大小,监听的也是整体文件上传的进度。所以在客户端可以做一些改进,比如模拟一次可以上传多个文件,但实际上传时只上传单个文件,等第一个文件上传完毕后再依次发请求上传第二第三个文件。

 

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值