Commons FileUpload

一) 基础简介:
    1、FileUpload 是 Apache commons下面的一个子项目,用来实现Java环境下面的 文件上传功能,与常见的SmartUpload齐名。
    2、组件FileUpload依赖于Commons IO组件。 目前FileUpload的最新版本是1.2.2 ,对于此版本官方推荐的依赖的IO组件版本是1.3.2
    3、FileUpload 是基于RFC1867协议实现的。
    4、API: http://commons.apache.org/fileupload/apidocs/index.html

二)RFC1867协议:
    RFC1867协议作为HTTP协议的附加协议,详细描述了File Upload的规则。RFC1867协议主要是在HTTP协议的基础上为INPUT标签增加了file属性,同时限定了Form的method必须为POST,ENCTYPE必须为multipart/form-data,当然还增加了一些与此相关属性。
    比如value属性表示默认的上传文件的文件名(无文件上传时生效)
         width表示默认的显示文件名的长度
         height表示显示上传文件的个数

    例子:
    <FORM ACTION="http://server.dom/cgi/handle" ENCTYPE="multipart/form-data"  METHOD=POST>
     What is your name? <INPUT TYPE=TEXT NAME=field1>
     What files are you sending? <INPUT TYPE=FILE NAME=pics>
    </FORM>
    假设用户在name一栏里输入"Joe Blow",上传了一个文件名叫"file1.txt"的文件。那么浏览器将发送的包格式会是这样:
        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"; filename="file1.txt"
        Content-Type: text/plain

         ... contents of file1.txt ...
        --AaB03x--
    如果上传的文件中还包含一个叫"file2.gif"的图片,那么包格式将会是这样:
        Content-type: multipart/form-data, boundary=AaB03x

        --AaB03x
        content-disposition: form-data; name="field1"

        Joe Blow
        --AaB03x
        content-disposition: form-data; name="pics"
        Content-type: multipart/mixed, boundary=BbC04y

        --BbC04y
        Content-disposition: attachment; filename="file1.txt"
        Content-Type: text/plain

        ... contents of file1.txt ...
        --BbC04y
        Content-disposition: attachment; filename="file2.gif"
        Content-type: image/gif
        Content-Transfer-Encoding: binary

          ...contents of file2.gif...
        --BbC04y--
        --AaB03x--

    总结:
    RFC1867对HTTP头作了适当地变更,但变更很小。首先content-type头由以前的:
      content-type: application/x-www-form-urlencoded
    变为
      content-type: multipart/form-data; +空格+ boundary=AaB03x
    即增加了boundary,所谓的boundary其实就是分割线,RFC1867利用boundary分割HTTP实体数据。boundary中数字字符区是随机生成的。

三)代码样例:
    最简单的一个例子:
     
      // Create a factory for disk-based file items 
      FileItemFactory factory = new DiskFileItemFactory(); 
      // Create a new file upload handler 
      ServletFileUpload upload = new ServletFileUpload(factory); 
      // Parse the request 
      List <FileItem> items = upload.parseRequest(request); 

    如上我们就把request的所有信息包括上传文件的信息都转换到items这个对象里去了。

    再增加一点点控制:
     
      // Create a factory for disk-based file items 
      DiskFileItemFactory factory = new DiskFileItemFactory(); 
      // Sets the size threshold beyond which files are written directly to disk. 
      factory.setSizeThreshold(yourMaxMemorySize);
      // Sets the directory used to temporarily store files that are larger than the configured size threshold. 
      factory.setRepository(yourTempDirectory); 
      // Create a new file upload handler 
      ServletFileUpload upload = new ServletFileUpload(factory); 
      // Sets the maximum allowed size of a complete request 
      upload.setSizeMax(yourMaxRequestSize); 
      // Parse the request 
      List <FileItem> items = upload.parseRequest(request);

   
    FileItem的处理:
     
      Iterator iter = items.iterator(); 
      while (iter.hasNext()) { 
        FileItem item = (FileItem) iter.next(); 
        if (item.isFormField()) { // Process a regular form field 
            String name = item.getFieldName(); 
            String value = item.getString(); 
        } else { // Process a file upload 
            String fieldName = item.getFieldName(); 
            String fileName = item.getName(); 
            String contentType = item.getContentType(); 
            boolean isInMemory = item.isInMemory(); 
            long sizeInBytes = item.getSize(); 
        } 
      }

     这里有必要对FileItem的一些方法做进一步的介绍:
     public boolean isFormField() -- 用于判断 FileItem 类对象封装的数据是否属于一个普通表单字段,还是属于一个文件表单字段,如果是普通表单字段则返回 true,否则返回 false。
     public String getName() -- 依据RFC1867协议返回的是filename的内容。以上文例子为例,返回值将是“file1.txt” 或 “file2.gif”。如果 FileItem 类对象对应的是普通表单字段,getName 方法将返回 null。
     public String getFieldName() -- 依据RFC1867协议返回的是name的内容。以上文例子为例,返回值将是“field1” 或 “pics”。
     public void write(File  file) -- 用于将 FileItem 对象中保存的主体内容保存到某个指定的文件中。如果 FileItem对象中的主体内容是保存在某个临时文件中,该方法顺利完成后,临时文件有可能会被清除。该方法也可将普通表单字段内容写入到一个文件中,但它主要用途是将上传的文件内容保存在本地文件系统中。
     public boolean isInMemory() -- 用来判断 FileItem 类对象封装的主体内容是存储在内存中,还是存储在临时文件中,如果存储在内存中则返回 true,否则返回false。
     public void delete() -- 用来清空 FileItem 类对象中存放的主体内容,如果主体内容被保存在临时文件中,delete 方法将删除该临时文件。

    上传文件的保存:
    
     File uploadedFile = new File(...);
     item.write(uploadedFile);


四)注意点:
对于fileupload,一共有3种上传文件的处理方式:
    DiskFileUpload, ServletFileUpload, PortlerFileUpload
他们的区别是:
    ServletFileUpload 最常用的类,大多情况我们就用它了。
    DiskFileUpload 已被标记为Deprecated,由ServletFileUpload取代。
    PortletFileUpload  需配合portlet的api一起使用(本人至今没用过 = =!)

你可能感兴趣的:(java,apache,fileupload,commons,RFC1867)