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:\aaa\aaa\xxx.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 在頁面就可以限制上傳文件。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM