• About Me
  • Java基礎教學
  • 部落格聯播

[教學]jsp Web的檔案上傳-FileUpload

分類: Java, jsp, 程式 時間:2010/3/22 瀏覽:4,376 瀏覽數 — 33 回應

這是一個簡單的fileupload程式,把整個upload動作都包裝在UploadTool這個class裡,而在jsp裡再call此class來做檢查及上傳等動作。jar檔需放置WEB-INF/lib/裡,而程式complier後放置WEB-INF/classes/toolkie/裡。

首先需要二個第三方的jar檔 Apache FiluploadApache common io 都下載Binary的jar檔就可以了

檔案的配制結構如下圖:

tomcat文件配制圖

再來利用下面的程式來進行上傳作業


UploadTool.java

package toolkie;
 
import java.io.File;
import java.io.UnsupportedEncodingException;
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;
import java.util.*;
 
public class UploadTool {
    private int buffersize = 4096;
    private int SizeMax = 1024 * 1024;// 1Mbyte最大檔案大小
    private File tempfile = null;
    private String def_upload_dir = null;
 
    // 用來存parameter
    private Map map = null;
    private Map uploadlist = null;
 
    // 處始化時把給request把所有的值取出,存入map
    public UploadTool(HttpServletRequest request) throws FileUploadException,
            UnsupportedEncodingException {
 
        map = new HashMap();
        uploadlist = new HashMap();
 
        // 建立一個以disk-base的檔案物件
        DiskFileItemFactory factory = new DiskFileItemFactory();
 
        // 初始化內容
        // 傳送所用的buffer空間
        factory.setSizeThreshold(buffersize);
        // The directory in which temporary files will be located.
 
        factory.setRepository(tempfile);
 
        // 建立一個檔案上傳的物件
        ServletFileUpload upload = new ServletFileUpload(factory);
 
        // 最大檔案大小
        upload.setSizeMax(SizeMax * 10);
 
        // 每一個Fileitem代表一個form上傳的物件內容ex input type="text"
        List items = null; // 會產生 FileUploadException
        // 把資料從request取出
        items = upload.parseRequest(request); // Parse the request
 
        Iterator iter = items.iterator();
 
        while (iter.hasNext()) {// 先把所有參數取得而不先write to file
            FileItem item = (FileItem) iter.next();
            // 一般文字欄位
            if (item.isFormField()) {
                map.put(item.getFieldName(), item.getString("Big5"));
                System.out.println("上傳檔案的其它參數:" + item.getFieldName() + "="
                        + item.getString("Big5"));
            } else {// 上傳檔案欄位
                // or it's a file upload request
 
                if (item.getSize() > 0) {
                    uploadlist.put(item.getFieldName(), item);
                    System.out.println("上傳檔案:" + item.getFieldName());
                }
            }
        }
    }
 
    // 設定檔案上傳後存放的地方
    public void setUploadDir(String upload_dir) {
        this.def_upload_dir = upload_dir;
    }
 
    // 取得所有欄位,包含一般欄位及上傳的欄位
    public Map getAllParameter() {
        Map rvalue = new HashMap();
        rvalue.putAll(map);
        rvalue.putAll(uploadlist);
        return rvalue;
    }
 
    // 取得某一欄位的值,一般欄位
    public String getParameter(String FieldName) {
        if (map.containsKey(FieldName))
            return String.valueOf(map.get(FieldName));
        else
            return null;
    }
 
    // 取得某一欄位的值,上傳欄位
    public FileItem getUploadParameter(String FieldName) {
        if (uploadlist.containsKey(FieldName))
            return (FileItem) uploadlist.get(FieldName);
        else
            return null;
    }
 
    // 檢查上傳資料是否正確
    public String checkUpload() {
        Iterator iter = uploadlist.keySet().iterator();
        while (iter.hasNext()) {
            Object Name = iter.next();
            FileItem item = (FileItem) uploadlist.get(Name);
            String itename = item.getName();
            System.out.println("上傳的檔案為:" + itename);
            if (item.getSize() > SizeMax)
                return "檔案太大!";
        }
        return "";
    }
 
