上传功能几乎是每个web工程必备的,比如注册功能的头像上传,文章的背景音乐上传,视频上传等。
本章主要讲解怎样通过java技术实现上传功能。

一,上传表单
      用户通过form表单把数据提交给服务端,服务端通过request.getParameter()得到,但是这个api只能得到
      字符串类型的数据,而文件是二进制数据,所以通过这个api肯定不能接收到用户的文件。
      html表单元素提供<input type='file' name='photo'  />这个标签,可以在网页上显示一个上传的文件筐和文件选择按钮,如下:
spacer.gif
      这个框也必须包含在form表单里面,并且form表单必须满足两个条件:
     1,表单提交方式必须设置为post,即method="post"
     2,表单必须加上二进制的设置,即加上enctype="multipart/form-data"这个属性

    所以一个包含了上传表单的form,看起来应该是这样的:
<form action="<%=path%>/servlet/RegisterServlet"  method="post" enctype="multipart/form-data"   >
       <table>
         <tr>
            <td>照片</td>
            <td><input type="file" name="photo" /></td>
         </tr>
         <tr>
             <td><input type="submit" value="注册" /></td>
             <td>&nbsp;</td>
          </tr>
     </table>
     </form>
二,服务端接收用户上传的文件
       刚才我们说过,使用request.getParameter("")是不能得到用户上传的文件的,必须借助其他库或组件才能实现。
       目前最为流行的上传下载组件是 Apache基金会旗下的commons-fileupload,这个组件需要依赖两个jar包:commons-fileupload和
       commons-io,所以在做这个功能之前需要下载这两个包并复制到WebRoot的lib文件夹下。
       下面我们看看怎样使用commons-fileupload获得用户上传的文件。
       首先在工程的WebRoot下建立一个文件夹用于存放用户上传的文件,取名uploadfile
       然后新建一个Servlet,取名RegisterServlet,在doPost方法里面编写如下代码:
//获得文件项的工厂类
                FileItemFactory factory = new DiskFileItemFactory();
               //通过工厂类创建一个Servlet文件上传类
ServletFileUpload upload = new ServletFileUpload(factory);
try {
 //把请求中的每个数据读取出来,并且封装成FileItem对象,然后存入List集合里面
    List<FileItem> items = upload.parseRequest(request);
   for(FileItem item:items){
    //非常规表单,即上传表单
    if(!item.isFormField()){
//getRealPath这个方法返回uploadfile这个文件夹在当前web项目下的绝对路径
    String folder=request.getRealPath("uploadfile");
                                //得到文件的大小,单位是byte
    long filesize=item.getSize();
    System.out.println("folder: "+folder);
    System.out.println("filename: "+filename);
    System.out.println("filesize: "+filesize);
    if(filesize>0){
                //构造这个文件,这个时候此文件还并不存在
    File file=new File(folder+File.separator+filename);
                    //用这个文件对象填充上面的file对象
    item.write(file);
    }
    }
   }
} catch (Exception e) {
e.printStackTrace();
}
       item.isFormField()这个方法用于判断是否是常规的表单域,假如false,则说明是二进制数据,假如是true,说明是其他的文本表单数据。所以这里当判断某个域是二进制数据,才去接收这个二进制文件。
       至此,文件上传功能就算完成了

三,上传文件和提交文本信息
       在注册的时候,往往既让你提交基本信息,比如姓名,年龄等,还会让你同时上传头像图片。
       那这样的功能如何做呢?
       我们的第一想法是:在Servlet里面通过request.getParameter("")得到文本信息,通过common-fileupload得到上传数据不就完了.
       首先我们在jsp中加几个文本输入框,让这个表单代码如下:
<form action="<%=path%>/servlet/RegisterServlet"  method="post" enctype="multipart/form-data"   >
        <table>
        <tr>
       <td>姓名</td><td><input type="text" name="username" /></td>
     </tr>
     <tr>
       <td>住址</td><td><input type="text" name="address" /></td>
     </tr>
     <tr>
       <td>照片</td>
       <td><input type="file" name="photo" /></td>
     </tr>
     <tr>
       <td><input type="submit" value="注册" /></td>
       <td>&nbsp;</td>
     </tr>
     </table>
     </form>
  这里既有文本框又有文件上传框
  然后改造一下之前的Servlet:
   String username=request.getParameter("username");
   String address=request.getParameter("address");
   System.out.println("用户名: "+username);
   System.out.println("住址:"+address);

 然后测试一下,会发觉控制台会输出
  用户名: null
  住址:null
也就是说此时并不能接收到用户提交的文本信息了。
这就是问题所在:一旦form表单设置了 enctype="multipart/form-data",那么就不能使用request.getParameter()得到用户提交的文本信息了
而common-fileupload可以帮我们解决这个问题,刚才我们通过item.isFormField()来判断是否是文本表单数据,假如true的话,说明就是文本表单信息了,所以
我们可以把之前的Servlet改造成如下所示:
//获得文件项的工厂类
                FileItemFactory factory = new DiskFileItemFactory();
        //通过工厂类创建一个Servlet文件上传类
ServletFileUpload upload = new ServletFileUpload(factory);
try {
  //把请求中的每个数据读取出来,并且封装成FileItem对象,然后存入List集合里面
    List<FileItem> items = upload.parseRequest(request);
    for(FileItem item:items){
     //非常规表单,即上传表单
     if(!item.isFormField()){
//getRealPath这个方法返回uploadfile这个文件夹在当前web项目下的绝对路径
         String folder=request.getRealPath("uploadfile");
                       //得到文件的大小,单位是byte
                       long filesize=item.getSize();
                      System.out.println("folder: "+folder);
                      System.out.println("filename: "+filename);
                      System.out.println("filesize: "+filesize);
                      if(filesize>0){
                             //构造这个文件,这个时候此文件还并不存在
                File file=new File(folder+File.separator+filename);
                             //用这个文件对象填充上面的file对象
                           item.write(file);
                     }
       }else{
    //非上传表单元素
    System.out.println(item.getFieldName()+" : "+item.getString());
}
    }
} catch (Exception e) {
e.printStackTrace();
}

测试一下,控制台会输出如下结果:

用户名: null

住址:null

username : admin

address : admin

folder: E:\apache-tomcat-6.0.16\webapps\FileUpload\uploadfile

filename: 57fbd2efc17eb5c41e3dd1070e031243.jpg

filesize: 194927

最后上传的图片会放到folder后面的路径里面。