`
michaelxz
  • 浏览: 21113 次
  • 性别: Icon_minigender_1
  • 来自: 遂宁
社区版块
存档分类
最新评论

common-fileupload 分析

阅读更多

以前项目里面都经常用到上传的功能,从最早的smartFileUpload到apache 的common-fileupload.但是运用归运用,还是要了解实质才行,下面以common-fileupload为例子来讲解

首先要了解上传的本质,首先上传需要在jsp页面的form标签中配置enctype="multipart/form-data"

因为这样配置后,在http请求发出时才会以2进制的方式去传输上传文件

 

当请求到达服务端后,在action我们的代码是

DiskFileItemFactory factory = new DiskFileItemFactory();
// 当文件大小超过300k时,就在磁盘上建立临时文件
factory.setSizeThreshold(300000);
//设计文件上传的临时目录
factory.setRepository(new File("D:\\temp"));
ServletFileUpload upload = new ServletFileUpload(factory);
// 文件大小不能超过20M
upload.setSizeMax(20000000);

 

用struts2做上传的朋友都知道,在struts2的property文件中可以配置上传文件大小和上传的临时文件目录,其实struts2也是这样的实现

 

在这里我们同时还可以使用upload.setProgressListener(new ProgressListener())来监控上传的进度,一般情况下都是采用ajax来同步客户端和服务端的数据

具体可以参考:http://www.ibm.com/developerworks/cn/opensource/os-cn-agajax/

 

在设定好了一系列参数后,我们就要开始主要的方法了

ServletFileUpload.parseRequest(Request  request)

 

  public List /* FileItem */ parseRequest(HttpServletRequest request)
    throws FileUploadException {
        return parseRequest(new ServletRequestContext(request));
    }

 

 

 public List /* FileItem */ parseRequest(RequestContext ctx)
            throws FileUploadException {
        try {
            FileItemIterator iter = getItemIterator(ctx);//这个方法是相当重要的,在下面介绍
            List items = new ArrayList();
            FileItemFactory fac = getFileItemFactory();
            if (fac == null) {
                throw new NullPointerException(
                    "No FileItemFactory has been set.");
            }
            while (iter.hasNext()) {
                FileItemStream item = iter.next();
                FileItem fileItem = fac.createItem(item.getFieldName(),
                        item.getContentType(), item.isFormField(),
                        item.getName());
                try {
//将2个流copy,item.openStream()是request中的流,fileItem.getOutputStream()是准备向指定上传文件夹写文件的流
//fileItem.getOutputStream() 中就设定了临时文件的路径 下面将介绍
                   Streams.copy(item.openStream(), fileItem.getOutputStream(),
                            true);
                } catch (FileUploadIOException e) {
                    throw (FileUploadException) e.getCause();
                } catch (IOException e) {
                    throw new IOFileUploadException(
                            "Processing of " + MULTIPART_FORM_DATA
                            + " request failed. " + e.getMessage(), e);
                }
                if (fileItem instanceof FileItemHeadersSupport) {
                    final FileItemHeaders fih = item.getHeaders();
                    ((FileItemHeadersSupport) fileItem).setHeaders(fih);
                }
                items.add(fileItem);
            }
//返回FileItem的集合(关于FileItem的实现类,大家可以参考DiskFileItem)
            return items;
        } catch (FileUploadIOException e) {
            throw (FileUploadException) e.getCause();
        } catch (IOException e) {
            throw new FileUploadException(e.getMessage(), e);
        }
    }

 

  

  public OutputStream getOutputStream()
        throws IOException {
        if (dfos == null) {
            File outputFile = getTempFile();
            dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
        }
        return dfos;
    }

    protected File getTempFile() {
      //如果没设置临时目录,就用System.getProperty("java.io.tmpdir")
        if (tempFile == null) {
            File tempDir = repository;
            if (tempDir == null) {
                tempDir = new File(System.getProperty("java.io.tmpdir"));
            }
      //设计临时文件名
            String tempFileName =
                "upload_" + UID + "_" + getUniqueId() + ".tmp";

            tempFile = new File(tempDir, tempFileName);
        }
        return tempFile;
    }

 

 

  public FileItemIterator getItemIterator(RequestContext ctx)
    throws FileUploadException, IOException {
        return new FileItemIteratorImpl(ctx);
    }

 

  FileItemIteratorImpl(RequestContext ctx)
                throws FileUploadException, IOException {
            if (ctx == null) {
                throw new NullPointerException("ctx parameter");
            }

            String contentType = ctx.getContentType();
//这就是为什么需要将请求写成multipart/form-data
//  public static final String MULTIPART = "multipart/"  
            if ((null == contentType)
                    || (!contentType.toLowerCase().startsWith(MULTIPART))) {
                throw new InvalidContentTypeException(
  "the request doesn't contain a "  + MULTIPART_FORM_DATA  + " or "   + MULTIPART_MIXED  + " stream, content type header is "+ contentType);
            }

            InputStream input = ctx.getInputStream();

//此处的sizeMax就是我们在action中set进去的值
            if (sizeMax >= 0) {
                int requestSize = ctx.getContentLength();
                if (requestSize == -1) {
                    input = new LimitedInputStream(input, sizeMax) {
                        protected void raiseError(long pSizeMax, long pCount)
                                throws IOException {
                            FileUploadException ex =
                                new SizeLimitExceededException(
                                    "the request was rejected because"   + " its size (" + pCount      + ") exceeds the configured maximum" + " (" + pSizeMax + ")",  pCount, pSizeMax);
                            throw new FileUploadIOException(ex);
                        }
                    };
                } else {
//此处主要是判断上传文件的大小是否超过了设定值
                    if (sizeMax >= 0 && requestSize > sizeMax) {
                        throw new SizeLimitExceededException(
                                "the request was rejected because its size ("
 + requestSize   + ") exceeds the configured maximum ("+ sizeMax + ")", requestSize, sizeMax);
                    }
                }
            }

 

当返回了这个FileItem集合后,我们的代码如下

List<FileItem> items = getUploadFileIteams(request,pushObj,goUrl);

	for (FileItem item : items) {
		File file = new File(realPath);
		item.write(file);
	}

这里就将文件真正写到了服务器上

再最后把item.write这个方法贴下吧,大家就更明白了

public void write(File file) throws Exception {
        if (isInMemory()) {
            FileOutputStream fout = null;
            try {
                fout = new FileOutputStream(file);
                fout.write(get());
            } finally {
                if (fout != null) {
                    fout.close();
                }
            }
        } else {
            File outputFile = getStoreLocation();
            if (outputFile != null) {
                // Save the length of the file
                size = outputFile.length();
              //看到下面的代码,大家就应该明白了吧
                if (!outputFile.renameTo(file)) {
                    BufferedInputStream in = null;
                    BufferedOutputStream out = null;
                    try {
                        in = new BufferedInputStream(
                            new FileInputStream(outputFile));
                        out = new BufferedOutputStream(
                                new FileOutputStream(file));
                        IOUtils.copy(in, out);
                    } finally {
                        if (in != null) {
                            try {
                                in.close();
                            } catch (IOException e) {
                                // ignore
                            }
                        }
                        if (out != null) {
                            try {
                                out.close();
                            } catch (IOException e) {
                                // ignore
                            }
                        }
                    }
                }
            } else {
                /*
                 * For whatever reason we cannot write the
                 * file to disk.
                 */
                throw new FileUploadException(
                    "Cannot write uploaded file to disk!");
            }
        }
    }

 关于临时文件的删除,我们可以考虑2种方式,利用DiskFileItem#delete方法手动删除,也可以用

 <listener>
   <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class>
</listener>

 

关于FileCleanerCleanup的执行大家可以看看org.apache.commons.io.FileCleaningTracker的实现

分享到:
评论
3 楼 momantang 2009-11-13  
mark too
2 楼 jk8341444 2009-09-29  
写的一点思路没有
1 楼 loocao 2009-08-25  
mark...

相关推荐

    利用Common-fileupload封装的文件上传组件...附上源码.

    首先,我们来看一下标题:“利用Common-fileupload封装的文件上传组件...附上源码”。这表明我们将讨论如何使用这个库来创建一个文件上传系统,并且提供有源码可供参考。通过`Common-fileupload`,我们可以实现用户...

    使用Common-fileUpload 上传文件 读取文件内容

    读取文件内容后,你可以根据业务需求对内容进行处理,例如存储到数据库、进行文本分析等。 4. **错误处理与安全注意事项** 在处理文件上传时,务必考虑错误处理和安全性。例如,确保文件大小限制在合理范围内,...

    common-fileupload控件不能删除临时文件的原因分析

    common-fileupload控件不能删除临时文件的原因分析 1.分析原因 2.出现条件 3.过程分析 4.解决办法

    java中common-fileupload 上传文件demo

    下面,我们将深入探讨如何使用`Commons FileUpload`库在Java中实现文件上传功能,并基于提供的"文件上传demo"进行分析。 首先,我们需要添加`Commons FileUpload`的依赖到我们的项目中。如果你使用的是Maven,可以...

    commons-fileupload-1.3.2-src 源码

    通过分析"commons-fileupload-1.3.2-src"源码,我们可以更深入地理解其内部实现,包括解析流程、内存管理、错误处理机制等,并可能发现性能优化或定制化服务的机会。对于Java Web开发者来说,熟悉并掌握这个库能极大...

    dom4j、common-fileupload、hibernate、jdom、log4j、proxool、spring、struts、webwork等工具、框架源码

    2. **Common-FileUpload**: 这是Apache Commons的一个模块,用于处理HTTP协议中的多部分文件上传请求。它简化了在Web应用程序中接收和处理大文件上传的过程,支持分块上传和错误处理。 3. **Hibernate**: Hibernate...

    common-fileupload的详细介绍

    本节分析了Apache文件上传组件的实现思想和主要的源代码,建议读者参照本节的方式多分析一些开源项目。

    commons-fileupload文件上传组件中文教程--张孝祥写的

    #### 四、源码分析 1. **设计模式**:Apache Commons FileUpload采用了工厂模式和策略模式来设计。 2. **模块划分**:组件内部模块化清晰,便于扩展和维护。 3. **异常处理**:提供了丰富的异常类型,有助于开发者...

    commons-fileupload文档及源代码.rar

    `common_fileupload详解.doc`文档应该提供了关于库的详细使用指南、API参考和示例代码。通过阅读文档,你可以快速掌握如何在项目中集成和使用`commons-fileupload`。 总的来说,Apache Commons FileUpload库极大地...

    Commons-io-fileload源码和组件

    在这个主题中,我们将深入探讨其中的两个关键组件:`Commons-IO` 和 `Commons-Fileupload`,以及它们的源码分析。 **Apache Commons IO** `Commons-IO` 是一组与I/O相关的实用工具类,它弥补了Java标准库中对输入/...

    commonfileupload.zip 文件上传功能

    `common-fileupload`标签可能指的是Apache Commons FileUpload库,这是一个Java库,专门用于处理基于Servlet的文件上传。它能处理多部分/表单数据,使开发人员能够轻松地处理文件上传请求。使用此库,我们可以通过...

    struts2实现文件上传

    例如 `HttpServletReques`t 和 `common-fileupload` 相关的库被用来处理上传请求。 #### 五、小结 Struts2 支持强大的文件上传功能,这得益于其对 Apache Commons FileUpload 和 Commons IO 库的支持。通过上述...

    SSH 框架所需JAR包

    1.commons-fileupload.jar(commons项目中的关于文件上传的包, struts2.1.6版本后必须加入此文件) 2.commons-io.jar(commons项目(commons项目就是java中一些常用的公共的组件)的io子项目,是处理异常的) 3....

    SSH 项目 整合jar包

    1.commons-fileupload.jar(commons项目中的关于文件上传的包, struts2.1.6版本后必须加入此文件) 2.commons-io.jar(commons项目(commons项目就是java中一些常用的公共的组件)的io子项目,是处理异常的) 3....

    web项目常用jar包及说明.zip

    1.commons-fileupload.jar(commons项目中的关于文件上传的包, struts2.1.6版本后必须加入此文件) 2.commons-io.jar(commons项目(commons项目就是java中一些常用的公共的组件)的io子项目,是处理异常的) 3....

    Java无组件上传Java无组件上传

    - **文件删除问题**:在处理完毕后,如果没有使用`common-fileupload.jar`等库中的删除方法,可能会导致临时文件未被正确清理。需要注意的是,即使没有显式调用删除方法,通常操作系统也会在文件句柄关闭后清理这些...

    struts2文件上传(java)

    首先,文件上传的核心依赖于两个Java库,即`common-io-1.4.jar`和`commons-fileupload-1.2.1.jar`。`Commons IO`库提供了一系列与输入/输出操作相关的工具类,而`Commons FileUpload`则专门用于处理HTTP请求中的多...

    项目小结.doc

    作者了解到common-fileUpload能更好地处理中文乱码。 7. **前后端交互**: - 在后台设置的属性要传递到前端显示,通过隐藏字段(hidden input)作为中介,然后通过JavaScript的getElementById获取并显示,展示了...

    ssh框架的jar包,分析

    - **common-annotations.jar**:提供JSR-250中的注解支持,如@PostConstruct、@PreDestroy等,用于定义生命周期回调方法。 - **spring-webmvc-struts.jar**:整合了Struts和Spring MVC,用于Web层的开发。 - **log4j...

Global site tag (gtag.js) - Google Analytics