    // 開始上傳
    public String doUpload(FileItem item, String fileName) {
        String str = "";
        long sizeInBytes = item.getSize();
        // 碓認上傳資料是否有誤
        if (sizeInBytes > SizeMax)
            return "檔案太大!";
 
        if (sizeInBytes > 0) {
 
            int index = -1;
            String itename = null;
            if ((index = item.getName().lastIndexOf("\\")) != -1)
                itename = item.getName().substring(index,
                        item.getName().length());
            else
                itename = item.getName();
            // 副檔名
            String formatName = itename.substring(itename.length() - 4,
                    itename.length());
 
            fileName = (fileName + formatName).toLowerCase();
 
            System.out.println("上傳檔案檔案名稱:" + fileName);
 
            File uploadedFile = new File(def_upload_dir + fileName);
            // 會產生 Exception
            try {
                item.write(uploadedFile);
 
            } catch (Exception e) {
                System.out.println("上傳失敗!" + e.toString());
                str = "上傳失敗!";
            }
            // 會產生 Exception
 
        }
        return str;
    }
 
    // 是否存在此上傳欄位資料
 
    public boolean isExtUpload(String fileName) {
        return uploadlist.containsKey(fileName);
    }
}

這是整個程式最主要的範例 把所有可能會用到的上傳狀況及行為均寫入此Class裡 再來我們寫一個form來當上傳介面及另一個接收檔案的程式

form表單DemoFileUpload.html

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=BIG5">
<title>Insert title here</title>
</head>
<body>
<b>File Upload</b>
<br>
<form name="UploadForm" enctype="multipart/form-data" method="post"
    action="doupload.jsp">檔案1<input type="file" name="File1"
    size="50" maxlength="20" /> <br>
檔案2<input type="file" name="File2" size="50" maxlength="20" /> <br>
文字<input type="text" name="textfield" size="50" maxlength="20" /> <br>
<input type="submit" value="upload"></form>
</body>
</html>

實際使用doupload.jsp

<%@ page language="java" contentType="text/html; charset=BIG5"
    pageEncoding="BIG5"%>
<%
    //把request傳入UploadTool裡
    toolkie.UploadTool upload = new toolkie.UploadTool(request);
%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=BIG5">
<title>Insert title here</title>
</head>
<body>
<%
    //查詢是否錯誤
    String msg = upload.checkUpload();
    if (msg.length() > 0) {
        out.println(msg);
    } else {
        //設定上傳路徑
        upload.setUploadDir(this.getServletContext().getRealPath("."));
        out.println("上傳到此路徑:"
                + this.getServletContext().getRealPath(".") + "<br/>");
        //取得文字檔
        out.println("文字欄位:" + upload.getParameter("textfield")
                + "<br/>");
        //開始上傳
        if (upload.isExtUpload("File1"))
            msg = upload.doUpload(upload.getUploadParameter("File1"),
                    "File1");
        if (msg.length() == 0 && upload.isExtUpload("File2"))
            msg = upload.doUpload(upload.getUploadParameter("File1"),
                    "File2");
 
        if (msg.length() > 0)
            out.println(msg);
        else
            out.println("上傳成功" + "<br/>");
 
    }
%>
 
</body>
</html>

說明:

  • upload需要先設定到上傳的路徑為何
  • 可以直接取得form其它非上傳欄位的值,用法跟request一樣->upload.getParameter("欄位名")
  • 上傳指定的欄位檔案及更改其名稱->upload.doUpload(FileItem,"要變成的檔案名稱")
  • 其中FileItem可以使用upload.getParameter("欄位名稱")
  • 如上傳成功則不會有msg回傳,否則則會告知錯誤內容
  • 欄位名稱為傳送的form表單中元素的欄位名稱

以下是執行過程

1.選擇要上傳的檔案

2.按下upload後會告知檔案被上傳的路徑及文字欄位的內容及上傳成功與否

3.可以在上傳路徑裡看到二個剛才上傳的欄案,而名稱已重新命名了

4.可以在Console裡看到整個上傳過程

