Java Servlet實現文件上傳

文件上傳能夠說是Web應用中很經常使用的一塊,前幾天打算研究一下HTML5提供的FileReader API,而且用Tomcat做爲後端來實驗大文件的上傳(只是學校的課程做業必須用Java寫,都不容許使用最好的編程語言php>.<)。可Java Servlet與php這種喜聞樂見的Web碼農語言不一樣,並無提供一個很簡單的處理文件上傳的API,因此還搗鼓了蠻久,也對通常的文件上傳的HTML控件和實現原理稍微有了一點了解。php

對面宿舍的一位同窗說我好久沒更了不太好,因而我就寫一篇,謝謝他的提醒。html

首先,咱們都知道最多見的HTML的文件上傳控件是喜聞樂見的<input type="file">,但必定要搭配form的屬性enctype="multipart/form-data",服務器上要有一個接收上傳的cgi或者別的什麼,既然咱們用java寫,就叫uploadServlet。因而有了一個以下的常見的上傳表單。java

<form action="uploadServlet" enctype="multipart/form-data" method="POST">
    <input name="password" type="password" />
    <input name="File1" type="file" />
    <input type="submit" value="Upload" />
</form>

而後咱們在後端處理。因爲Java Servlet的API是沒有提供什麼$_FILES數組這樣傻瓜式的文件操控方式,咱們必須本身處理request。咱們不妨先把收到的request輸出到文件當中,看看Servlet會收到什麼,再想一想怎麼處理。放這樣一個servlet的代碼:web

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class UploadServlet extends HttpServlet{
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        response.setContentType("text/plain;charset=utf-8");
        PrintWriter writer=response.getWriter();
        InputStream in=request.getInputStream();
        File f = new File("/tmp/upload");
        //把文件存到/tmp/upload
        FileOutputStream fout = new FileOutputStream(f);
        byte[] b=new byte[1024];
        int n=0;
        while ((n=in.read(b))!=-1){
            fout.write(b,0,n);
        }
        fout.close();
        in.close();
        writer.println("Finished uploading files!");
        writer.close();
    }
}

有了Servlet就拖出去跑一跑。這裏個人表單不只會發送文件,還會發送一個密碼域。若是我隨便發一個文本文件,那麼我獲得了這樣的結果。
upload請求數據用gedit打開的upload請求數據圖片
多上傳幾回還會發現那一堆橫槓開頭的數字會變更。這下很差玩了,雖然咱們能夠看到咱們上傳的數據,但要解析它有點過於複雜了。這個請求是依據RFC1867來寫的,雖然有標準可依,但咱們這麼懶怎麼會去依照標準寫一個解析器呢?apache

因而咱們須要請出Apache開發的文件上傳處理庫Commons FileUpload。這個網站提供了最新版的下載連接和基本的使用指南。文檔講得過於全面了,而咱們通常不須要那麼多功能,夠用就好。翻了幾篇教程,寫出來了一個簡單的文件上傳接收代碼。編程

javaimport javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.servlet.*;
import org.apache.commons.fileupload.disk.*;

首先須要多裝載三個庫,以及一個java.util.List,由於到時候處理的時候,Commons FileUpload會把搞成一個List返回回來,咱們須要接收這個List並處理解析它。後端

public class UploadServlet extends HttpServlet{
    private String filepath;
    private String temppath;
    private String buf;
    public void init(ServletConfig config) throws ServletException{
        super.init(config);
        ServletContext context=getServletContext();
        filepath=context.getRealPath("/"+config.getInitParameter("filepath"));
        temppath=context.getRealPath("/"+config.getInitParameter("temppath"));
    }

爲了方便維護,我把保存上傳文件的目錄用Init Parameter的方式寫到web.xml裏面去,而後在這個地方讀出來。咱們須要一個保存上傳文件的目錄和一個用來作緩存的臨時目錄。若是你接收上傳文件以後不打算保存而是直接拿去處理,也沒有問題,可是必定要有一個緩存目錄,在後面有用。數組

接下來是真正激動人心的處理上傳的代碼了。我懶得寫doGet了因此就只有一個doPost。緩存

@Override
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        response.setContentType("text/plain;charset=utf-8");
        PrintWriter writer=response.getWriter();
        int count=0;
        try{
            DiskFileItemFactory diskFactory = new DiskFileItemFactory();
            diskFactory.setSizeThreshold(4 *1024 );
            diskFactory.setRepository(new File(temppath));

這裏咱們開了一個diskFactory,就是FileUpload所須要使用的緩存,當內存存不下上傳的文件的時候,它會自動寫入緩存目錄。經過setSizeThreshold方法能夠設置內存的使用上限,也就是當內存用了這麼多卻還存不下,就開始寫緩存。顯然這個值很大程度上會決定這個Servlet的效率。服務器

ServletFileUpload upload = new ServletFileUpload(diskFactory);
    upload.setSizeMax(4 * 1024 * 1024);
    List fileItems = upload.parseRequest(request);
    Iterator iter = fileItems.iterator();

這裏咱們就真正建了一個ServletFileUpload的實例upload來處理文件的上傳。能夠設置上傳文件的最大大小。而後把request對象直接交給upload來解析,它會返回一個一個List,這個List的每一項其實是一個FileItem對象,後面就要用迭代器處理這個列表。

while (iter.hasNext()){
        FileItem item = (FileItem) iter.next();
        if (item.isFormField()){
            writer.println(item.getFieldName()+" : "+item.getString());
        }

要注意的是ServletFileUpload也會處理非文件的信息,能夠用isFormField方法來檢查,而後將信息獲取出來。但這在這裏不是重點,只是必需要處理掉而已。

else{
            String filename = item.getName();
            filename = filename.substring(
            filename.lastIndexOf("\\")+1,filename.length());
            File uploadFile = new File(filepath+"/"+filename);
            item.write(uploadFile);
            writer.println("Get file:"+ filename);
            writer.println(" filetype: "+item.getContentType());
            count++;
        }
        }
    } catch (Exception e){
        e.printStackTrace();
    }
    writer.println("Finished uploading files!");
    writer.close();
}
}

處理文件的代碼就這麼點,若是還要說什麼的話,就是每一個文件的FileItem對象不只能夠用write方法來直接寫到什麼文件裏面去,也能夠用getInputStream方法獲得一個輸入流來解析,或者用get方法直接讀到一個byte數組裏面去。能夠說這個庫提供了一個很方便的方法解析上傳的文件。

最後提一下,Apache Commons是一個Java加強庫,提供了大量的優質Java資源庫,涉及不少開發領域。若是不出意外,應該我會在近期寫一篇關於JavaScript FileReader的blog,敬請期待。

參考的文章:
Servlet實現基本文件上傳
在Servlet中使用開源fileupload包實現文件上傳功能

相關文章
相關標籤/搜索