Struts2攔截器之FileUploadInterceptor


 一、它能做什么?

 借助於這個攔截器我們可以實現文件的上傳和下載功能。

 理論部分:

struts2的文件上傳下載功能也要依賴於Apache commons-fileupload和Apache commons-io兩個開源項目,要使用上傳功能就需要把它們引入到classpath中。

比如考慮上傳文件,幾個關鍵點就是可以傳什么類型的文件?可以傳多大的文件?傳過來以后放哪兒?叫什么名字?

當文件上傳過來的時候是放在一個臨時目錄里的,我們在Action中持有一個成員屬性File,這個File指向的就是服務器存放上傳文件的臨時目錄中的實際文件(臨時目錄中的文件不會長久保存)

這個是default.properties中默認的一些屬性,不配置臨時目錄的話默認就是用javax.servlet.context.tempdir

# uses javax.servlet.context.tempdir by default
struts.multipart.saveDir=
struts.multipart.maxSize=2097152

可以在配置文件中使用配置常量,這個配置的常量是全局的,意思就是struts.multipart.saveDir表示所有上傳的文件都臨時保存在這個目錄中,而struts.multipart.maxSize指的是整個項目的上傳文件的最大的size不能超過多少。

而下面這個是在action下設置的,針對的是單個的Action級別的:

allowedExtensionsSet 允許的文件類型擴展名,基於擴展名檢查並不是特別靠譜

allowedTypesSet 允許的文件類型

maximumSize 允許的文件大小,這個zhide是一次上傳的文件大小的上限

二、如何做?

1. 單文件上傳:

首先來一個最簡單的用法,即一次上傳一個文件,參數都使用默認值。

只需要寫一個前端:

  <form action="uploadAction" method="post" enctype="multipart/form-data">
      <input type="file" name="file"/><br/>
      <input type="submit" value="上傳" />
  </form>

  然后定義Action:

 1 public class UploadAction extends ActionSupport {
 2 
 3     private File file; //與表單file控件的name一致,指向了服務器臨時目錄中的上傳文件
 4     private String fileContentType; //File變量的名+ContentType,表示文件的MIME類型
 5     private String fileFileName; //File變量的名+FileName,表示文件上傳之前的名稱
 6 
 7     @Override
 8     public String execute() throws Exception {
 9         
10         System.out.println(file+" "+fileContentType+" "+fileFileName);
11         
12         //do something...
13         
14         return SUCCESS;
15     }
16 
17     public File getFile() {
18         return file;
19     }
20 
21     public void setFile(File file) {
22         this.file = file;
23     }
24 
25     public String getFileContentType() {
26         return fileContentType;
27     }
28 
29     public void setFileContentType(String fileContentType) {
30         this.fileContentType = fileContentType;
31     }
32 
33     public String getFileFileName() {
34         return fileFileName;
35     }
36 
37     public void setFileFileName(String fileFileName) {
38         this.fileFileName = fileFileName;
39     }
40 
41 }

 Action中的三個變量:

File file : 對於單文件上傳類型,這個文件的名字必須是File類型的並且變量的名字要和前端表單的文件控件的name屬性一致,會給這個變量賦值指向處於服務器上傳文件臨時目錄中的那個文件。

fileContentType :文件的MIME類型,比如image/jpeg,application/octet-stream之類的。

fileFileName : 文件名,文件在上傳之前在客戶端的磁盤上存在就必然有一個名字,這里就是那個名字。

總結一下單文件上傳:

1.表單的enctype="multipart/form-data"屬性。

2.Action的三個成員變量file(文件本身),fileContentType(文件MIME類型),fileFileName(文件名)。

