跳到主要內容

JavaEE 上傳機制

Servlet 3.0 加入了上傳機制
之前寫過的cos套件也可以拿來比對
除了本篇介紹,另外可參考良葛格的介紹
使用時對於提供上傳的form表單有些前置需求,如下

上傳的頁面demo.jsp==================
<!-- action指向處理後續的頁面/Servlet   實作上傳功能時method只能用post 
       enctype沒指定的話會用預設值application/x-www-form-urlencoded
       使用上傳功能時則設定為multipart/form-data-->

<form action="uploadTest" method="post" enctype="multipart/form-data">
    <p>選擇檔案:</p><input type="file" name="file1" value="" /><br />
    <p>選擇檔案:</p><input type="file" name="file2" value="" /><br />
    <input type="submit" name="upload" value="upload" />
</form>

成果大概長這樣:

Servlet 3.0新增了part介面來方便檔案上傳的處理
整體相當簡單易用

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@MultipartConfig(location="C:/")      //for web container,and set file destination
@WebServlet("/uploadTest")
public class uploadTest extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse res)
                            throws ServletException, IOException{
          req.setCharacterEncoding("UTF-8");
  for(Part part : req.getParts()) {       //get collections of part objects
if("application/octet-stream".equals(part.getContentType())) {
                  String header = part.getHeader("Content-Disposition");
                  String filename = header.substring(
                            header.indexOf("filename=\"") + 10, header.lastIndexOf("\""));
                  long maxsize = 5 * 1024 * 1024;    //max size = 5 MB

                  if(! "".equals(filename) && part.getSize() < maxsize){
                  part.write(filename);
                  }
            }
        }
   }
}

程式碼簡短又很明瞭

MultipartConfig annotation可以設定 Servlet 如何處理上傳檔案
少了這一行會讓 container 無法使用 part
如果沒有填入設定的屬性,就會啟用預設值;可以設定的屬性有
fileSizeThreshould - 上傳檔案大小超過設定值時會先寫入暫存檔案,預設值0
location - 字串設定檔案寫入的目錄,預設為空字串
maxFileSize - 限制上傳檔案大小,預設值 -1L 為不限制檔案大小
maxRequestSize - 限制 multipart/form-data 請求的數目,預設值 -1L 為不限制
屬性設定很方便,但要小心對應的錯誤處理

而表單裡面的所有 input 欄位都會被包成 part 物件
假如表單裡面只有一個上傳欄位的話可以用 req.getPart(fieldName) 這樣取得
若有多個上傳欄位則使用 .getParts() 處理
"application/octet-stream".equals(part.getContentType()) 這個條件過濾 type="file" 的 input 欄位

要取得檔案名稱的話則用 part.getHeader("Content-Disposition")
每個檔案的 Content-Disposition header長這樣 form-data; name="file1"; filename="a.txt"
從這裡就可以擷取字串取得 file name

part 的 getSize() 是整個機制裡面讓我最喜歡的部分,可以在上傳前取得檔案大小
之前使用 cos 套件時沒辦法做到這樣,總覺得很浪費資源

最後一切需求都確認好之後就用 wirte() 方法寫入檔案到目的地的目錄
目標目錄如果不用MultipartConfig annotation設定,也可以寫在 web.xml 中
...
<servlet>
    <servlet-name>uploadTest</servlet-name>
    <servlet-class>tw.vencs.uploadTest</servlet-class>
    <multipart-config>
        <location>c:/</location>
    </multipart-config>
</servlet>
...

part的其他較常用的方法還有
getName() - 取得 input 欄位的 attribute
getInputStream() - 取得檔案的 inputStream,可以搭配 outputStream 實作檔案寫入
                             不過 part 已經幫我們包好了 write(),不需要再實作這個功能就是了

留言

  1. 請問:
    如果要去取得 input type="text" name="title" 之類的值,要如何取得呢?

    回覆刪除
    回覆
    1. 指在Java中嗎? 那就是 request.getParameter("title");
      如果對這方面不清楚,建議可以多了解HTML的表單資訊傳送原理

      刪除

張貼留言