一、文件上傳的原理
表單元素的enctype屬性指定的是表單數據的編碼方式,該屬性有3個值:
1、application/x-www-form-urlencoded:這是默認編碼方式,它只處理表單域里的value屬性值,采用這種編碼方式的表單會將表單域的值處理成URL編碼方式。
2、multipart/form-data:這種編碼方式的表單會以二進制流的方式來處理表單數據,這種編碼方式會把文件域指定文件的內容也封裝到請求參數里。
3、text/plain:這種方式主要適用於直接通過表單發送郵件的方式。文件上傳是web應用經常用到的一個知識。原理是,通過為表單元素設置
二、Struts2的文件上傳
Struts2並未提供自己的請求解析器,也就是就Struts2不會自己去處理multipart/form-data的請求,它需要調用其他請求解析器,將HTTP請求中的表單域解析出來。但Struts2在原有的上傳解析器基礎上做了進一步封裝,更進一步簡化了文件上傳。Struts2默認使用的是Jakarta的Common-FileUpload框架來上傳文件,因此,要在web應用中增加兩個Jar文件:commons-fileupload-1.2.jar和commons-io-1.3.1.jar。它在原上傳框架上做了進一步封裝,簡化了文件上傳的代碼實現,取消了不同上傳框架上的編程差異。如果要改成其它的文件上傳框架,可以修改struts.multipart.parser常量的值為cos/pell,默認值是jakata。並在classpath中增加相應上傳組件的類庫。
以下是如何利用Struts如何實現單文件上傳的示例:
1、首先是創建一個FileUpload.jsp頁面(此頁面特殊之處只是把表單的enctype屬性設置為multipart/form-data。)。
1 <%@ page language="java" contentType="text/html; charset=UTF-8"%> 2 <html> 3 <head> 4 <title>Struts2 File Upload</title> 5 </head> 6 <body> 7 <form action="fileUpload.action" method="POST" enctype="multipart/form-data"> 8 文件標題:<input type="text" name="title" size="50"/><br/> 9 選擇文件:<input type="file" name="upload" size="50"/><br/> 10 <input type="submit" value=" 上傳 "/> 11 </form> 12 </body> 13 </html>
2、創建處理上傳請求的Action類
1 package org.qiujy.web.struts2; 2 import java.io.BufferedInputStream; 3 import java.io.BufferedOutputStream; 4 import java.io.File; 5 import java.io.FileInputStream; 6 import java.io.FileOutputStream; 7 import java.io.InputStream; 8 import java.io.OutputStream; 9 import org.apache.struts2.ServletActionContext; 10 import com.opensymphony.xwork2.ActionSupport; 11 publicclass FileUploadAction extends ActionSupport { 12 privatestaticfinalintBUFFER_SIZE = 16 * 1024; 13 // 文件標題 14 private String title; 15 // 上傳文件域對象 16 private File upload; 17 // 上傳文件名 18 private String uploadFileName; 19 // 上傳文件類型 20 private String uploadContentType; 21 // 保存文件的目錄路徑(通過依賴注入) 22 private String savePath; 23 //以下省略getter和setter...... 24 //自己封裝的一個把源文件對象復制成目標文件對象 25 privatestaticvoid copy(File src, File dst) { 26 InputStream in = null; 27 OutputStream out = null; 28 try { 29 in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE); 30 out = new BufferedOutputStream(new FileOutputStream(dst), 31 BUFFER_SIZE); 32 byte[] buffer = newbyte[BUFFER_SIZE]; 33 int len = 0; 34 while ((len = in.read(buffer)) > 0) { 35 out.write(buffer, 0, len); 36 } 37 } catch (Exception e) { 38 e.printStackTrace(); 39 } finally { 40 if (null != in) { 41 try { 42 in.close(); 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 } 47 if (null != out) { 48 try { 49 out.close(); 50 } catch (IOException e) { 51 e.printStackTrace(); 52 } 53 } 54 } 55 } 56 @Override 57 public String execute() throws Exception { 58 //根據服務器的文件保存地址和原文件名創建目錄文件全路徑 59 String dstPath = ServletActionContext.getServletContext() 60 .getRealPath(this.getSavePath()) 61 + "\" + this.getUploadFileName(); 62 63 System.out.println("上傳的文件的類型:"+ this.getUploadContentType()); 64 65 File dstFile = new File(dstPath); 66 copy(this.upload, dstFile); 67 returnSUCCESS; 68 } 69 }
上面這個Action類中,提供了title和upload兩個屬性來分別對應頁面的兩個表單域屬性,用來封裝表單域的請求參數。但是,值得注意的是,此Action中還有兩個屬性:uploadFileName和uploadContentType,這兩個屬性分別用於封裝上傳文件的文件名、文件類型。這是Struts2設計的獨到之處:Strut2的Action類直接通過File類型屬性直接封裝了上傳文件的文件內容,但這個File屬性無法獲取上傳文件的文件名和文件類型,所以Struts2就直接將文件域中包含的上傳文件名和文件類型的信息封裝到uploadFileName和uploadContentType屬性中,也就是說Struts2針對表單中名為xxx的文件域,在對應的Action類中使用3個屬性來封裝該文件域信息:
1、類型為File的xxx屬性:用來封裝頁面文件域對應的文件內容。
2、類型為String的xxxFileName屬性:用來封裝該文件域對應的文件的文件名。
3、類型為String的xxxContentType屬性:用來封裝該文件域應用的文件的文件類型。
另外,在這個Action類中還有一個savePath屬性,它的值是通過配置文件(Struts.XML中的參數節點的設置)來動態設置的,這也是Strut2設計中的一個依賴注入特性的使用。
3、在Struts.xml中的配置文件的情況
1 <!DOCTYPE struts PUBLIC 2 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 3 "http://struts.apache.org/dtds/struts-2.0.dtd"> 4 <struts> 5 <package name ="fileUploadDemo" extends ="struts-default"> 6 <action name ="fileUpload" 7 class ="org.qiujy.web.struts2.FileUploadAction"> 8 <!-- 動態設置Action中的savePath屬性的值 --> 9 <param name="savePath">/upload</param> 10 <result name ="success">/showupload.jsp</result> 11 </action > 12 </package > 13 </struts>
1 <!DOCTYPE struts PUBLIC 2 "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 3 "http://struts.apache.org/dtds/struts-2.0.dtd">
4 <struts>
5 <constant name="struts.custom.i18n.resources" value="messages"/>
6 <package name="fileUploadDemo" extends="struts-default">
7 <action name="fileUpload"
8 class="org.qiujy.web.struts2.FileUploadAction">
9 <interceptor-ref name="fileUpload">
10 <!-- 配置允許上傳的文件類型,多個用","分隔 -->
11 <param name="allowedTypes">
12 image/bmp,image/png,image/gif,image/jpeg,image/jpg 13 ,image/x-png, image/pjpeg 14 </param>
15 <!-- 配置允許上傳的文件大小,單位字節 -->
16 <param name="maximumSize">102400</param>
17 </interceptor-ref>
18 <interceptor-ref name="defaultStack" />
19 <!-- 動態設置Action中的savePath屬性的值 -->
20 <param name="savePath">/upload</param>
21 <result name="input">/index.jsp</result>
22 <result name="success">/showupload.jsp</result>
23 </action>
24 </package>
25 </struts>
如果文件上傳失敗后,會跳轉到input節點中對應的index.jsp頁面,在index.jsp頁面中添加一個 <s:fielderror/>標簽,用於將錯誤信息顯示在index.jsp頁面中。然后進行運行調試。最后發現效果不是太友好,則可以利用Struts2的國際化標准來將錯誤進行重新定義。
新建一個國際化資源文件,Struts.propertites,然后補充資源文件中的內容如下所示:
#更改上傳文件類型不允許的提示信息
struts.messages.error.content.type.not.allowed=文件上傳失敗:你要上傳的文件類型不允許
#更改上傳文件太大的提示信息
struts.messages.error.file.too.large=文件上傳失敗:你要上傳的文件太大
#文件上傳其它錯誤信息
struts.messages.error.uploading=文件上傳失敗:發生內部錯誤
另外,在控制台會看一些消息例如:
Unable to find 'struts.multipart.saveDir' property setting. Defaulting to javax.servlet.context.tempdir
Removing file upload D:\tomcat6.0.13\work\Catalina\localhost\fileload_struts2\upload__4b616fd1_115a3d5d9dc__7fff_00000005.
第一個說是找不以struts.multipart.saveDir,即沒有指定臨時文件夾,這個很好解決,只需指定一個struts.multipart.saveDir常量值為某個目錄來解決。
第二個說正在刪除一個臨時文件,這個臨時文件是上傳過程中產生的,屬正常。
