servlet、struts2、springmvc中实现带进度条的文件上传

38 篇文章 0 订阅
37 篇文章 0 订阅

实现带进度条的文件上传的基本原理是这样的:

前台异步提交文件上传请求,然后每隔一段时间向服务器发送请求查询文件上传进度。

后台处理程序解析文件上传请求,并且每隔一段时间将上传进度保存在HttpSession中。(由于HttpRequest是无状态的,因此只能保存在HttpSession中)

commons-fileupload包中的ServletFileUpload类可以注册一个进度监听器ProgressListener,使用它可以简化工作(实际上也没多大简化,嘿嘿),不用自己处理监听了。

前台异步提交上传请求的方式就不多说了。(可以使用jquery的文件上传插件)

下面说说如何在servlet、struts2以及springmvc中进行处理。

1、servlet中带进度条的文件上传:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 
        final HttpSession session = req.getSession(); 
        FileItemFactory factory = new DiskFileItemFactory(); 
        ServletFileUpload upload = new ServletFileUpload(factory); 
        upload.setProgressListener(new ProgressListener() { 
            @Override 
            public void update(long pBytesRead, long pContentLength, int pItems) { 
                int percent = (int) (((float)pBytesRead / (float)pContentLength) * 100); 
                session.setAttribute("percent", percent + "%"); 
            } 
        }); 
        upload.setHeaderEncoding("utf-8"); 
        try { 
            List<FileItem> items = upload.parseRequest(req); 
            for (FileItem fileItem : items) { 
                if (!fileItem.isFormField()) { 
                    String fileName = fileItem.getName(); 
                    FileOutputStream fos = new FileOutputStream(new File("c:/" + fileName)); 
                    InputStream is = fileItem.getInputStream(); 
                    byte[] buffer = new byte[256]; 
                    int readBytes = 0; 
                    while (-1 != (readBytes = is.read(buffer))) { 
                        fos.write(buffer, 0, readBytes); 
                    } 
                    is.close(); 
                    fos.close(); 
                } 
            } 
        } catch (FileUploadException e) { 
            e.printStackTrace(); 
        } 
    } 

2、struts2中带进度条的文件上传。

struts2默认的拦截器中有一个FileUploadInterceptor,它会拦截所有的MultipartRequest,并且将得到的File及相关信息传递给action,因此在action被调用之前,文件上传已经被处理完了。

struts2处理文件上传使用的是commons-fileupload,因此我们可以使用ProgressListener。注意我们需要在解析请求的时候加入我们的监听器,我们首先想到的是替换掉FileUploadInterceptor,不幸的是FileUploadInterceptor并不执行解析的任务,实际在FileUploadInterceptor被调用之前,MultipartRequest已经被解析了,文件上传的工作已经完成。

实际上对于所有的文件上传请求,struts2会为其生成一个MultiPartRequestWrapper进行包装,而它维护着一个MultiPartRequest接口的实例。MultiPartRequest的实现类只有一个JakartaMultiPartRequest,JakartaMultiPartRequest有一个方法parseRequest,此方法负责解析request并生成FileItem。

因此我们可以重写此方法,添加ProgressListener。不幸的是,JakartaMultiPartRequest的很多方法都是private的,我们不能继承它然后重写parseRequest方法。

JakartaMultiPartRequest实现了MultiPartRequest接口,我们可以编写一个类,实现MultiPartRequest接口,并且把JakartaMultiPartRequest的代码全都拷贝过来,然后修改parseRequest方法。 

下面是修改后的parseRequest方法:

private List<FileItem> parseRequest(HttpServletRequest servletRequest, String saveDir) throws FileUploadException { 
        final HttpSession session = servletRequest.getSession(); 
        DiskFileItemFactory fac = createDiskFileItemFactory(saveDir); 
        ServletFileUpload upload = new ServletFileUpload(fac); 
        upload.setProgressListener(new ProgressListener() { 
            @Override 
            public void update(long pBytesRead, long pContentLength, int pItems) { 
                int percent = (int) (((float)pBytesRead / (float)pContentLength) * 100); 
                session.setAttribute("percent", percent + "%"); 
                System.out.println(percent); 
            } 
        }); 
        upload.setSizeMax(maxSize); 
        return upload.parseRequest(createRequestContext(servletRequest)); 
    } 

最后我们需要将我们编写的类注册到struts2的配置文件中。

strtus-default.xml  中有这么一段配置:

<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="struts" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default"/> 
    <bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="jakarta" class="org.apache.struts2.dispatcher.multipart.JakartaMultiPartRequest" scope="default" /> 
    <constant name="struts.multipart.handler" value="jakarta" /> 

我们照葫芦画瓢即可。

在struts.xml中按下面的方式配置,覆盖掉struts-default.xml中的配置。

<bean type="org.apache.struts2.dispatcher.multipart.MultiPartRequest" name="parser" class="parser.MultipartRequestParser" scope="default" /> 
    <constant name="struts.multipart.handler" value="parser" />

这样所有的文件上传请求都会获得进度提示支持

3、spring中带进度条的文件上传。

spring的DispatcherServlet在初始化的时候会去容器中查找是否有可用的MultipartResolver,如果有的话就会使用此resolver将request转换为MultipartHttpServletRequest。

spring提供了两个resolver,CommonsMultipartResolver,StandardServletMultipartResolver。我们可以任选其一。

CommonsMultipartResolver的parseRequest方法调用commons-fileupload的ServletFileupload完成了对request的解析工作。

我们可以覆盖parseRequest方法,添加监听器:

public class MyMultipartResolver extends CommonsMultipartResolver { 
    @Override 
    public MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException { 
        String encoding = "utf-8"; 
        FileUpload fileUpload = prepareFileUpload(encoding); 
        final HttpSession session = request.getSession(); 
        fileUpload.setProgressListener(new ProgressListener() { 
            public void update(long pBytesRead, long pContentLength, int pItems) { 
                int percent = (int) (((float)pBytesRead / (float)pContentLength) * 100);

                session.setAttribute("percent", percent + "%"); 
            } 
        }); 
         
        try { 
            List<FileItem> fileItems = ((ServletFileUpload) fileUpload).parseRequest(request); 
            return parseFileItems(fileItems, encoding); 
        } 
        catch (FileUploadBase.SizeLimitExceededException ex) { 
            throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), ex); 
        } 
        catch (FileUploadException ex) { 
            throw new MultipartException("Could not parse multipart servlet request", ex); 
        } 
    } 
} 

最后在controller的配置文件中指定resolver:

<bean id="multipartResolver" class="com.springmvc.bean.MyMultipartResolver"></bean> 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值