這個章節是Struts2框架應用最普遍的三個版塊(上傳下載、國際化、校驗輸入)之一,因此這一版塊的學習還蠻重要的。html
本小節經過一個示例講解Struts2如何實現單文件的上傳。java
(1) 先寫一個選擇上傳單文件頁面(select.jsp)web
<%@ taglib prefix="s" uri="/struts-tags" %> <%-- Created by IntelliJ IDEA. User: mairr Date: 17-12-7 Time: 下午9:04 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" import="java.util.*" language="java" pageEncoding="UTF-8" %> <html> <head> <title>upload_test</title> </head> <body> <s:form action="upload" method="post" theme="simple" enctype="multipart/form-data"> 輸入賬號:<s:textfield name="uid"/><br> 選擇頭像:<s:file name="headImage"/><br> <s:submit value="提交"/>
<s:fielderror/>
</s:form> </body> </html>
以下所示的一個上傳選擇界面框:apache
(2) 當文件上傳頁面提交請求時,請求發送到upload.action,這是一個Struts2的Action,該Action處理上傳請求,具體的UploadAction類代碼以下:數組
package action; import com.opensymphony.xwork2.ActionSupport; import org.apache.commons.io.FileUtils; import org.apache.struts2.ServletActionContext; import java.io.File; import java.io.IOException; public class UploadAction extends ActionSupport { private String uid; // 封裝賬號(uid)請求參數屬性 private File headImage; // 封裝上傳文件域屬性 private String headImageContentType; // 封裝上傳文件類型的屬性 private String headImageFileName; // 封裝上傳文件屬性 public String getUid() { return uid; } public void setUid(String uid) { this.uid = uid; } public File getHeadImage() { return headImage; } public void setHeadImage(File headImage) { this.headImage = headImage; } public String getHeadImageContentType() { return headImageContentType; } public void setHeadImageContentType(String headImageContentType) { this.headImageContentType = headImageContentType; } public String getHeadImageFileName() { return headImageFileName; } public void setHeadImageFileName(String headImageFileName) { this.headImageFileName = headImageFileName; } public String execute() throws IOException { // 上傳文件的保存位置在「/image」,該位置在tomcat服務器的「webapps」之中 String realpath= ServletActionContext.getServletContext().getRealPath("/image"); // 聲明文件目錄image,若是文件名不存在就建一個唄~ File file = new File(realpath); if(!file.exists()){ file.mkdirs(); } // 實現文件上傳,也就是作了一個方法調用~ FileUtils.copyFile(headImage,new File(file,headImageFileName)); return SUCCESS; } }
須要注意的是,上面的Action除了包含兩個表單域的name屬性外,還包含headImageContentType和headImageFileName兩個屬性,這兩個屬性分別能用於封裝上傳文件的文件類型、上傳文件的文件名。能夠這樣認爲:若是表單中包含一個name屬性爲xxx的文件域,則對應的Action須要使用3個屬性來封裝文件域信息:瀏覽器
因此,在Action的execute方法中,能夠直接經過這3個屬性獲取上傳文件的文件名、文件類型和文件內容。tomcat
(3) 接下來進行UploadAction的配置(struts.xml文件配置),具體代碼以下:服務器
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!--指定國際化資源文件(下一章會講到)--> <constant name="struts.custom.i18n.resources" value="messageResource"/> <!--設置Struts應用的解碼集--> <constant name="struts.i18n.encoding" value="utf-8"/>
<!-- --- 包配置 ---- --> <package name="default" namespace="/" extends="struts-default"> <action name="upload" class="action.UploadAction"> <result>/uploadSuccess.jsp</result> </action> </package> </struts>
(4) 最後寫一個上傳成功頁面(uploadSuccess.jsp)app
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>上傳初始頁</title> </head> <body> 上傳成功!<br> <!--輸入表單裏的用戶賬號屬性--> 用戶賬號:<s:property value="uid"/><br> <!--根據上傳文件名字,顯示上傳頭像--> 您的頭像:<img src="<s:property value="'image/' + headImageFileName"/> " alt="圖像沒法顯示"/> </body> </html>
上傳過程圖:框架
(a)選擇圖片
(b)確認選擇
(c)提交以後,顯示上傳成功
Struts2提供了一個名爲fileUpload攔截器,經過配置該攔截器能夠輕鬆地實現文件過濾。爲了讓fileUpload攔截器起做用,只須要在處理文件上傳的Action中配置該攔截器引用便可。
配置fileUpload攔截器時能夠指定以下兩個參數:
當文件過濾失敗後,系統自動轉入input邏輯視圖,所以必須爲Action配置名爲input的邏輯視圖。
(1) 經過攔截器來實現文件過濾的struts.xml配置文件以下:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!--指定國際化資源文件(下一講會講到)--> <constant name="struts.custom.i18n.resources" value="messageResource"/> <!--設置Struts應用的解碼集--> <constant name="struts.i18n.encoding" value="utf-8"/> <!--package中加入攔截器--> <package name="default" namespace="/" extends="struts-default"> <interceptors> <!--配置攔截器棧(在攔截器章節有講述)--> <interceptor-stack name="myStack"> <!--配置fileUpload攔截器--> <interceptor-ref name="fileUpload"> <!--配置容許上傳文件的類型(此處要注意的是png圖片在ie瀏覽器中是image/x-png類型)--> <param name="allowedTypes">image/x-png,image/bmp,image/gif,image/jpeg,image/jpg</param> <!--配置容許上傳文件大小攔截器,單位是字節(2的16次冪=65536(64k))--> <param name="maximumSize">65536</param> </interceptor-ref> <interceptor-ref name="defaultStack"/> </interceptor-stack> </interceptors> <action name="upload" class="action.UploadAction"> <!--使用攔截器棧--> <interceptor-ref name="myStack"/> <result>/uploadSuccess.jsp</result> <!--過濾失敗,系統會轉入input邏輯視圖,這裏配置其返回選擇界面--> <result name="input">/select.jsp</result> </action> </package> </struts>
格式不對和容量大於64kb會上傳失敗,直接返回從新選擇的界面。若是上傳失敗,系統須要迴應上傳失敗信息。所以,須要在文件上傳頁selectFile.jsp頁面中加上「<s:filederror/>」------->(我直接加到了selectFile.jsp代碼中,你能夠回看上面)
(a) 文件格式不對
------(提交以後)------->
(b) 文件大小超過了限額
-------(提交以後)----->
上傳文件時,系統默認使用web服務器的工做路徑做爲臨時路徑。爲了不文件上傳時候使用Web服務器的工做路徑做爲臨時路徑,則應該設置struts.multipart.saveDir常量。該常量指定上傳文件的臨時保存路徑。該常量配置示例以下:
<constant name="struts.multipart.saveDir" value="HOME/....(寫上路徑)..."/>
此外,還有一個文件上傳的常量struts.multipart.maxSize。該常量指定struts.mutipart.maxSize。該常量指定在struts2文件上傳中整個請求內容所容許的最大字節數,默認爲2097152(即2MB)。該常量配置示例以下:
<constant name="struts.multipart.maxSize" value="209971520"/>
在Struts2應用中,若是一個頁面有多個文件域須要實現上傳,則能夠爲每一個文件域提供三個屬性,分別封裝該文件域對應的文件名、文件類型和文件內容。多文件上傳與單文件上傳沒有什麼區別,僅僅是利用數組同時上傳多個文件的方式。
在處理多文件上傳時,要注意改變的是,在Action類中,須要使用三個數組分別封裝文件名、文件類型和文件內容。
// 實現單文件上傳代碼以下: FileUtils.copyFile(headImage,new File(file,headImageFileName)); // 實現多文件下載代碼以下: for(int i = 0; i < headImage.length(); i++){ File uploadImage = headImage[i]; FileUtils.copyFile(uploadImage,new File(file,headImageFileName[i])); }
利用Struts2來處理文件的下載的問題時,可以解決下載文件的文件名爲中英文等等都不出現亂碼。此外,還可以在用戶下載以前進行檢查,判斷用戶是否有足夠的權限來下載該文件等。下面用一個示例來說解文件的下載:
(1) 先寫一個下載頁面:(index.jsp)
<%-- Created by IntelliJ IDEA. User: mairr Date: 17-12-9 Time: 下午2:20 To change this template use File | Settings | File Templates. --%> <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <html> <head> <title>test_download</title> </head> <body> 請下載中文課件:<a href="downLoad.action?downPath=第一章節.doc">中</a><br> 請下載英文課件:<a href="downLoad.action?downPath=chapter01.doc">英</a><br> </body> </html>
(2) 在Struts2框架文件下載Action類中,須要提供一個返回InputStream流方法,該輸入流表明了被下載文件的入口。該Action類代碼以下所示:(DownLoadAction.java)
package action; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.ServletActionContext; import util.MyUtil; import java.io.InputStream; import java.io.UnsupportedEncodingException; public class DownLoadAction extends ActionSupport{ private String downPath; // 下載時的文件名 private String contentType; // 保存文件類型 private String filename; // 保存時的文件名 public String getContentType() { return contentType; } public void setContentType(String contentType) { this.contentType = contentType; } public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public String getDownPath() { return downPath; } public void setDownPath(String downPath) { try { // 解決下載時候的中文文件亂碼問題 downPath = new String(downPath.getBytes("ISO-8859-1"),"UTF-8"); }catch (UnsupportedEncodingException e){ e.printStackTrace(); } this.downPath = downPath; } /* *下載用的Action返回一個InputString實例,該方法對應Action配置 *裏面的result的inputName參數,值爲inputString * */ public InputStream getInputString(){ return ServletActionContext.getServletContext().getResourceAsStream(downPath); } public String execute(){ // 下載保存時的文件名和被下載的文件名同樣 filename = downPath; // 下載的文件路徑,請在webapps目錄下建立images downPath = "images/" + downPath; // 保存文件的類型 contentType = "application/x-msdownload"; /* *對下載的文件名按照UTF-8進行編碼,解決下載窗口中的中文亂碼問題 * 其中,MyUtil是本身定義的一個類 */ filename = MyUtil.toUTF8String(filename); return SUCCESS; } }
(3) 在上述的Action類中定義了一個工具類MyUtil,該類中有一個靜態方法toUTF8String實現對下載的文件名按照UTF-8進行編碼,解決下載窗口中中文亂碼的問題:(MyUtil.java)
package util; import java.io.UnsupportedEncodingException; public class MyUtil { // 對下載文件按照 UTF-8 進行編碼 public static String toUTF8String(String str){ StringBuffer sb = new StringBuffer(); int len = str.length(); for (int i = 0; i < len; i++) { // 取出字符中的每一個字符 char c = str.charAt(i); // Unicode碼值在0~255之間,不作處理 if(c>=0 && c <= 255){ sb.append(c); }else { // 轉換 UTF-8 編碼 byte b[]; try{ b = Character.toString(c).getBytes("UTF-8"); }catch(UnsupportedEncodingException e){ e.printStackTrace(); b = null; } // 轉換爲%HH的字符串形式 for(int j = 0;j < b.length ; j++){ int k = b[j]; if(k < 0){ k &= 255; } sb.append("%" + Integer.toHexString(k).toUpperCase()); } } } return sb.toString(); } }
(4) 最後,完成Action的配置,關鍵是要配置一個類型爲stream的結果,配置時須要指定以下四個屬性:
具體代碼以下:(struts.xml)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <package name="default" namespace="/" extends="struts-default"> <action name="downLoad" class="action.DownLoadAction"> <!--結果類型爲String--> <result type="stream"> <param name="contentType">${contentType}</param> <!--默認就是inputStream,它將會指示StreamResult經過 inputName屬性值的getter和setter方法,如這裏就是 getInputStream()來獲取下載文件的內容,意味着Action 要有這個方法 --> <param name="inputName">inputStream</param> <!--默認爲inline(在線打開),設置爲attachment將會告訴瀏覽器下載 該文件,filename指定下載文件時的文件名,若未指定將會以瀏覽器 頁面名做爲文件名,如:以download.action做爲文件名 --> <param name="contentDisposition">attachment;filename=${filename}</param> <!--指定下載文件的緩衝大小--> <param name="bufferSize">4096</param> </result> </action> </package>
(5) 最後的下載窗口: