Struts2與OGNL的聯絡
1、Struts與OGNL的結合原理
(1)值棧:
OGNL表示式要想執行就要準備一個OGNLContext物件,Struts2內部含有一個OGNLContext物件,名字叫做值棧。
值棧也由兩部分組成,一部分叫做root,裡面放置的是棧,另一部分是context放入的是資料中心。
(2)棧:
利用了棧先進先出的特點,每次放入元素的時候是放入到索引為零的位置,取出的時候也是取出索引為零的元素,即:從下圖的最上方元素取,符合棧的先進先出的特性。
2、<s:debug>標籤(檢視值棧中的內容)
(1)root(棧)
預設情況下棧中存放當前訪問的Action。
(2)context:
存放以下這些東西:
即:
3、Struts2與OGNL結合的體現
(1)Action以屬性名的方式獲取資料解析:
直接輸出屬性名,保持和表單的name屬性的值相同。
表單將資料提交給攔截器,攔截器獲取到“name=zhai”後,交給OGNL處理,OGNL從root中拿到name屬性並賦值為“zhai”,由此,Action獲取到了表單提交的資料。
(2)物件方式:
表單:
獲取:
OGNL從棧頂獲得user物件後,獲得其name屬性並將其值設定為“zhai”,由此,Action獲取到了表單提交的資料。
(3)模型驅動
OGNL獲取到name=zhai後,在值棧的root中,將user壓入棧頂,並給user中的name賦值,也就是說從棧頂取元素並賦值。
原理演示:
建立一個Action:
public class ActionStack extends ActionSupport implements Preparable { User user=new User(); public String execute(){ System.out.println(user); return "success"; } @Override public void prepare() throws Exception { ValueStack valueStack=ActionContext.getContext().getValueStack(); valueStack.push(user); } }
實現Preparable介面的原因:
要在賦值前將user壓入棧頂 ,而將獲取棧的程式碼和將user物件壓入棧頂的程式碼寫入到prepare()函式中的目的正是獲取棧並在賦值前將user物件壓入棧頂。
原始碼分析:
<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="datetime"/> <interceptor-ref name="multiselect"/> <interceptor-ref name="staticParams"/> <interceptor-ref name="actionMappingParams"/> <interceptor-ref name="params"/> <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-ref name="deprecation"/> </interceptor-stack>
在眾多的攔截器中,params攔截器位置相對靠後,因此需要將params攔截器放到prepare攔截器的位置,以實現賦值前將user壓入棧頂。
那麼如何操作呢?開啟prepare攔截器的原始碼可知要呼叫prepare攔截器需要實現Preparable介面並呼叫 prepare()方法。
配置Struts的配置檔案、建立表單、User類後將表單資料提交給Action:
<body> <form action="${pageContext.request.contextPath}/s/ActionStack"> 使用者名稱:<input type="text" name="username"/><br> <input type="submit" value="提交"/> </form> </body>
public class ActionStack extends ActionSupport implements Preparable { User user=new User(); public String execute(){ System.out.println(user); return "success"; } @Override public void prepare() throws Exception { ValueStack valueStack=ActionContext.getContext().getValueStack(); valueStack.push(user); } }
4、在struts.xml配置檔案中的使用
(1)建立兩個Action:
Action1:
public class Action1 extends ActionSupport { private String name; public String execute(){ name="zhang"; return "success"; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Action2:
public class Action2 extends ActionSupport { public String execute(){ return "success"; } }
(2)配置Struts.xml配置檔案,使得訪問Action1的時候能夠重定向到Action2,:
<struts> <package name="action" namespace="/a" extends="struts-default"> <action name="Action2" class="pers.zhb.hello.Action2" method="execute"> <result name="success" type="dispatcher">hello.jsp</result> </action> <action name="Action1" class="pers.zhb.hello.Action1" method="execute"> <result name="success" type="redirectAction"> <param name="actionName">Action2</param> <param name="namespace">/a</param> <param name="name">${name}</param> </result> </action> </package> </struts>
(3)訪問Action1:
也就是說在配置struts.xml配置檔案的時候,在<param>標籤內部將name屬性的值設定為屬性不能識別的值,就可以在重定向的時候將引數加到另外一個Actio