SECTION 01 FileUpload 總覽
在撰寫網站程式的時候, client 與 server 之間的往往不只有純文字的溝通, 還會有 binary 的檔案傳輸, 該如何在 HTML Form 之中傳送, 就要遵守 RFC 1867 的規範了.
基本上, post.jsp (選擇檔案)應該都會有下面類似的 html tag :
<form action="upload.jsp" enctype="multipart/form-data" method="POST">
input your name: <input type="text" name="name"> <br>
select the file: <input type="file" name="file"> <br>
<input type="submit" value="submit">
</form>
這一部份是屬於 HTML 的範疇, 有興趣的可以鑽研 RFC ...
SECTION 02 multipart/form-data 的 HTTP 表現情形
當你按下傳送的時候, Browser 將會送出 Post 的資料到 server,
POST http://localhost:9000/fileupload/upload.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Referer: http://localhost:9000/fileupload/post.jsp
Accept-Language: zh-tw,zh-cn;q=0.7,en-us;q=0.3
Content-Type: multipart/form-data; boundary=---------------------------7d33e580784
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: www.softleader.com.tw
Content-Length: 3020
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=3B31F07F56328E7B623A9BA1C4E3479D
我們可以知道, Contenet-Type 是用 multipart/form-data 另外還有 boundary 的傳輸.
SECTION 03 實際的例子
<html>
<head>
<title>File Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=big5">
</head>
<body bgcolor="#FFFFFF" text="#000000"><p><font size="5"color="#FF0000">
<b>第七章 檔案上傳範例</b></font></p>
<form name="Form1" enctype="multipart/form-data" method="post" action="JYFile.jsp">
<p>上傳檔案 1: <input type="file"name="File1" size="20" maxlength="20"> </p>
<p>檔案1敘述: <input type="text" name="File1" size="30" maxlength="50"> </p>
<p>上傳檔案 2: <input type="file" name="File2" size="20" maxlength="20"> </p>
<p>檔案2敘述: <input type="text" name="File2" size="30" maxlength="50"> </p>
<p>上傳檔案3: <input type="file" name="File3" size="20" maxlength="20"> </p>
<p>檔案3敘述: <input type="text" name="File3" size="30" maxlength="50"> </p>
<p> <input type="submit"value="上傳"> <input type="reset" value="清除"> </p>
</form>
</body>
</html>
SECTION 04 傳送格式
POST /newspaper/JYFile.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Referer: http://localhost:9000/newspaper/JYFile.html
Accept-Language: zh-tw,zh-cn;q=0.7,en-us;q=0.3
Content-Type: multipart/form-data; boundary=---------------------------7d31091c6205fc
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: localhost:9000
Content-Length: 428583
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=E141744815A8FF44F8AA9BA6D5946710
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File1"; filename="C:/test/測試.exe"
Content-Type: application/octet-stream
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File1"
exe
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File2"; filename="C:/test/測試.gif"
Content-Type: image/gif
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File2"
gif
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File3"; filename="C:/test/測試.xls"
Content-Type: application/vnd.ms-excel
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File3"
xls
-----------------------------7d31091c6205fc--
SECTION 05 送到 JYFile.jsp
<%@ page contentType="text/html;charset=Big5" language="java" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.*" %>
<%@ page import="org.apache.commons.fileupload.*" %>
<%
// 宣告將上傳之檔案放置到伺服器的 / .... /upload 目錄中
String saveDirectory = "c://";
// 宣告暫存目錄
String tmpDirectory = "c://";
// 宣告限制上傳之檔案總大小為, 單位為 byte, -1 表示無限制
int maxPostSize = 1024 * 1024;
%>
<%
// 宣告儲存敘述上傳檔案內容的變數
String FileDescription = null;
// 宣告儲存上傳檔案名稱的變數
String FileName = null;
// 宣告儲存上傳檔案大小的變數
long FileSize = 0;
// 宣告儲存上傳檔案型態的變數
String ContentType = null;
// 計算上傳檔案之個數
int count = 0 ;
%>
<%
DiskFileUpload upload = new DiskFileUpload();
// 設定記憶體存放資料的大小, 超過則寫入檔案, 有設定暫存目錄, 暫存檔置於暫存目錄下
upload.setSizeThreshold(4096);
// 設定總上傳大小限制
upload.setSizeMax(maxPostSize);
// 設定暫存目錄
upload.setRepositoryPath(tmpDirectory);
List /* FileItem */ items = upload.parseRequest(request);
%>
<body>
<%
Iterator iter = items.iterator();
int tmp = 0;
FileItem tmpItem = null;
while (iter.hasNext())
{
tmp++;
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
// 如果是一般欄位, 取得檔案敘述
FileDescription = item.getString();
} else {
// 否則取得檔案資訊
FileName = item.getName();
// 因為不同的瀏覽器會造成傳遞 path + filename, 有些則只有 filename
try {
// for wintel platform
FileName = FileName.substring(FileName.lastIndexOf("//")+1);
// for unix-like platform
FileName = FileName.substring(FileName.lastIndexOf("/")+1);
} catch ( Exception ex ) {
out.println(ex);
}
ContentType = item.getContentType();
FileSize = item.getSize();
tmpItem = item;
}
// 因為一個檔案都是兩個欄位, 每讀取兩個欄位處理一次
if (tmp == 2 && FileSize != 0)
{
count ++;
%>
<font color="red">你上傳的第<%= count %>個的檔案:</font><br>
檔案名稱為:<%= FileName %><br>
檔案大小為:<%= FileSize %> Bytes<br>
檔案型態為:<%= ContentType %><br>
檔案的敘述:<%= FileDescription %><br><br>
<%
// 將檔案寫入存檔目錄
try {
out.println(FileName);
File uploadedFile = new File(saveDirectory + FileName);
tmpItem.write(uploadedFile);
} catch ( Exception ex ) {
out.println(ex);
}
tmp = 0;
} else if (tmp == 2 && FileSize == 0) {
tmp = 0;
} // end if
} // end while
%>
您總共上傳<font color="red"><%= count %></font>個檔案
</body>
</html>
SECTION 06 Struts FileUpload
為何 struts 1.1 要等 Commons-FileUpload 1.0 呢
因為 struts 有一個 subpackage 叫做 org.apache.struts.upload.*; 這裡面就是設定相關的 file 格式如果你使用 struts 為 MVC Framework 就可以參考 example 中的 struts-upload.war 的開發
(1) 建立 upload.jsp
<html:form action="upload.do?queryParam=Successful" enctype="multipart/form-data">
檔案敘述:<html:text property="theText" /><br>
選擇檔案:<html:file property="theFile" /><br>
</html:form>
(2) 建立 UploadForm.java
public class UploadForm extends ActionForm{
..........
public String getTheText() {
return theText;
}
public void setTheText(String theText) {
this.theText = theText;
}
public FormFile getTheFile() {
return theFile;
}
public void setTheFile(FormFile theFile) {
this.theFile = theFile;
}
..........
}
請注意 FormFile 是建立在 org.apache.struts.upload 這個 package 中的
(3) 撰寫 UploadAction
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
UploadForm theForm = (UploadForm) form;
String text = theForm.getTheText();
FormFile file = theForm.getTheFile();
String fileName= file.getFileName();
String contentType = file.getContentType();
String size = (file.getFileSize() + " bytes");
.... // 看你要如何處理
.... // 可以用 InputStream 取得 file.getInputStream 等等
return mapping.findForward("ThePageYouWannaGo");
}
(4) 建立 struts-config.xml
<form-beans>
<form-bean name="uploadForm"
type="org.apache.struts.webapp.upload.UploadForm" />
</form-beans>
<action-mappings>
<!-- Upload Action -->
<action path="/upload" type="org.apache.struts.webapp.upload.UploadAction"
name="uploadForm" scope="request" input="/upload.jsp">
<forward name="display" path="/display.jsp" />
</action>
詳細內容請下載 struts 1.1 src 查閱內容
SECTION 06 總結
其實大家熟悉的都是 Oreilly MultiPartRequest 和 jspsmart的SmartUpload , 請參考 jsptw 的 browser 所寫的著作.
在撰寫網站程式的時候, client 與 server 之間的往往不只有純文字的溝通, 還會有 binary 的檔案傳輸, 該如何在 HTML Form 之中傳送, 就要遵守 RFC 1867 的規範了.
基本上, post.jsp (選擇檔案)應該都會有下面類似的 html tag :
<form action="upload.jsp" enctype="multipart/form-data" method="POST">
input your name: <input type="text" name="name"> <br>
select the file: <input type="file" name="file"> <br>
<input type="submit" value="submit">
</form>
這一部份是屬於 HTML 的範疇, 有興趣的可以鑽研 RFC ...
SECTION 02 multipart/form-data 的 HTTP 表現情形
當你按下傳送的時候, Browser 將會送出 Post 的資料到 server,
POST http://localhost:9000/fileupload/upload.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Referer: http://localhost:9000/fileupload/post.jsp
Accept-Language: zh-tw,zh-cn;q=0.7,en-us;q=0.3
Content-Type: multipart/form-data; boundary=---------------------------7d33e580784
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: www.softleader.com.tw
Content-Length: 3020
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=3B31F07F56328E7B623A9BA1C4E3479D
我們可以知道, Contenet-Type 是用 multipart/form-data 另外還有 boundary 的傳輸.
SECTION 03 實際的例子
<html>
<head>
<title>File Upload</title>
<meta http-equiv="Content-Type" content="text/html; charset=big5">
</head>
<body bgcolor="#FFFFFF" text="#000000"><p><font size="5"color="#FF0000">
<b>第七章 檔案上傳範例</b></font></p>
<form name="Form1" enctype="multipart/form-data" method="post" action="JYFile.jsp">
<p>上傳檔案 1: <input type="file"name="File1" size="20" maxlength="20"> </p>
<p>檔案1敘述: <input type="text" name="File1" size="30" maxlength="50"> </p>
<p>上傳檔案 2: <input type="file" name="File2" size="20" maxlength="20"> </p>
<p>檔案2敘述: <input type="text" name="File2" size="30" maxlength="50"> </p>
<p>上傳檔案3: <input type="file" name="File3" size="20" maxlength="20"> </p>
<p>檔案3敘述: <input type="text" name="File3" size="30" maxlength="50"> </p>
<p> <input type="submit"value="上傳"> <input type="reset" value="清除"> </p>
</form>
</body>
</html>
此图片仅显示局部,请点击查看完整图片
=514)window.open(this.src);else return false;" hspace=2 src="http://hi1-pass-ren/log/uploadimg/fileupload-1.gif" οnlοad="if(this.width>=514){this.style.cursor='hand';this.alt='!!!此图片仅显示局部,请点击查看完整图片!!!';this.previousSibling.style.display='';}" vspace=2 border=0>
SECTION 04 傳送格式
POST /newspaper/JYFile.jsp HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg,
application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, */*
Referer: http://localhost:9000/newspaper/JYFile.html
Accept-Language: zh-tw,zh-cn;q=0.7,en-us;q=0.3
Content-Type: multipart/form-data; boundary=---------------------------7d31091c6205fc
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: localhost:9000
Content-Length: 428583
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=E141744815A8FF44F8AA9BA6D5946710
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File1"; filename="C:/test/測試.exe"
Content-Type: application/octet-stream
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File1"
exe
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File2"; filename="C:/test/測試.gif"
Content-Type: image/gif
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File2"
gif
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File3"; filename="C:/test/測試.xls"
Content-Type: application/vnd.ms-excel
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ( binary 亂碼 )
-----------------------------7d31091c6205fc
Content-Disposition: form-data; name="File3"
xls
-----------------------------7d31091c6205fc--
SECTION 05 送到 JYFile.jsp
<%@ page contentType="text/html;charset=Big5" language="java" %>
<%@ page import="java.io.*" %>
<%@ page import="java.util.*" %>
<%@ page import="org.apache.commons.fileupload.*" %>
<%
// 宣告將上傳之檔案放置到伺服器的 / .... /upload 目錄中
String saveDirectory = "c://";
// 宣告暫存目錄
String tmpDirectory = "c://";
// 宣告限制上傳之檔案總大小為, 單位為 byte, -1 表示無限制
int maxPostSize = 1024 * 1024;
%>
<%
// 宣告儲存敘述上傳檔案內容的變數
String FileDescription = null;
// 宣告儲存上傳檔案名稱的變數
String FileName = null;
// 宣告儲存上傳檔案大小的變數
long FileSize = 0;
// 宣告儲存上傳檔案型態的變數
String ContentType = null;
// 計算上傳檔案之個數
int count = 0 ;
%>
<%
DiskFileUpload upload = new DiskFileUpload();
// 設定記憶體存放資料的大小, 超過則寫入檔案, 有設定暫存目錄, 暫存檔置於暫存目錄下
upload.setSizeThreshold(4096);
// 設定總上傳大小限制
upload.setSizeMax(maxPostSize);
// 設定暫存目錄
upload.setRepositoryPath(tmpDirectory);
List /* FileItem */ items = upload.parseRequest(request);
%>
<body>
<%
Iterator iter = items.iterator();
int tmp = 0;
FileItem tmpItem = null;
while (iter.hasNext())
{
tmp++;
FileItem item = (FileItem) iter.next();
if (item.isFormField()) {
// 如果是一般欄位, 取得檔案敘述
FileDescription = item.getString();
} else {
// 否則取得檔案資訊
FileName = item.getName();
// 因為不同的瀏覽器會造成傳遞 path + filename, 有些則只有 filename
try {
// for wintel platform
FileName = FileName.substring(FileName.lastIndexOf("//")+1);
// for unix-like platform
FileName = FileName.substring(FileName.lastIndexOf("/")+1);
} catch ( Exception ex ) {
out.println(ex);
}
ContentType = item.getContentType();
FileSize = item.getSize();
tmpItem = item;
}
// 因為一個檔案都是兩個欄位, 每讀取兩個欄位處理一次
if (tmp == 2 && FileSize != 0)
{
count ++;
%>
<font color="red">你上傳的第<%= count %>個的檔案:</font><br>
檔案名稱為:<%= FileName %><br>
檔案大小為:<%= FileSize %> Bytes<br>
檔案型態為:<%= ContentType %><br>
檔案的敘述:<%= FileDescription %><br><br>
<%
// 將檔案寫入存檔目錄
try {
out.println(FileName);
File uploadedFile = new File(saveDirectory + FileName);
tmpItem.write(uploadedFile);
} catch ( Exception ex ) {
out.println(ex);
}
tmp = 0;
} else if (tmp == 2 && FileSize == 0) {
tmp = 0;
} // end if
} // end while
%>
您總共上傳<font color="red"><%= count %></font>個檔案
</body>
</html>
此图片仅显示局部,请点击查看完整图片
=514)window.open(this.src);else return false;" hspace=2 src="http://hi1-pass-ren/log/uploadimg/fileupload-2.gif" οnlοad="if(this.width>=514){this.style.cursor='hand';this.alt='!!!此图片仅显示局部,请点击查看完整图片!!!';this.previousSibling.style.display='';}" vspace=2 border=0>
SECTION 06 Struts FileUpload
為何 struts 1.1 要等 Commons-FileUpload 1.0 呢
因為 struts 有一個 subpackage 叫做 org.apache.struts.upload.*; 這裡面就是設定相關的 file 格式如果你使用 struts 為 MVC Framework 就可以參考 example 中的 struts-upload.war 的開發
(1) 建立 upload.jsp
<html:form action="upload.do?queryParam=Successful" enctype="multipart/form-data">
檔案敘述:<html:text property="theText" /><br>
選擇檔案:<html:file property="theFile" /><br>
</html:form>
(2) 建立 UploadForm.java
public class UploadForm extends ActionForm{
..........
public String getTheText() {
return theText;
}
public void setTheText(String theText) {
this.theText = theText;
}
public FormFile getTheFile() {
return theFile;
}
public void setTheFile(FormFile theFile) {
this.theFile = theFile;
}
..........
}
請注意 FormFile 是建立在 org.apache.struts.upload 這個 package 中的
(3) 撰寫 UploadAction
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response){
UploadForm theForm = (UploadForm) form;
String text = theForm.getTheText();
FormFile file = theForm.getTheFile();
String fileName= file.getFileName();
String contentType = file.getContentType();
String size = (file.getFileSize() + " bytes");
.... // 看你要如何處理
.... // 可以用 InputStream 取得 file.getInputStream 等等
return mapping.findForward("ThePageYouWannaGo");
}
(4) 建立 struts-config.xml
<form-beans>
<form-bean name="uploadForm"
type="org.apache.struts.webapp.upload.UploadForm" />
</form-beans>
<action-mappings>
<!-- Upload Action -->
<action path="/upload" type="org.apache.struts.webapp.upload.UploadAction"
name="uploadForm" scope="request" input="/upload.jsp">
<forward name="display" path="/display.jsp" />
</action>
詳細內容請下載 struts 1.1 src 查閱內容
SECTION 06 總結
其實大家熟悉的都是 Oreilly MultiPartRequest 和 jspsmart的SmartUpload , 請參考 jsptw 的 browser 所寫的著作.