struts2中,攔截器是非常核心的內容,框架默認提供的攔截器,我們可以從struts2-core-**.jar/struts-default.xml中查詢到,我們以struts2-core-2.3.15.3.jar爲例,打開struts-default.xml,可以看到如下的默認攔截器:
<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
在struts-default.xml中,除了定義了一些默認的攔截器以外,還有一些默認的攔截器堆。這也提示我們,不光可以在使用時引用一個個的攔截器,也可以使用攔截器堆的方式,一次引用多個攔截器。如:我們在struts.xml配置文件中,沒有配置攔截器的情況下,會默認引用以下這個攔截器堆:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params">
<param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>
</interceptor-ref>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
</interceptor-stack>
爲何我如此肯定,因爲在這個文件中,有以下代碼,我們在struts.xml中定義一個package元素時,通過也會extends這個struts-default.xml,那麼也表示我們引用這個攔截器堆:
<default-interceptor-ref name="defaultStack"/>
好了,抄了一陣struts的源碼,現在我們開始今天的事情:文件上傳
先來進行單文件上傳:
從上面的默認攔截器定義,可以看到,struts2給我們提供了一個現成的攔截器fileUpload,並且已經默認引用了。
我們先來做一些準備工作,做一個文件上傳的頁面,相信大家都還記得文件上傳的頁面必須滿足以下三個條件:
- 表單的提交方式必須是post
- 表單的enctype必須爲multipart/form-data
- 表單中必須提供一個type=file的input元素
以下就是這個表單提交的頁面:
<fieldset>
<legend>單文件上傳</legend>
<s:form action="single/upload.action" enctype="multipart/form-data" method="post">
<s:textfield name="name" label="姓名"></s:textfield>
<s:file name="photo" label="靚照"></s:file>
<s:submit value="上傳"></s:submit>
</s:form>
</fieldset>
上面使用的是struts2的標籤,當然也可以使用普通的html標籤。
上面的表單提交,我們需要一個action動作在來支持,我們先來在struts.xml中配置一下這個action動作
<package name="upload" extends="struts-default" namespace="/single">
<action name="upload" class="demo.action.SingleFileUploadAction" method="upload">
<result>/success.jsp</result>
</action>
</package>
那個成功的返回頁面success.jsp,沒有任何展示,大不了就提示一下成功了
<body>
上傳成功了
</body>
現在,我們就只差一個動作類了,我們來寫配置文件中配置的demo.action.SingleFileUploadAction這個動作類:
package demo.action;
//省略引入的包
/**
* 這個測試類,簡單起見,使用模型和動作爲同一個類的方式
* @author Minhellic
*
*/
public class SingleFileUploadAction extends ActionSupport {
private String name; //對應頁面上的name字段
private File photo; //對應頁面上要上傳的文件,必須使用File來接收
private String photoFileName; //上傳的文件名,XXXFileName這樣的固定寫法
private String photoContentType; //上傳文件的MIME類型, XXXContentType這樣的固定寫法
public String upload() throws IOException {
//普通的屬性,可以直接使用
System.out.println(name);
/*
* 完全文件上傳
*/
//1.得到文件上要傳的真實路徑
ServletContext sc = ServletActionContext.getServletContext();
String dirPath = sc.getRealPath("/files");//得到文件的真實保存路徑,需要在WebRoot根目錄下建一個files目錄
//2.構建目標文件
File target = new File(dirPath, photoFileName);
//3.複製文件
FileUtils.copyFile(photo, target);
return SUCCESS;
}
//省略各個屬性的getter和setter
}
以上代碼爲了簡潔,省略了導入的包和各個屬性的getter和setter,大家可以自己添加上。
通過上面的代碼可以看到,我們需要有一個文件夾來存放上傳的文件,本例,我們是在工程的根目錄下,用一個files文件夾來存放的,所以,我們在WebRoot下,建一個files文件夾
好了,最最粗糙的文件上傳完成了,先來看看效果
部署到tomcat,訪問這個上傳頁面:
隨便選張圖片,上傳下,果然,上傳成功了。我們到tomcat下去查看,在項目的根目錄下,發現有一個files目錄,打開這個目錄,發現確實上傳成功了
感覺是完成了。再來得瑟一下,這回我選擇一個視頻,大概有幾十M吧,然後
我操,這一定不是真的,剛纔玩得還好好的。關鍵是,控制檯還沒報錯,這怎麼辦?仔細看看這個報錯,發現報的是沒有input對應的邏輯視圖,可明明我們的action裏只返回了success,哪來的input,除了這個action,就只有一個可能,就是那個fileUpload攔截器乾的。
好吧,既然你說我沒有input視圖,那我給你一個,在struts.xml中,action的定義裏,添加一個result元素
<result name="input">/index.jsp</result>
再次去嘗試去上傳一個那個幾十M的視頻文件,這回倒是不報錯了,而是重新又回到了上傳頁面。
那麼問題來了,爲什麼呢?再上傳那張圖片是可以成功的,爲什麼視頻就不可以嗎?是因爲格式不對嗎?也沒有指定格式呀,按理說應該是可以支持所有格式的,畢竟只是一個上傳,又不是解析。
那會不會是大小的問題呢,可能性很大。因爲文件上傳不成功,無非不是路徑問題,文件格式問題,然後就是文件大小問題,前面已經成功過,那麼路徑是沒有問題的,格式的問題可能性很小。那麼我們來找找有沒有設置文件默認上傳大小的地方:
我們知道,struts2加載的時候,不單會加載struts-default.xml,還會加載一個叫default.properties的文件,我們在struts2-core-2.3.15.3.jar包中,找到這個文件,仔細一看,找到了:
struts.multipart.maxSize=2097152
原來這裏的文件默認大小這麼小,難怪上傳不上去,好吧,我們可以在struts.xml中,通過constant元素,來修改這個默認值
<constant name="struts.multipart.maxSize" value="100000000"></constant>
再次部署,試一下,終於成功了。在tomcat中,也找到了這個文件
感覺像是應該沒有問題了。然而如果把這樣的上傳頁面交付給甲方,相信這項目一定就沒希望了。我們想想,這個地方明明在頁面上寫的是要上傳“靚照”的,那也就是說這裏我們希望要上傳的是一張圖片。可用戶可不管那麼多,他什麼都有可能上傳,就像我剛纔一樣,居然會上傳一個視頻上來。而且,如果用戶上傳的文件不對,應該給出提示。
那麼,下面我們就來限制一下用戶上傳文件的大小和後綴名,如果用戶上傳的東西不對,那麼給用戶一個提示。
文件大小的限制,上面已經介紹了,那麼現在,就應該是要給出用戶提示了。
爲了方便測試,我先把上傳大小的限制調小一些,這樣基本上隨便一個文件都會過大,這樣好測試:
<constant name="struts.multipart.maxSize" value="1000"></constant>
struts2提供了一些標籤,可以用於展示這些提示信息,比如這次的錯誤提示,我們就可以在頁面上用以下標籤展示:
<s:actionerror/>
這樣,我們再次上傳一個超過大小的文件,則會在頁面上出現以下提示:
至於要把這個提示展示成中文的,則是可以通過國際化的配置來做,就不再是這篇博客要表現的東西了。