標籤:style blog http color io os 使用 ar java
前一陣子有些朋友在電子郵件中問關於Struts 2實現檔案上傳的問題, 所以今天我們就來討論一下這個問題。
實現原理
Struts 2是通過Commons FileUpload檔案上傳。Commons FileUpload通過將HTTP的資料儲存到臨時檔案夾,然後Struts使用fileUpload攔截器將檔案綁定到Action的執行個體中。從而我們就能夠以本地檔案方式的操作瀏覽器上傳的檔案。
具體實現
前段時間Apache發布了Struts 2.0.6 GA,所以本文的實現是以該版本的Struts作為架構的。以下是例子所依賴類包的列表:
清單1 依賴類包的列表
首先,建立檔案上傳頁面FileUpload.jsp,內容如下:
<% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncoding = " utf-8 " %> <% @ taglib prefix = " s " uri = " /struts-tags " %> <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns ="http://www.w3.org/1999/xhtml" > < head > < title > Struts 2 File Upload </ title > </ head > < body > < s:form action ="fileUpload" method ="POST" enctype ="multipart/form-data" > < s:file name ="myFile" label ="Image File" /> < s:textfield name ="caption" label ="Caption" /> < s:submit /> </ s:form > </ body > </ html >
清單2 FileUpload.jsp
在FileUpload.jsp中,先將表單的提交方式設為POST,然後將enctype設為multipart/form-data,這並沒有什麼特別之處。接下來,<s:file/>標誌將檔案上傳控制項綁定到Action的myFile屬性。
其次是FileUploadAction.java代碼:
package tutorial; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.Date; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; public class FileUploadAction extends ActionSupport { private static final long serialVersionUID = 572146812454l ; private static final int BUFFER_SIZE = 16 * 1024 ; private File myFile; private String contentType; private String fileName; private String imageFileName; private String caption; public void setMyFileContentType(String contentType) { this .contentType = contentType; } public void setMyFileFileName(String fileName) { this .fileName = fileName; } public void setMyFile(File myFile) { this .myFile = myFile; } public String getImageFileName() { return imageFileName; } public String getCaption() { return caption; } public void setCaption(String caption) { this .caption = caption; } private static void copy(File src, File dst) { try { InputStream in = null ; OutputStream out = null ; try { in = new BufferedInputStream( new FileInputStream(src), BUFFER_SIZE); out = new BufferedOutputStream( new FileOutputStream(dst), BUFFER_SIZE); byte [] buffer = new byte [BUFFER_SIZE]; while (in.read(buffer) > 0 ) { out.write(buffer); } } finally { if ( null != in) { in.close(); } if ( null != out) { out.close(); } } } catch (Exception e) { e.printStackTrace(); } } private static String getExtention(String fileName) { int pos = fileName.lastIndexOf( " . " ); return fileName.substring(pos); } @Override public String execute() { imageFileName = new Date().getTime() + getExtention(fileName); File imageFile = new File(ServletActionContext.getServletContext().getRealPath( " /UploadImages " ) + " / " + imageFileName); copy(myFile, imageFile); return SUCCESS; } }
清單3 tutorial/FileUploadAction.java
在FileUploadAction中我分別寫了setMyFileContentType、setMyFileFileName、setMyFile和setCaption四個Setter方法,後兩者很容易明白,分別對應FileUpload.jsp中的<s:file/>和<s:textfield/>標誌。但是前兩者並沒有顯式地與任何的頁面標誌綁定,那麼它們的值又是從何而來的呢?其實,<s:file/>標誌不僅僅是綁定到myFile,還有myFileContentType(上傳檔案的MIME類型)和myFileFileName(上傳檔案的檔案名稱,該檔案名稱不包括檔案的路徑)。因此,<s:file name="xxx" />對應Action類裡面的xxx、xxxContentType和xxxFileName三個屬性。
FileUploadAction作用是將瀏覽器上傳的檔案拷貝到WEB應用程式的UploadImages檔案夾下,新檔案的名稱是由系統時間與上傳檔案的尾碼組成,該名稱將被賦給imageFileName屬性,以便上傳成功的跳轉頁面使用。
下面我們就來看看上傳成功的頁面:
<% @ page language = " java " contentType = " text/html; charset=utf-8 " pageEncoding = " utf-8 " %> <% @ taglib prefix = " s " uri = " /struts-tags " %> <! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" > < html xmlns ="http://www.w3.org/1999/xhtml" > < head > < title > Struts 2 File Upload </ title > </ head > < body > < div style ="padding: 3px; border: solid 1px #cccccc; text-align: center" > < img src =‘UploadImages/<s:property value ="imageFileName" /> ‘ /> < br /> < s:property value ="caption" /> </ div > </ body > </ html >
清單4 ShowUpload.jsp
ShowUpload.jsp獲得imageFileName,將其UploadImages組成URL,從而將上傳的映像顯示出來。
然後是Action的設定檔:
<? xml version="1.0" encoding="UTF-8" ?> <! DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd" > < struts > < package name ="fileUploadDemo" extends ="struts-default" > < action name ="fileUpload" class ="tutorial.FileUploadAction" > < interceptor-ref name ="fileUploadStack" /> < result name ="success" > /ShowUpload.jsp </ result > </ action > </ package > </ struts >
清單5 struts.xml
fileUpload Action顯式地應用fileUploadStack的攔截器。
最後是web.xml設定檔:
<? xml version="1.0" encoding="UTF-8" ?> < web-app id ="WebApp_9" version ="2.4" xmlns ="http://java.sun.com/xml/ns/j2ee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" > < display-name > Struts 2 Fileupload </ display-name > < filter > < filter-name > struts-cleanup </ filter-name > < filter-class > org.apache.struts2.dispatcher.ActionContextCleanUp </ filter-class > </ filter > < filter > < filter-name > struts2 </ filter-name > < filter-class > org.apache.struts2.dispatcher.FilterDispatcher </ filter-class > </ filter > < filter-mapping > < filter-name > struts-cleanup </ filter-name > < url-pattern > /* </ url-pattern > </ filter-mapping > < filter-mapping > < filter-name > struts2 </ filter-name > < url-pattern > /* </ url-pattern > </ filter-mapping > < welcome-file-list > < welcome-file > index.html </ welcome-file > </ welcome-file-list > </ web-app >
清單6 WEB-INF/web.xml
發布運行應用程式,在瀏覽器地址欄中鍵入:http://localhost:8080/Struts2_Fileupload/FileUpload.jsp,出現圖示頁面:
清單7 FileUpload頁面
選擇圖片檔案,填寫Caption並按下Submit按鈕提交,出現圖示頁面:
清單8 上傳成功頁面
更多配置
在運行上述例子,如果您留心一點的話,應該會探索服務器控制台有如下輸出:
Mar 20 , 2007 4 : 08 : 43 PM org.apache.struts2.dispatcher.Dispatcher getSaveDirINFO: Unable to find ‘struts.multipart.saveDir‘ property setting. Defaulting to javax.servlet.context.tempdirMar 20 , 2007 4 : 08 : 43 PM org.apache.struts2.interceptor.FileUploadInterceptor interceptINFO: Removing file myFile C:\Program Files\Tomcat 5.5 \work\Catalina\localhost\Struts2_Fileupload\upload_251447c2_1116e355841__7ff7_00000006.tmp
清單9 伺服器控制台輸出
上述資訊告訴我們,struts.multipart.saveDir沒有配置。struts.multipart.saveDir用於指定存放臨時檔案的檔案夾,該配置寫在struts.properties檔案中。例如,如果在struts.properties檔案加入如下代碼:
struts.multipart.saveDir = /tmp
清單10 struts配置
這樣上傳的檔案就會臨時儲存到你根目錄下的tmp檔案夾中(一般為c:\tmp),如果此檔案夾不存在,Struts 2會自動建立一個。
錯誤處理
上述例子實現的圖片上傳的功能,所以應該阻止使用者上傳非圖片類型的檔案。在Struts 2中如何?這點呢?其實這也很簡單,對上述例子作如下修改即可。
首先修改FileUpload.jsp,在<body>與<s:form>之間加入“<s:fielderror />”,用於在頁面上輸出錯誤資訊。
然後修改struts.xml檔案,將Action fileUpload的定義改為如下所示:
< action name ="fileUpload" class ="tutorial.FileUploadAction" > < interceptor-ref name ="fileUpload" > < param name ="allowedTypes" > image/bmp,image/png,image/gif,image/jpeg </ param > </ interceptor-ref > < interceptor-ref name ="defaultStack" /> < result name ="input" > /FileUpload.jsp </ result > < result name ="success" > /ShowUpload.jsp </ result > </ action >
清單11 修改後的設定檔
顯而易見,起作用就是fileUpload攔截器的allowTypes參數。另外,配置還引入defaultStack它會幫我們添加驗證等功能,所以在出錯之後會跳轉到名稱為“input”的結果,也即是FileUpload.jsp。
發布運行應用程式,出錯時,頁面如所示:
清單12 出錯提示頁面
上面的出錯提示是Struts 2預設的,大多數情況下,我們都需要自訂和國際化這些資訊。通過在全域的國際資源檔中加入“struts.messages.error.content.type.not.allowed=The file you uploaded is not a image”,可以實現以上提及的需求。對此有疑問的朋友可以參考我之前的文章《在Struts 2.0中國際化(i18n)您的應用程式》。
實現之後的出錯頁面如所示:
清單13 自訂出錯提示頁面
同樣的做法,你可以使用參數“maximumSize”來限制上傳檔案的大小,它對應的字元資源名為:“struts.messages.error.file.too.large”。
字元資源“struts.messages.error.uploading”用提示一般的上傳出錯資訊。
多檔案上傳
與單檔案上傳相似,Struts 2實現多檔案上傳也很簡單。你可以將多個<s:file />綁定Action的數組或列表。如下例所示。
< s:form action ="doMultipleUploadUsingList" method ="POST" enctype ="multipart/form-data" > < s:file label ="File (1)" name ="upload" /> < s:file label ="File (2)" name ="upload" /> < s:file label ="FIle (3)" name ="upload" /> < s:submit /> </ s:form >
清單14 多檔案上傳JSP程式碼片段
如果你希望綁定到數組,Action的代碼應類似:
private File[] uploads; private String[] uploadFileNames; private String[] uploadContentTypes; public File[] getUpload() { return this .uploads; } public void setUpload(File[] upload) { this .uploads = upload; } public String[] getUploadFileName() { return this .uploadFileNames; } public void setUploadFileName(String[] uploadFileName) { this .uploadFileNames = uploadFileName; } public String[] getUploadContentType() { return this .uploadContentTypes; } public void setUploadContentType(String[] uploadContentType) { this .uploadContentTypes = uploadContentType; }
清單15 多檔案上傳數組綁定Action程式碼片段
如果你想綁定到列表,則應類似:
private List < File > uploads = new ArrayList < File > (); private List < String > uploadFileNames = new ArrayList < String > (); private List < String > uploadContentTypes = new ArrayList < String > (); public List < File > getUpload() { return this .uploads; } public void setUpload(List < File > uploads) { this .uploads = uploads; } public List < String > getUploadFileName() { return this .uploadFileNames; } public void setUploadFileName(List < String > uploadFileNames) { this .uploadFileNames = uploadFileNames; } public List < String > getUploadContentType() { return this .uploadContentTypes; } public void setUploadContentType(List < String > contentTypes) { this .uploadContentTypes = contentTypes; }
清單16 多檔案上傳列表綁定Action程式碼片段
總結
在Struts 2中實現檔案上傳的確是輕而易舉,您要做的只是使用<s:file />與Action的屬性綁定。這又一次有力地證明了Struts 2的簡單易用。
本文轉自:http://www.blogjava.net/max/archive/2007/03/21/105124.html
轉:在Struts 2中實現檔案上傳