1. 程式人生 > >Java for Web學習筆記(九):Servlet(7)上傳檔案

Java for Web學習筆記(九):Servlet(7)上傳檔案

上傳檔案

Servlet的引數設定

採用annotation方式如下:

@WebServlet(
	name = "TicketServlet",
	urlPatterns = {"/tickets"},
	loadOnStartup = 1
	)
/* MultipartConfig配置了本Servlet的檔案上傳引數,
 * location:這裡沒有列出的是location引數,表示存放臨時檔案的位置,一般無需配置,選擇預設的臨時資料夾
 * fileSizeThreshold:表示收到檔案到達這麼大後,不在放入快取,而是寫入臨時檔案。本例中,如果檔案小於5M,則存放在快取,然後被垃圾回收;同樣的,如果採用臨時檔案方式,臨時檔案也會被刪除。
 * maxFileSize:限制檔案的最大值,本例檔案不超過20M
 * maxRequestSize:由於可能同時上傳多個檔案,servlet可能會被同時請求,此限制總量。 
 */
@MultipartConfig(  
	fileSizeThreshold = 5_242_880, // 5M
	maxFileSize = 20_971_520L, //20M
	maxRequestSize = 41_943_040L //40M
	)

採用web.xml的方式如下:

<servlet>
    <multipart-config>
        <location>......</location>
        <file-size-threshold>......</file-size-threshold>
        <max-file-size>......</<max-file-size>
        <max-request-size>......</max-request-size>
    </multipart-config>
</servlet>

Multipart上傳檔案

下面是Create Ticket的HTML,檔案上傳有關的是<form… enctype="multipart/form-data"/><input type="file" name="file1"/>

<!DOCTYPE html>
  <html>
  <head>
    <title>Customer Support</title>
  </head>
  <body>
    <h2>Create a Ticket</h2>
    <form method="POST" action="tickets" enctype="multipart/form-data">
      <input type="hidden" name="action" value="create"/>
      Your Name<br/>
      <input type="text" name="customerName"/><br/><br/>
      Subject<br/>
      <input type="text" name="subject"/><br/><br/>
      Body<br/>
      <textarea name="body" rows="5" cols="30"></textarea><br/><br/>
      <b>Attachments</b><br/>
      <input type="file" name="file1"/><br/><br/>
      <input type="submit" value="Submit"/>
    </form>
  </body>
</html>

點選submite,將觸發一個action=create的POST請求,抓包如下:

POST /customer-support/tickets HTTP/1.1
Host: 191.8.1.103:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101 Firefox/42.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://191.8.1.103:8080/customer-support/tickets?action=create
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------168557226814076645131805352216
Content-Length: 729

-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="action"

create
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="customerName"

Wei
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="subject"

moon
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="body"

Hello,world
-----------------------------168557226814076645131805352216
Content-Disposition: form-data; name="file1"; filename="moon.txt"
Content-Type: text/plain

Hello, Moon!
Hello, my friend!

-----------------------------168557226814076645131805352216--

先對比普通的form-data的HTTP POST訊息體的例子如下。和GET的引數傳遞部分是一樣的。

action=create&customerName=j&subject=jj&body=jjjj

現在,我們在HTML中指明enctype="multipart/form-data",因此在HTTP POST的封裝中採用了multipart/form-data的方式。這在RFC1867 Form-based File Uploadin HTML中有詳細的規定,包括file型別。對於普通的form-data的內容讀取有下面兩個方式:

(1)通過javax.servlet.http.part類來讀取

Part part1 = request.getPart("customerName");
System.out.println(part1.getHeader("Content-Disposition"));
InputStream is = part1.getInputStream();
int len = is.available();
byte[] buff = new byte[len];
is.read(buff);
System.out.println(new String(buff));

(2)提供了更直接的方式

System.<em>out</em>.println(<strong>request.getParameter("customerName"));</strong>

毫無疑問,我們會採用第二種方式,但是第一種方式提供了通用的讀取multipart的方法。我們將使用該方式讀取上傳檔案部分,小例子的程式碼如下:

private void createTicket(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
    //獲取普通的form-data資訊
    String customerName = request.getParameter("customerName");
    String subject = request.getParameter("subject");
    String body = request.getParameter("body");

    //讀取上傳檔案部分:獲取相應的multipart
    Part filePart = request.getPart("file1");
    //讀取上傳檔案部分:getSize()是multipart中資訊的大小,而非整個multipart的大小,對應即為上傳檔案的大小
    if(filePart != null && filePart.getSize() > 0){
        // 獲取檔名稱,即Content-Disposition: form-data; name="file1"; filename="moon.txt"中的filename,我們可以通過filePart.getHeader("Content-Disposition")分析獲取。javax.servlet.http.Part直接提供了方法
        String fileName = filePart.getSubmittedFileName();
        // 獲取檔案上傳內容放。
        InputStream inputStream = filePart.getInputStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int read;
        final byte[] bytes = new byte[1024];
        while((read = inputStream.read(bytes)) != -1){
            outputStream.write(bytes, 0, read);
        }
        /* 如果是二進位制,通過outputStream.toByteArray()獲得byte[]。任何格式均適合二進位制;如果是文字檔案,可以先通過filePart.getHeader("Content-Type")來確認,直接outputStream.toString() */
          … …
    }
    ......
}