Struts2單文件上傳原理及示例


一、文件上傳的原理

   表單元素的enctype屬性指定的是表單數據的編碼方式,該屬性有3個值:

   1、application/x-www-form-urlencoded:這是默認編碼方式,它只處理表單域里的value屬性值,采用這種編碼方式的表單會將表單域的值處理成URL編碼方式。

   2、multipart/form-data:這種編碼方式的表單會以二進制流的方式來處理表單數據,這種編碼方式會把文件域指定文件的內容也封裝到請求參數里。

   3、text/plain:這種方式主要適用於直接通過表單發送郵件的方式。文件上傳是web應用經常用到的一個知識。原理是,通過為表單元素設置

enctype=”multipart/form-data”屬性,讓表單提交的數據以二進制編碼的方式提交,在接收此請求的Servlet中用二進制流來獲取內容,就可以取得上傳文件的內容,從而實現文件的上傳。 在Java領域中,有兩個常用的文件上傳項目:一個是Apache組織Jakarta的Common-FileUpload組件 (http://commons.apache.org/fileupload/),另一個是Oreilly組織的COS框架(http://www.servlets.com/cos/)。利用這兩個框架都能很方便的實現文件的上傳。

二、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>
       在這個文件中跟以前配置唯一不同的是給action配置了一個<param …/>元素,用來為該Action的savePath屬性動態注入值。 web.xml中的配置跟以前的應用一樣。說明一點:好多網絡文章說Struts2上傳時要在web.xml中配置一個名為 ActionContextUp的過濾器,說是有一些莫名的錯誤,可是是我用了Struts2新版本2.0.9GA版,測了n次,沒出現什么問題,所以沒配置。
     
     4、運行項目進行調試
     運行前要在根目錄下建立一個Upload文件夾,如果不建可在項目中的代碼中添加創建文件夾的代碼。用於存放上傳后的文件。
      
      5、文件類型及錯誤輸出
      Struts2提供了一個文件上傳的攔截器(名為fileUpload),通過配置這個攔截器能輕松地實現文件類型的過濾。在上例中,若要配置上傳的文件只能是一些普通的圖片文件格式:image/bmp、image/png、image/gif、image/jpeg、image/jpg等,則可在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     <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常量值為某個目錄來解決。

第二個說正在刪除一個臨時文件,這個臨時文件是上傳過程中產生的,屬正常。

 

     

    

   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM