本菜鳥開始寫博客啦......
一、Struts2的主要組建
FilterDispatcher:中央控制作用的過濾器
Action:處於Model層的Action,調用JavaBean實現業務邏輯
struts.xml:核心配置文件,配置有Action、Result等
result:與forward類似,轉發的目的地,支持多種視圖技術。
二、Struts2的Action訪問web對象
Action是一個普通的POJO對象,與web的四大內置對象未耦合在一起,便於單獨測試Action
訪問這些web內部對象有2種方式:
1. 直接訪問Web對象
Struts2框架提供org.apache.struts2.ServletActionContext輔助類來獲得web對象。
HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); HttpSession session = request.getSession(); ServletContext application = ServletActionContext.getServletContext();
2. Action訪問ActionContext
com.opensymphony.xwork2.ActionContext是一個Action執行的上下文,Action執行期間所用到的對象都保存在ActionContext中,例如session、參數等,並且ActionContext是一個局部線程變量,不用擔心Action的線程安全。
ActionContext context = ActionContext.getContext(); ActionContext中的常用方法 Object get(Object key): 使用key來查找當前ActionContext中的值 Map getApplication(): 返回一個Application範圍的Map static ActionContext getContext() :獲得當前線程的ActionContext實例 Map getParameters(): Map類型的所有HttpServletRequest的參數 Map getSession(): Map類型的HttpSession值 ValueStack getValueStack(): 返回一個ValueStack類型OGNL值棧 void put(Object key,Object value): 向當前ActionContext存入值,等於在HttpServletRequest中加入值 void setApplication(Map application): 設置application上下文 void setSession(Map session): 設置session值,參數爲Map實例 這種方法使用的所有對象和Web對象沒有直接聯繫,所以在測試的時候也是很方便的。
三、Action的分類
1. 繼承ActionSupport實現Action
通過繼承ActionSupport來實現Action是我們的推薦做法,因爲ActionSupport中提供了輸入驗證、國際化、execute等常用方法,使得編寫Action時代碼很簡單。
2. 模型驅動(ModelDriven)的Action
Struts2的Action屬於model層,Action中的方法代表業務邏輯,Action中的屬性代表請求中的參數,當頁面請求參數較多的時候,把過多的參數對象的屬性定義在Action中不太符合Struts所倡導的鬆耦合原則,所以我們推薦單獨用JavaBean來封裝參數,在Action中爲JavaBean賦值,這就是ModelDriven的Action。模型驅動的Action要求Action實現ModelDriven接口,假如登錄頁面需要傳輸參數username和userpass,我們把這2個參數封裝在一個數據的JavaBean中,然後在Action中定義該JavaBean爲Model即可,代碼如下:
UserInfo.java
package po; //用戶名和密碼封裝對象 public class UserInfo { private String username; private String userpass; get...; set...; }
UserAction.java
import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class UserAction extends ActionSupport implements ModelDriven<Userinfo> { private Userinfo model = new Userinfo(); @Override public String execute() throws Exception { // TODO Auto-generated method stub return SUCCESS; } //返回模型對象的實例 public Userinfo getModel() { // TODO Auto-generated method stub return model; } }
當請求該Action的時候,請求中的參數會自動填充到模型Userinfo的屬性中,當然需要參數名和屬性名一樣,到跳轉的頁面上利用Struts2標籤<s:property value="username" />可以取出模型Userinfo中的屬性username。在ModelDriven接口中的方法getModel()必須實現,通過它告訴系統模型的具體對象是什麼。
3. 多方法的Action
Action中的方法代表業務邏輯,那麼一個模塊中的多個業務邏輯如何用Action來處理呢?我們有2種辦法來處理這個問題:
1. 一個Action對應一個業務邏輯,實現方便,但是Action數量多,struts.xml中需要配置的內容也多,這種方法不推薦;
2. 一個Action對應多個業務邏輯,例如表的CRUD操作,含有多個業務邏輯,我們只寫一個Action來實現,Action的數量沒有增加,struts.xml的配置也簡單,所以這種方法是我們推薦的做法。
Action中自定義方法的聲明和execute方法一樣,方法的調用路徑爲“Action名稱!方法名稱.action”。
以用戶表Userinfo的CRUD操作爲例,看一下多方法Action的代碼:
import po.Userinfo; import service.UserService; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class CrudUserAction extends ActionSupport implements ModelDriven<Userinfo> { // crud業務方法 private UserService userservice = new UserService(); private Userinfo userinfo = new Userinfo(); // 模型對象userinfo public Userinfo getModel() { // TODO Auto-generated method stub return userinfo; } // 增加 public String create() throws Exception { userservice.createUser(userinfo); return SUCCESS; } // 查詢 public String retrive() throws Exception { // 查詢結果放在request中 ActionContext.getContext().put("userlist", userservice.selectUsers()); return "list"; } // 修改 public String update() throws Exception { userservice.updateUser(userinfo); return SUCCESS; } // 刪除 public String delete() throws Exception { userservice.deleteUser(userinfo.getUsername()); return SUCCESS; } // 默認的execute public String execute() throws Exception { return SUCCESS; } }
在struts.xml中配置如下:
<?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="actions" extends="struts-default"> <action name="CrudUser" class="action.CrudUserAction"> <result>/Success.jsp</result> <result name="list">/UserList.jsp</result> </action> </package> </struts>
除了以上方式,還可以在<action>標籤中配置method屬性,使用通配符。
四、Result類型
Action中表示跳轉的目的地使用了在struts.xml配置的字符串,格式爲:<result name=”” type=””></result>,type可以有多種選擇,Struts2支持各種視圖技術,例如JSP、JSF、XML等,默認的是JSP。常見的type類型配置如下:
dispatcher—轉發到JSP頁面,默認
redirect—重定向到JSP頁面
redirect-action—重定向到action,目的地爲Action,配置時可以指定如下兩個參數:actionName-重定向的Action名;namespace-重定向的Action所在的命名空間
chain—轉發到action,形成action-chain,可以指定兩個參數:actionName-重定向的Action名;namespace-重定向的Action所在的命名空間。
stream—用於向頁面返回一個InputStream,原始數據直接傳遞給HttpServletResponse,這種結果類型在用戶下載文件(例如PDF文件等)等情況下非常有意義.
plantext—用於輸出目的地JSP/HTML的源代碼內容,可以指定兩個參數:location-目的地JSP/HTML,charSet-輸出內容時使用的字符集。
除了上述類型以外,還支持如下的類型:
chart:用於整合JFreeChart的result類型;
freemarker:用於整合FreeMarker的result類型;
httpheader:用於處理特殊http行爲的result類型;
jasper:用於整合JasperReport的result類型;
jsf:用於整合JSF的result類型;
titles:用於整合Titles的result類型;
velocity:用於整合Velocity的result類型;
xslt:用於整合XML/XSLT的result類型。
這些視圖技術的支持,有些還需要導入相應的插件包,即Struts2提供的含有plugin字樣的jar包。
五、Strut2的國際化
在struts.xml中配置struts.custom.i18n.resources常量
<constant name="struts.custom.i18n.resources" value="globalMessages"/>
在src目錄下建立中文和英文的資源文件
六、Struts2攔截器
攔截器(interceptor)是Struts2框架核心組成部分。很多功能都是構建在攔截器基礎之上的,例如文件的上傳和下載、國際化、數據類型轉換和數據有效性驗證等,Struts2利用內建的攔截器,完成了框架內的大部分操作。
攔截器就是動態攔截Action調用的對象。它提供了一種機制,使開發者可以定義一個特定的功能模塊,這個模塊可以在Action執行之前或之後運行,也可以在一個Action執行之前阻止Action執行。同時也提供了一種可以提取Action中可重用部分的方式。
Struts2框架的Action被一個或者多個攔截器(攔截器棧)所包圍,所有的用戶請求都會被攔截器所攔截,然後交給Action處理,處理結果以邏輯視圖的方式返回給用戶。而這個調用的執行流程,是由Strut2的配置文件(struts.xml)來實現的。
在前面幾節中,沒有明確說明攔截器,爲什麼可以直接調用Action呢?那是因爲在Struts2框架中如果沒有顯式的攔截器配置,則系統會調用默認的攔截器來調用Action,在用戶看來,好像沒有配置攔截器一樣。演示一個簡單攔截器的開發:HelloWorld攔截器。假設我們需要實現這麼一個功能,在調用每個Action之前都能在控制檯打印出“HelloWorld”。這樣的一個功能使用Struts2攔截器來實現最簡單。下面介紹一個具體的實現步驟。
HelloWorldInterceptor.java
package interceptor; import action.MyAction; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; public class HelloWorldInterceptor extends AbstractInterceptor { //攔截方法 @Override public String intercept(ActionInvocation arg0) throws Exception { // 獲得被調用的Action類 Object action = arg0.getAction(); // 打印HelloWorld System.out.println("攔截器信息:HelloWorld!"); // 執行Action或調用下一個攔截器 String result = arg0.invoke(); // 執行完action後提示 System.out.println("Action執行完畢!"); return result; } }
在struts.xml中加入攔截器的配置 <?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="action" extends="struts-default"> <!-- 定義攔截器 --> <interceptors> <interceptor name="helloworld" class="interceptor.HelloWorldInterceptor"/> </interceptors> <action name="test" class="action.MyAction"> <result>Success.jsp</result> <!-- action中引用默認攔截器--> <interceptor-ref name="defaultStack" /> <!-- action中引用攔截器--> <interceptor-ref name="helloworld"/> </action> </package> </struts>
七、攔截器應用實例-文件上傳和下載
上傳單個文件
<body> <s:form action="fileupload" method="post" enctype="multipart/form-data"> 上傳文件:<s:file name="doc"/><br> <s:submit value="上傳"/> </s:form> </body>
form表單的enctype屬性設置爲multipart/form-data。enctype用來指定表單數據的編碼方式,有如下3個值。
1. application/x-www-form-urlencoded:指定該值,則表單中的數據被編碼爲Key-Value對,這是默認的編碼方式。
2. multipart/form-data:使用mime編碼,會以二進制流的方式來處理表單數據,文件上傳需要使用該編碼方式。
3. text/plain:表單數據以純文本形式進行編碼,其中不含任何控件和格式字符。
file類型表單域doc用於選擇上傳文件,它和Action中的java.io.File類型的屬性doc對應,同時上傳文件的文件名對應於Action中的屬性docFileName,上傳文件的文件類型對應於Action中的屬性docContentType。一般說來,爲了上傳文件,如果表單域名稱爲xxx,那麼在Action中應建立如下3個屬性來接收上傳文件的信息。
private java.io.File xxx;//封裝上傳文件的二進制內容 private String xxxContentType;//封裝上傳文件的文件類型 private String xxxFileName;//封裝上傳文件的文件名
上傳文件的過濾
上傳文件的時候可以限制上傳文件的類型和大小,使用攔截器來實現。文件上傳的攔截器是系統攔截器,我們只要配置參數就可以了。
<struts> <!-- 上傳文件的臨時保存目錄--> <constant name="struts.multipart.saveDir" value="/tmp" /> <package name="action" extends="struts-default"> <action name="fileupload" class="action.FileUploadAction"> <result>/Success.jsp</result> <result name="input">/index.jsp</result> <interceptor-ref name="fileUpload"> <!-- 允許上傳的文件類型 --> <param name="allowedTypes">image/bmp,image/png,image/gif,image/jpeg </param> <!--上傳文件的最大容量單位字節--> <param name="maximumSize">20000</param> </interceptor-ref> <interceptor-ref name="defaultStack" /> </action> </package> </struts>
在struts.xml中配置<constant name="struts.multipart.saveDir" value="/tmp" />用於指定上傳文件保存的臨時目錄,上傳完成後系統會自動刪除臨時目錄中的內容。
文件下載
public class FileDownloadAction extends ActionSupport { private String inputpath; //下載文件路徑 private String contenttype; //文件類型 private String filename;//文件名 //返回一個InputStream類型 public java.io.InputStream getInputStream() { return ServletActionContext.getServletContext().getResourceAsStream(inputpath); } @Override public String execute() throws Exception { //調用相關業務邏輯方法動態設置下載信息 inputpath = "/updfile/Bliss.jpg"; contenttype = "image/jpeg"; //解決下載的中文文件名問題 filename = java.net.URLEncoder.encode("文件.jpg","utf-8"); return SUCCESS; }
struts.xml中配置下載Action的result類型爲stream,內容如下:
<action name="filedownload" class="action.FileDownloadAction"> <result name="success" type="stream"> <!-- 定義相關參數 --> <param name="contentType">${contenttype}</param> <param name="inputName">inputStream</param> <param name="bufferSize">4096</param> <param name="contentDisposition">attachment;filename=${filename}</param> </result> </action>