文件上传之 commons-fileupload

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件上传之 commons-fileupload相关的知识,希望对你有一定的参考价值。

对commons fileupload上传组件的简单封装


在上一篇文章《利用Jakarta commons fileupload组件实现多文件上传》中,我介绍了commons fileupload组件的基本原理和实现方法。但是在实际操作中,我们需要分析每个FileItem,然后从该FileItem中读取该控件的name和value,显然这不符合我们的习惯。比如我们在页面上有个text文本框:

<input type="text" name="possess">


我们要取得possess传过来的value,一般我们是这么写的:

String possess = request.getParameter("possess")


但是在commons fileupload中我们却需要这么处理:

        DiskFileItemFactory factory = new DiskFileItemFactory();
        //Create a new file upload handler
        ServletFileUpload upload = new ServletFileUpload(factory);
        String possess = "";
        try {
            List items = upload.parseRequest(request);
            Iterator iterator = items.iterator();
            while(iterator.hasNext()){
                FileItem item = (FileItem)iterator.next();
                if(item.isFormField()){                    
                    String fieldName = item.getFieldName();
                    String value = item.getString();
                    if(fieldName.equals("possess")){
                       possess = value;
                    }
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }


按照上面处理的话,很是不爽,因此我想包装一下,使得使用起来符合我们的习惯。
总体设计思想:

1.我们可以像以前那样,传入控件的name,就可以取得该控件的value,因此我想可以遍历所有FileItem,然后把他们存入一个Map中(key中存入fieldname,value中存入该控件的value),这样就可以达到以上目的了。
2.在该包装类中,我们还要可以设置一些值,从而我们可以更改commons fileupload中的一些配置。

具体实现:
 

  根据以上要求,我写出了一个MutiFileUpload类,代码如下,稍后再做详细解释。
package chb.commons.fileupload.web;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;


public class MutiFileUpload extends HttpServlet{
    private static final long serialVersionUID = 670829239023754119L;
    
    protected Map<String, String> parameters;//保存普通form表单域
    protected Map<String, FileItem> files;//保存上传的文件
   
    
    private int sizeThreshold = DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD;
   
    

  private long sizeMax = -1;
    
    private String encoding = "utf-8";//字符编码,当读取上传表单的各部分时会用到该encoding

    public String getEncoding() {
        return encoding;
    }

    public void setEncoding(String encoding) {
        this.encoding = encoding;
    }

    public long getSizeMax() {
        return sizeMax;
    }

    public void setSizeMax(long sizeMax) {
        this.sizeMax = sizeMax;
    }

    public int getSizeThreshold() {
        return sizeThreshold;
    }

    public void setSizeThreshold(int sizeThreshold) {
        this.sizeThreshold = sizeThreshold;
    }

    public void parse(HttpServletRequest request){

        parameters = new HashMap<String, String>();
        files = new HashMap<String, FileItem>();
        //Create a factory for disk-based file items

       DiskFileItemFactory factory = new DiskFileItemFactory();
        //Set factory constraints
        factory.setSizeThreshold(sizeThreshold);

        //factory.setRepository(repository);
        //Create a new file upload handler

        ServletFileUpload upload = new ServletFileUpload(factory);
        //Set overall request size constraint
        upload.setSizeMax(sizeMax);
        upload.setHeaderEncoding(encoding);
        try {             List items = upload.parseRequest(request);             Iterator iterator = items.iterator();             while(iterator.hasNext()){                 FileItem item = (FileItem)iterator.next();                 if(item.isFormField()){                                         String fieldName = item.getFieldName();                     String value = item.getString();                     parameters.put(fieldName, value);                }else{                    String fieldName = item.getFieldName();                     files.put(fieldName, item);                 }             }         } catch (FileUploadException e) {             e.printStackTrace();         }     }          public String getFileName(FileItem item){         String fileName = item.getName();         fileName = replace(fileName,"\\","/");         fileName = fileName.substring(fileName.lastIndexOf("/")+1);         return fileName;     }          public static String replace(String source, String oldString, String newString) {         StringBuffer output = new StringBuffer();         int lengthOfSource = source.length();          int lengthOfOld = oldString.length();          int posStart = 0;          int pos;          while ((pos = source.indexOf(oldString, posStart)) >= 0) {             output.append(source.substring(posStart, pos));             output.append(newString);             posStart = pos + lengthOfOld;         }         if (posStart < lengthOfSource) {             output.append(source.substring(posStart));         }         return output.toString();     } }

         以上代码很简单,看过commons FileUpload组件API的程序员,应该都能看明白。值得注意一下的是:编码问题(setHeaderEncoding),这个方法是从FileUploadBase类里继承的,根据其说明,当读取上传表单的各部分时会用到该encoding,如果没有指定encoding则使用系统缺省的encoding。建议在这里设置成utf-8,并把jsp的charset也设置成utf-8,否则可能会出现乱码。
测试demo
        好了,下面我就写个简单的demo吧,说明一下MutiFileUpload的用法。
       1.新建一个jsp页面,注意设置form表单的enctype,如下:
  <form id="form1" method="post" action="../servlet/UploadServlet" enctype="multipart/form-data">
                
                <tr>
                    <td width="25%" align="right">上传图片:</td>
                    <td>                            
                        <input id="file1" type="file" NAME="file1" style="width:300px;">                                                      
                    </td>
                </tr>
                <tr>
                    <td width="25%" align="right">上传音频:</td>
                    <td>                            
                        <input id="file2" type="file" NAME="file2" style="width:300px;">                                                    
                    </td>
                </tr>
                <tr align="center" valign="middle">
                    <td height="60" colspan="2">
                        <input type="submit" id="BtnOK" value="确认上传">
  <button onclick="javascript:window.opener == null;window.close();">取消上传</button> </td>
                </tr>
                <tr align="center" valign="middle">
                    <td height="60" colspan="2">
                         <input type="text" name="possess" value="private">
                    </td>
                </tr>
        </form>
     2.新建一个UploadServlet并继承自MutiFileUpload,如下:

public class UploadServlet extends MutiFileUpload {
}
     
3.然后在post方法中如下处理:
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        parse(request);
        System.out.println(parameters.get("possess"));
        Iterator iterator = files.values().iterator();
        while(iterator.hasNext()){
            FileItem item = (FileItem) iterator.next();
            String fileName = getFileName(item);
            File file = new File("/root/upload/",fileName);
            try {
                item.write(file);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
     选择上传文件,然后我们就可以在/root/upload下看到我们上传的文件了。
        好了,先写到这里吧,具体应用时,我们可能需要很多变通,比如集成到spring,hibernate中,关键是给出一个想法,我们可以对他进行包装变更,使其更适合我们的系统。

以上是关于文件上传之 commons-fileupload的主要内容,如果未能解决你的问题,请参考以下文章

爬虫之上传文件,request如何上传文件

Web安全之文件上传漏洞

一起学SpringMVC之文件上传

文件上传之 MultipartFile

第四天——Web安全之文件上传漏洞专题.

iOS开发中上传Word文件之上传Word文件到服务器