java文件上传-使用apache-fileupload组件

 

目前文件上传的(框架)组件:Apache----fileupload 、Orialiy – COS – 2008() 、Jsp-smart-upload – 200M。

用fileupload上传文件:

需要导入第三方包:

       Apache-fileupload.jar – 文件上传核心包。

       Apache-commons-io.jar – 这个包是fileupload的依赖包。同时又是一个工具包。

核心类:

       DiskFileItemFactory – 设置磁盘空间,保存临时文件。只是一个具类。

       ServletFileUpload  - 文件上传的核心类,此类接收request,并解析reqeust

  ServletFileUpload.parseRequest(request);  --List<FileItem>   解析request

       一个FileItem就是一个标识分隔符开始 到结束。如下图:

查看DiskFileItemFactory源代码,可知

If not otherwise configured, the default configuration values are as
 follows:
   Size threshold is 10KB.
   Repository is the system default temp directory, as returned by
   System.getProperty("java.io.tmpdir")

 可知,如果不设置临时目录,会保存在默认的临时目录-  System.getProperty("java.io.tmpdir");这个目录正是windows系统的临时文件存放目录,通过环境变量,可找到这个目录

这里存放着许多临时文件。

单文件上传Servlet:

package com.lhy.upload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


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;

@WebServlet(name="Up2Servlet",urlPatterns="/Up2Servlet")
public class Up2Servlet extends HttpServlet{

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doPost(req, resp);
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTf-8");
    //获取tomcat下的up目录的路径   
    String path = getServletContext().getRealPath("/up");
    //临时文件目录
    String tmpPath = getServletContext().getRealPath("/tmp");
    
    //检查我们是否有文件上传请求
    boolean isMultipart = ServletFileUpload.isMultipartContent(req);
    //1,声明DiskFileItemFactory工厂类,用于在指定磁盘上设置一个临时目录
    DiskFileItemFactory disk = new DiskFileItemFactory(1024*10,new File(tmpPath));
    //2,声明ServletFileUpload,接收上边的临时文件。也可以默认值
    ServletFileUpload up = new ServletFileUpload(disk);
    //3,解析request
    try {
        List<FileItem> list = up.parseRequest(req);
        //如果就一个文件,
        FileItem file = list.get(0);
        //获取文件名:
        String fileName = file.getName();
        //获取文件的类型:
        String fileType = file.getContentType();
        //获取文件的字节码:
        InputStream in = file.getInputStream();
        //文件大小
        int size = file.getInputStream().available();
        //声明输出字节流
        OutputStream out = new FileOutputStream(path+"/"+fileName);
        //文件copy
        byte[] b = new byte[1024];
        int len = 0;
        while((len=in.read(b))!=-1){
            out.write(b, 0, len);
        }
        out.flush(); 
        out.close();
        
        //删除上传生成的临时文件
        file.delete();
        
        //显示数据
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter pw = resp.getWriter();
        pw.println("文件名:"+fileName);
        pw.println("文件类型:"+fileType);
        pw.println("<br/>文件大小(byte):"+size);
    } catch (FileUploadException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

  }

}

from:

<form action="<%=basePath%>Up2Servlet" method="post" enctype="multipart/form-data">
        File1:<input type="file" name="txt"><br/>
        <input type="submit"/>
    </form> 

临时文件:

服务端:

响应:

实际项目中都是有文件服务器的,公司一般都提供了上传到文件服务器接口,有的是上传一个file类型,有的是流。

多文件上传Servlet:

package com.lhy.upload;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

@WebServlet(name="Up3Servlet",urlPatterns="/Up3Servlet")
public class Up3Servlet extends HttpServlet{

  @Override
  protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    this.doPost(req, resp);
  }

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    req.setCharacterEncoding("UTf-8");
    String path = getServletContext().getRealPath("/up");
    //临时文件目录
    String tmpPath = getServletContext().getRealPath("/tmp");
    //声明disk
    DiskFileItemFactory disk = new DiskFileItemFactory();
    disk.setSizeThreshold(1024*1024);
    disk.setRepository(new File(tmpPath));
    //声明解析requst的servlet
    ServletFileUpload up = new ServletFileUpload(disk);
    try{
      //解析requst
      List<FileItem> list = up.parseRequest(req);
      //声明一个list<map>封装上传的文件的数据
      List<Map<String,String>> ups = new ArrayList<Map<String,String>>();
      for(FileItem file:list){
        Map<String,String> mm = new HashMap<String, String>();
        //获取文件名
        String fileName = file.getName();
        fileName = fileName.substring(fileName.lastIndexOf("\")+1);
        String fileType = file.getContentType();
        InputStream in = file.getInputStream();
        int size = in.available();
        //使用工具类
//        FileUtils.copyInputStreamToFile(in,new File(path+"/"+fileName));
        //file 的方法可以直接写出文件
        file.write(new File(path+"/"+fileName));
        mm.put("fileName",fileName);
        mm.put("fileType",fileType);
        mm.put("size",""+size);
        
        ups.add(mm);
        file.delete();
      }
      req.setAttribute("ups",ups);
      //转发
      req.getRequestDispatcher("/jsps/show.jsp").forward(req, resp);
      
    }catch(Exception e){
      e.printStackTrace();
    }
  }

}

表单:

<form name="xx" action="<%=basePath%>Up3Servlet" method="post" enctype="multipart/form-data">
    <table id="tb" border="1">
        <tr>
            <td>
                File:
            </td>
            <td>
                 <input type="file" name="file">
                <button onclick="_del(this);">删除</button>
            </td>
        </tr>
    </table>
    <br/>
    <input type="button" onclick="_submit();" value="上传">
    <input onclick="_add();" type="button" value="增加">
    </form>

js

<script type="text/javascript">
      function _add(){
          var tb = document.getElementById("tb");
          //写入一行
          var tr = tb.insertRow();
          //写入列
          var td = tr.insertCell();
          //写入数据
          td.innerHTML="File:";
          //再声明一个新的td
          var td2 = tr.insertCell();
          //写入一个input
          td2.innerHTML='<input type="file" name="file"/><button onclick="_del(this);">删除</button>';
      }
      function _del(btn){
          var tr = btn.parentNode.parentNode;
          //alert(tr.tagName);
          //获取tr在table中的下标
          var index = tr.rowIndex;
          //删除
          var tb = document.getElementById("tb");
          tb.deleteRow(index);
      }
      function _submit(){
          //遍历所的有文件
          var files = document.getElementsByName("file");
          if(files.length==0){
              alert("没有可以上传的文件");
              return false;
          }
          for(var i=0;i<files.length;i++){
              if(files[i].value==""){
                  alert("第"+(i+1)+"个文件不能为空");
                  return false;
              }
          }
        document.forms['xx'].submit();
      }
  </script>

show.jsp:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
  </head>
  <body>
        <p>以下是你上传的文件</p>
        <c:forEach items="${ups}" var="mm">
            文件名:${mm.fileName}<br/>
            类型:${mm.fileType}<br/>
            大小:${mm.size}(bytes)
            <hr/>
        </c:forEach>    
  </body>
</html>

测试,上传3张图片:

up目录L:

响应:

多文件上传,如果是同一个文件,会覆盖以前的,需要重命名,具体自己实现吧,如用uuid

//获取扩展
String extName = fileName.substring(fileName.lastIndexOf("."));//.jpg
//UUID
String uuid = UUID.randomUUID().toString().replace("-", "");
//新名称
String newName = uuid+extName;


限制只能上传图片:

@Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    req.setCharacterEncoding("UTF-8");
    
    String path = getServletContext().getRealPath("/up");
    //项目里建的临时目录,存放临时文件,linux适用
    String tmpPath = getServletContext().getRealPath("/tmp");
    DiskFileItemFactory disk = 
        new DiskFileItemFactory(1024*10,new File(tmpPath));
    ServletFileUpload up = new ServletFileUpload(disk);
    try{
      List<FileItem> list = up.parseRequest(req);
      //只接收图片*.jpg-iamge/jpege.,bmp/imge/bmp,png,
      List<String> imgs = new ArrayList<String>();
      for(FileItem file :list){
        if(file.getContentType().contains("image/")){
          String fileName = file.getName();
          //如果是原始方式Servlet上传,IE:c:\xxx\aa.jpg,但是用框架ie也是aa.jpg,这句没啥用好似
          fileName = fileName.substring(fileName.lastIndexOf("\")+1);
          //获取扩展
          String extName = fileName.substring(fileName.lastIndexOf("."));//.jpg
          //UUID
          String uuid = UUID.randomUUID().toString().replace("-", "");
          //新名称
          String newName = uuid+extName;
          
          FileUtils.copyInputStreamToFile(file.getInputStream(),
              new File(path+"/"+newName));
          //放到list
          imgs.add(newName);
        }
        file.delete();
      }
      req.setAttribute("imgs",imgs);
      req.getRequestDispatcher("/jsps/imgs.jsp").forward(req, resp);
    }catch(Exception e){
      e.printStackTrace();
    }
  
  }

imgs.jsp:显示上传的图片

<body>
        <p>图片是:</p>
        <c:forEach items="${imgs}" var="img">
            <img src="<c:url value='/up/${img}'/>"></img>
        </c:forEach>
  </body>


处理表单域中普通的input:

指定表单的enctype="multipart/form-data" 后,表单将会以二进制请求,普通的input 用request.getParameter("xxx");为null,fileupload能很方便处理普通表单域:

FileItem接口方法:

 void

delete()
          删除保存在临时目录中的文件。

 

 

String

getContentType()  获取文档的类型
          Returns the content type passed by the browser or null if not defined.

 String

getFieldName() 获取字段的名称,即name=xxxx
          Returns the name of the field in the multipart form corresponding to this file item.

<input type=”file” name=”img”/>

 InputStream

getInputStream()
          Returns an InputStream that can be used to retrieve the contents of the file.

 String

getName()
          Returns the original filename in the client's filesystem, as provided by the browser (or other client software).

获取文件名称。

如果是在IE获取的文件为 c:aaaaaaxxx.jpg –即完整的路径。

非IE;文件名称只是 xxx.jpg

 

 

long

getSize()  获取文件大小 相当于in.avilivable();
          Returns the size of the file item

如果你上传是一普通的文本元素,则可以通过以下方式获取元素中的数据

<form enctype=”multipart/form-data”>

    <input type=”text” name=”name”/>

String

getString()  用于获取普通的表单域的信息。
          Returns the contents of the file item as a String, using the default character encoding.(IOS-8859-1)

 String

getString(String encoding) 可以指定编码格式
          Returns the contents of the file item as a String, using the specified encoding.

 void

write(File file) 直接将文件保存到另一个文件中去。
          A convenience method to write an uploaded item to disk.

以下文件用判断一个fileItem是否是file(type=file)对象或是text(type=text|checkbox|radio)对象:

 boolean

isFormField()  如果是text|checkbox|radio|select这个值就是true.
          Determines whether or not a FileItem instance represents a simple form field.

Servlet:

package com.lhy.upload;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet(name="UpDescServlet",urlPatterns="/UpDescServlet")
public class UpDescServlet extends HttpServlet {
  
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    //可以获取中文的文件名
    request.setCharacterEncoding("UTF-8");
    //项目真实路径
    String path = getServletContext().getRealPath("/up");
    //声明disk
    DiskFileItemFactory disk =  new DiskFileItemFactory();
    disk.setRepository(new File("D:/tmp"));//临时文件目录
    try{
      //声明解析requst的servlet
      ServletFileUpload up = new ServletFileUpload(disk);
      //解析requst
      List<FileItem> list = up.parseRequest(request);
      //声明一个map用于封装信息
      Map<String,Object> img = new HashMap<String, Object>();
      for(FileItem file:list){
        //第一步:判断是否是普通的表单项
        if(file.isFormField()){
          //可以读取多个普通的input
          String fileName = file.getFieldName();//<input type="text" name="desc">=desc
          String value = file.getString("UTF-8");//默认以ISO方式读取数据
          System.err.println(fileName+"="+value);
          //放入图片的说明
          img.put(fileName,value);
        }else{//说明是一个文件
          String fileName = file.getName();//以前的名称
          //处理文件名
          fileName = fileName.substring(fileName.lastIndexOf("\")+1);
          img.put("oldName",fileName);
          //修改名称
          String extName = fileName.substring(fileName.lastIndexOf("."));
          String newName = 
              UUID.randomUUID().toString().replace("-", "")+extName;
          //保存新的名称
          img.put("newName",newName);
          file.write(new File(path+"/"+newName));
          System.err.println("文件名是:"+fileName);
          System.err.println("文件大小是:"+file.getSize());
          img.put("size",file.getSize());
          file.delete();
        }
      }
      //将img=map放到req
      request.setAttribute("img",img);
      //转发
      request.getRequestDispatcher("/jsps/desc.jsp").forward(request, response);
    }catch(Exception e){
      e.printStackTrace();
    }
  }

}

form表单:

<form action="<c:url value='/UpDescServlet'/>" method="post" 
                                            enctype="multipart/form-data">
        你的图片:<input type="file" name="img"><br /> 
        说明:<input type="text" name="desc"/><br/>
        说明2:<input type="text" name="desc2"/><br/>
        <input type="submit" />
    </form>

desc.jsp:

<body>
    <p>请选择图片:名称(以前的名称oldName),顯示這張圖片newName。图片大小size,图片的说明desc</p>
    ${img.oldName}<br/>
    ${img.size}<br/>
    ${img.desc}<br/>
    ${img.desc2}  <br/>
    <img width="300" height="300" src="<c:url value='/up/${img.newName}'/>"></img>
    <hr/>
    <p>url:http://localhost:8080/day22/jsps/desc.jsp
    <img width="300" height="300" src="<c:url value='/up/8.jpg'/>"/>
</body>
</html>



性能提升?使用FileItemIterator上传:

package com.lhy.upload;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;

@WebServlet(name="FastServlet",urlPatterns="/FastServlet")
public class FastServlet extends HttpServlet{

  @Override
  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
long start = new Date().getTime();
    req.setCharacterEncoding("UTF-8");
    String path = getServletContext().getRealPath("/up");
    DiskFileItemFactory disk = new DiskFileItemFactory();
    try {
      ServletFileUpload up = new ServletFileUpload(disk);
      //迭代器模式
      FileItemIterator iter = up.getItemIterator(req);
      while(iter.hasNext()){
        FileItemStream item = iter.next();
        String fileName = item.getName();
        fileName = fileName.substring(fileName.lastIndexOf("\")+1);
        InputStream in = item.openStream();
        FileUtils.copyInputStreamToFile(in, new File(path+"/"+fileName));
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    long end = new Date().getTime();
    System.out.println(end - start);
  }
  
}

不知道能不能提升性能,我分别用这个和上边的上传了一个myeclipse2014安装包1.1G,用上传前后的毫秒差计算,结果显示这个耗时100930,上边的方法耗时54240,并没有提升性能反而满了,迭代器模式不知道能不能提升性能,。。

 限制上传文件的大小:

ServletFileUpload类的方法:

1:限制总文件的大小 。    如 上传10文件,设置最多总上传大小为100M。

      

void

setSizeMax(long sizeMax)
          Sets the maximum allowed size of a complete request, as opposed to setFileSizeMax(long).

       2:设置第每一个文件的大小 ,如果设置每 一个文件大小10M。

 void

setFileSizeMax(long fileSizeMax)
          Sets the maximum allowed size of a single uploaded file, as opposed to getSizeMax().

 两者一般设置一个就行了,可以catch到这个异常给提示信息。

ServletFileUpload up = new ServletFileUpload(disk);
      //限制总文件的大小,如果上传多个文件
      up.setSizeMax(1024*1024*100);//限制上传最大100M
      //设置第每一个文件的大小  两者有一个即可
//      up.setFileSizeMax(1024*1024);

有些上传插件,如插件fileuploadify 在页面就可以限制上传文件。

原文地址:https://www.cnblogs.com/lihaoyang/p/7295434.html