2. 多文件上傳

  <form action="uploadAction" method="post" enctype="multipart/form-data">
      <input type="file" name="file"/><br/>
      <input type="file" name="file"/><br/>
      <input type="submit" value="上傳" />
  </form>

 Action:

 1 public class UploadAction extends ActionSupport {
 2 
 3     private File file[]; // 與表單file控件的name一致,指向了服務器臨時目錄中的上傳文件
 4     private String fileContentType[]; // File變量的名+ContentType,表示文件的MIME類型
 5     private String fileFileName[]; // File變量的名+FileName,表示文件上傳之前的名稱
 6 
 7     @Override
 8     public String execute() throws Exception {
 9 
10         for(int i=0;i<file.length;i++){
11             System.out.println(file[i]+" "+fileContentType[i]+" "+fileFileName[i]);
12         }
13         
14         // do something...
15 
16         return SUCCESS;
17     }
18 
19     public File[] getFile() {
20         return file;
21     }
22 
23     public void setFile(File[] file) {
24         this.file = file;
25     }
26 
27     public String[] getFileContentType() {
28         return fileContentType;
29     }
30 
31     public void setFileContentType(String[] fileContentType) {
32         this.fileContentType = fileContentType;
33     }
34 
35     public String[] getFileFileName() {
36         return fileFileName;
37     }
38 
39     public void setFileFileName(String[] fileFileName) {
40         this.fileFileName = fileFileName;
41     }
42 
43 }

 或者:

 1 public class UploadAction extends ActionSupport {
 2 
 3     private List<File> file; // 與表單file控件的name一致,指向了服務器臨時目錄中的上傳文件
 4     private List<String> fileContentType; // File變量的名+ContentType,表示文件的MIME類型
 5     private List<String> fileFileName; // File變量的名+FileName,表示文件上傳之前的名稱
 6 
 7     @Override
 8     public String execute() throws Exception {
 9 
10         for (int i = 0; i < file.size(); i++) {
11             System.out.println(file.get(i) + " " + fileContentType.get(i) + " "
12                     + fileFileName.get(i));
13         }
14 
15         // do something...
16 
17         return SUCCESS;
18     }
19 
20     public List<File> getFile() {
21         return file;
22     }
23 
24     public void setFile(List<File> file) {
25         this.file = file;
26     }
27 
28     public List<String> getFileContentType() {
29         return fileContentType;
30     }
31 
32     public void setFileContentType(List<String> fileContentType) {
33         this.fileContentType = fileContentType;
34     }
35 
36     public List<String> getFileFileName() {
37         return fileFileName;
38     }
39 
40     public void setFileFileName(List<String> fileFileName) {
41         this.fileFileName = fileFileName;
42     }
43 
44 }

 多文件上傳的要點就是在單文件上傳的基礎上前端多個名字相同的表單文件域,Action接收的地方改成File[]數組或者List<File>集合都可以。

3. 文件下載

 配置文件:

<?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="default" namespace="/" extends="struts-default" >
        <action name="downloadAction" class="struts_practice_001.DownloadAction">
            <!-- 要將結果類型設置為stream -->
            <result type="stream">
                <!-- inputName跟Action中的輸入流的名字要相同 -->
                <param name="inputName">file</param>
                <!-- contentDisposition的attachment表示讓瀏覽器的默認行為是保存文件,而filename是保存文件的時候的默認名字 -->
                <param name="contentDisposition">attachment;filename="psd.jpg"</param>
            </result>
        </action>
    </package>
</struts>

 Action:

 1 public class DownloadAction extends ActionSupport {
 2 
 3     private InputStream file; //將要下載的文件讀到這個輸入流中
 4     
 5     @Override
 6     public String execute() throws Exception {
 7         file=ServletActionContext.getServletContext().getResourceAsStream("psb.jpg");
 8         return SUCCESS;
 9     }
10 
11     public InputStream getFile() {
12         return file;
13     }
14 
15     public void setFile(InputStream file) {
16         this.file = file;
17     }
18     
19 }

 文件下載的關鍵點:

1. Action中有一個InputStream,里面是要被下載的文件的流。

2.配置文件中配置一個為stream類型的結果,傳入兩個參數:inputName跟Action的InputStream名字保持一致,contentDisposition是給瀏覽器看的提示。

4.配置參數詳解

<struts>
    <!-- 文件上傳到服務器的臨時目錄 -->
    <constant name="struts.multipart.saveDir" value="/tempUpload"></constant>
    <!-- 允許的文件最大尺寸(全局) -->
    <constant name="struts.multipart.maxSize" value="1024000000"></constant>

    <package name="default" namespace="/" extends="struts-default" >
        <action name="uploadAction" class="struts_practice_001.UploadAction">
            <result>/success.jsp</result>
            <interceptor-ref name="fileUpload">
                <!-- 允許的MIME類型 -->
                <param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg</param>
                <!-- 允許上傳文件的最大尺寸 -->
                <param name="maximumSize">1024000</param>
            </interceptor-ref>
            <!-- 一定要寫在后面 -->
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
    </package>
</struts>

 這里有一點關於參數上的疑問,就是<constant name="struts.multipart.saveDir" value="/tempUpload" />我這樣寫的話這個目錄究竟保存到了哪里呢?看別的博客上說的是

 發現我的也是保存到了E盤上,但是這種說法很沒有是根本沒有說服力,設想一下如果讓我們來設計的話,肯定要優先保存到剩余可用空間最大的分區上啦。

如果路徑沒有以/開頭的話就是保存到user.dir。

參考資料:Struts2中的struts.multipart.saveDir的配置

 三、原理是啥?

 

 。。。。好長,以后閑下來再慢慢分析源碼吧。。。

 (沒錯,就這么太監了.....我發現寫東西是件很奇妙的事情,有的時候連着寫好幾個小時感覺很爽,有的時候寫不到十分鍾就感覺頭和蛋一起疼明明寫不出來還硬要使勁擠牙膏....o(╯□╰)o)

 


免責聲明!

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



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