程式碼的說明均寫在裡面就不在詳述,有興趣的人可以看看,再來會再寫一篇如何使用Eclipse來執行jsp程式,將會使用上面的範例^^


Related Posts Plugin for WordPress, Blogger...

33 回應 to “[教學]jsp Web的檔案上傳-FileUpload”

PingBack List:

  1. jsp檔案上傳並利用Ajax製作ProgressBar監控上傳進度 -教學文件與筆記
  1. 1
    1255

    您好,我下載您的範例後執行後,eclipse會回報找不到CLASS
    我就加入了
    再執行一次變成了下面的錯誤
    description The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: java.lang.NoClassDefFoundError: org/apache/commons/fileupload/FileItemFactory
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:268)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    請問我的問題是什麼原因產生的呢?
    謝謝

    [回應]

    yku Replay:

    這應該是您未在classpath裡加入需要的jar檔
    第三方的jar檔
    Apache Filupload及Apache common io
    你可以在文章一開始的地方取得連接,下載後解開裡面的jar
    然後開啟eclipse專案結點按右鍵properties->Java Build Path->Libraies 載入這些jar檔
    或著你可以把jar檔放到你載案目錄下的web-inf/lib目錄下,也有一樣的效果(如果是tomcat Server的話)

    [回應]

  2. 2
    weiham

    不好意思,打擾了,我參照你的程式碼,去實作檔案上傳的功能,
    但是在本機端測試可以成功將圖片上傳至
    C:\tomcat\webapps\Knowledge2\pic\

    但是在上傳至我自己的主機上運作,在上傳檔案之後仍出現 上傳成功
    但實際進入電腦裡面 pic的資料夾卻沒有檔案存在
    /var/lib/tomcat6/webapps/Knowledge/pic\

    upLoad_DIR=this.getServletContext().getRealPath("/")+"pic\\";
    這是我在上傳檔案的jsp頁面 所設定的路徑,

    因為沒有出現實際的錯誤訊息,所以才冒昧詢問一下,是否有相關的修正方向,可以提供給我參考

    不好意思,謝謝

    [回應]

    yku Replay:

    原始碼跟linux的環境是那一種可以給我一下嘛?
    我幫你架起來試看看^^
    有可能是你Linux給tomcat的權限不夠 有幾個地方要設
    一個是tomcat啟動的user
    一個是java的policy
    還有tomcat好像也要地方設
    建議你用下載的tomcat解壓縮來設定 可以參考我的文章
    用agt-get好像有這種問題...
    回答不知道是不是你想要的

    [回應]

  3. 3
    DV

    hi,我需要移jsp MySql網站
    您能幫我嗎

    謝謝

    [回應]

    yku Replay:

    請問是什麼意思?
    移jsp mysql?

    [回應]

  4. 4
    HOST

    用你的方是無法直行出現
    jar檔有放到lib內就ok 但而程式complier後放置WEB-INF/classes/toolkie/裡。
    這就看不懂囉

    [回應]

    yku Replay:

    我幫你補上一個這些檔案的放置位置圖喔...
    您可以看看!有問題再請告知

    [回應]

  5. 5
    Myron

    可以請問一下您嗎!

    我使用java寫了一個搜尋功能
    有使用到main
    是我的只要動作與印出

    也有使用到HttpServletRequest request
    是要從jsp那邊拿到text物件的資訊
    拿到的參數傳入main那邊執行結束後要印回jsp
    不知道這辦法對不對

    [回應]

    yku Replay:

    我不太懂你的意思
    main是指public static void main(String args[])嘛?
    那是application的寫法喔
    你要使用你寫的程式內容,可以利用servlet或是jsp去呼叫你的java class
    (跟你在main裡呼叫方式一樣)

    [回應]

    Myron Replay:

    嗯 是public static void main(String args[])
    但是我使用doget去丟值 他會在丟進去main去執行嗎?

    請問一下你有通訊方式嗎 ??facebook 或是 yahoo

    [回應]

    Myron Replay:

    @Myron, 網路怪怪!!抱歉

    [回應]

    yku Replay:

    不是網路怪怪的
    你看不到回覆的訊息是因為我blog的快取因素

    [回應]

    yku Replay:

    你可以給我範例嘛?
    你直接mail給我就可以了@我一直都有在收信喔

    [回應]

  6. 6
    Myron2

    @Myron, 是public static void main(String args[])
    我使用doget把jsp 文字區塊內的值傳入執行
    再使用最外層
    public class Searchss extends HttpServlet{
    public static String phrase;
    宣告一個變數phrase 要丟入main內去執行
    但是好像無法丟入

    請問一下您有通訊方式嗎? 例如:facebook,yahoo

    [回應]

  7. 7
    tsai

    @Myron, 是public static void main(String args[])
    我使用doget把jsp 文字區塊內的值傳入執行
    再使用最外層
    public class Searchss extends HttpServlet{
    public static String phrase;
    宣告一個變數phrase 要丟入main內去執行
    但是好像無法丟入

    請問一下您有通訊方式嗎? 例如:facebook,yahoo

    [回應]

  8. 8

    請問如何把程式改成上傳什麼檔案在目錄上就是那原本檔案的檔名呢?

    [回應]

    yku Replay:

    File uploadedFile = new File(def_upload_dir +item.getName());
    把上傳要存放的檔名修改成item.getName()的名稱就可以了

    [回應]

  9. 9
    阿達

    我在UploadTool.java 編譯時會發生錯誤?

    [回應]

    yku Replay:

    請問是什麼錯誤訊息?
    您有把jar檔都放到classpath去complier嘛?

    [回應]

    阿達 Replay:

    @yku, 原來是沒有環境變數設定:) 謝謝

    [回應]

  10. 10
    阿達

    doupload.jsp 執行時有誤,
    toolkie.UploadTool cannot be resolved to a type

    toolkie.UploadTool upload = new toolkie.UploadTool(request);

    Stacktrace:
    org.apache.jasper.compiler.DefaultErrorHandler.javacError(DefaultErrorHandler.java:92)
    org.apache.jasper.compiler.ErrorDispatcher.javacError(ErrorDispatcher.java:330)
    org.apache.jasper.compiler.JDTCompiler.generateClass(JDTCompiler.java:423)
    org.apache.jasper.compiler.Compiler.compile(Compiler.java:317)
    org.apache.jasper.compiler.Compiler.compile(Compiler.java:295)
    org.apache.jasper.compiler.Compiler.compile(Compiler.java:282)
    org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:586)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:317)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

    [回應]

    yku Replay:

    jsp的Complier沒過...你用什麼工具?
    環境是?

    [回應]

  11. 11
    Aurora

    您好,看完這篇文章有一個小問題想要請教您。
    若是只是想要取得欄位裡「檔案的完整路徑」要怎麼寫呢?

    如果用 request.getParameter("欄位名稱") 他只會列出檔名,不會是它的完整路徑

    不好意思,才剛碰這方面沒多久,想要用其他方法寫上傳,可是一直沒辦法取得完整檔案路徑>"<
    搜尋了很久好像都沒找到相關資料…不知道這個問題是不是有解的呢?謝謝您~

    [回應]

    Aurora Replay:

    阿…真是不好意思,留完言後亂試居然試出來了QQ
    File file = new File(request.getParameter("欄位名稱"));
    這樣就可以讀到檔案了!
    原本以為一定要完整路徑才可以,不好意思打擾您了>"<

    [回應]

  12. 12
    Toilet

    Dear sir,
      我的環境是Eclipse+JRE1.6+Tomact6.0,
      我在單獨執行UploadTool.java(為了將之編譯成.class),
      出現description  The requested resource () is not available.
      能否煩請協助告知原因,
      麻煩了~~~

    [回應]

    yku Replay:

    UploadTool你complier時有含servlet-api.jar嘛?

    [回應]

  13. 13
    skyghot

    你好:

    最近剛好也在寫這一塊,剛好看到這篇文章,實在是受益良多!

    但是我有一個小小的問題就是我在upload.getParameter 的時候

    如果傳進來的是中文會變成亂碼,這邊要怎麼解決啊??

    如果我們用一般的request的話可以用.getBytes("ISO8859-1"),"UTF-8"來解決,

    但是因為現在是用upload.getParameter 的方式,就沒有上述的方法可用了! 這有解嗎??

    還有一個問題就是我希望做到上傳之後的檔案名稱跟原來的檔名一樣,我試過你在上面說的方法,可是似乎無效,是我用錯了嗎?還是哪邊沒注意到???

    還有就是說如果上傳放置的地方,我們現在是用絕對路徑來做為存放位置,可改用相對位置嗎??

    小弟剛學沒多久,有一些問題希望大大可以幫我解惑 感激不進

    [回應]

    yku Replay:

    @skyghot,
    1.你可以把你的網頁 content-type設成utf8 接收端也一樣
    還有,把文件的編碼也設成utf8 <---這很重要
    基本上就可以解決了

    2.item.getName() 時 它就是原本的名字了,你可以把它存起來,要存回時再把它當檔名

    3.相對路徑也可以,只是當你在開發時,跟你上線到主機時 你會發生你的相對位置可能不一樣
    這樣子會讓你十分不好管理
    this.getServletContext().getRealPath(".") 這個會抓到你網頁的http://xxx.xxx.xxx/ 的實際路徑
    這樣子存在這裡才可以在網頁上看的到

    [回應]

    skyghot Replay:

    @yku,

    1.你說的那些我基本上都有設定了但是不知道是否有設對,因為他沒有起作用

    jsp中

    我做了這些設定 文件編碼也是使用utf-8

    其實upload.getParameter亂碼的問題我已經解決了,就是在java檔中
    if (item.isFormField()) {
    map.put(item.getFieldName(), item.getString("Big5")); <-----------------------改設成utf-8
    System.out.println("上傳檔案的其它參數:" + item.getFieldName() + "="
    + item.getString("Big5"));<-------------------------改設成utf-8

    但是這樣如果是上傳的檔案部分就沒辦法這樣改了,所以如果我檔案是中文名稱的話,上傳之後就會變成亂碼,不知道這邊有沒有解??

    2.你說item.getName()這個是在哪裡使用?? 在java檔裡面嗎 還是在jsp檔裡面
    我是在我的jsp黨裡面寫了
    String itename =upload.getUploadParameter("imgFile").getName();
    結果得到的是完整的檔案路徑,而不是只有檔名而已,因為我想說你 upload.doUpload("","filename")這個
    function裡面一定要傳檔名進去,所以我試圖在jsp檔案中,要call這個upload.doUpload之前把檔名抓到然後再送進去~~~這邊是我哪邊用錯了嗎,請指教囉

    3.再來就是說我昨天試了用相對路徑的方式,好像不行喔,會想要用相對路徑是有原因的,因為我是因為有兩個project, project1 project2 , 我要上傳圖片的程式是寫在project2中,然後存檔路徑是要在project1中,如果用你說的那個方式,可能就不適合了= =

    再來我發現一個問題就是說,因為我程式裡面其實很多東西要上傳,有一般的的text,textarea,還有file 因為有file的關係所以使用了enctype="multipart/form-data"
    這樣乍看之下好像滿OK的,但是如果今天file欄位如果沒上傳東西,好像連帶著連text跟textarea都會收不到參數耶~~~這有解嗎??

    問題好像有點多 , 抱歉 ,因為是新手還滿多不懂的~~感謝你的回答喔

    [回應]

    yku Replay:

    @skyghot,
    不好意思那麼晚才回你
    你看看這範例對你有沒有用

    [回應]

    skyghost Replay:

    @yku,
    恩~~~謝謝你囉!XD

    上面提的問題有些是我程式的問題,不過大部分是都已經解決了

    你的程式我之後有空再看囉,不管如何 總之謝謝你囉

    對了~~~看是不是方便留個MSN或是FB,之後我們可以討論問題或交個朋友囉

    方便的話就寄mail囉

    再次感謝你XD

    [回應]

留下您想說的話:

*