1.什么是值棧
在Servlet中蛉腌,我們都是把數(shù)據(jù)放在域?qū)ο笾校缓笤趈sp頁面中進(jìn)行讀取。那么在Struts2中烙丛,提供了另外一種存儲(chǔ)機(jī)制舅巷,就是值棧,在action中把值放入值棧河咽,在頁面中進(jìn)行讀取钠右。
2.action和servlet的區(qū)別
action:每次訪問的時(shí)候都會(huì)創(chuàng)建一次。
servlet:默認(rèn)在第一次訪問的時(shí)候創(chuàng)建忘蟹,在生命周期里只會(huì)創(chuàng)建一次飒房。
我們創(chuàng)建一個(gè)LifeAction來看看
@SuppressWarnings("serial")
public class LifeAction extends ActionSupport {
public LifeAction() {
System.out.println("action創(chuàng)建了。媚值。狠毯。。");
}
@Override
public String execute() throws Exception {
// 沒有操作
return NONE;
}
}
在該類中有一個(gè)構(gòu)造方法杂腰,每次創(chuàng)建action的時(shí)候都會(huì)打印信息垃你。
在struts.xml中配置action
<action name="life" class="com.codeliu.action.LifeAction"></action>
訪問后,每次刷新頁面喂很,都會(huì)創(chuàng)建一個(gè)action對(duì)象惜颇。
3.值棧的存儲(chǔ)位置
每次創(chuàng)建一個(gè)action對(duì)象,都會(huì)跟隨著一個(gè)值棧對(duì)象少辣,也就是說每個(gè)action里面都有一個(gè)值棧凌摄。
4.獲取值棧對(duì)象
// 獲取ActionContext實(shí)例對(duì)象
ActionContext context = ActionContext.getContext();
// 獲取值棧對(duì)象
ValueStack stack1 = context.getValueStack();
ValueStack stack2 = context.getValueStack();
// true 說明每個(gè)action只有一個(gè)值棧對(duì)象
System.out.println(stack1 == stack2);
上述代碼通過ActionContext類獲取一個(gè)ValueStack(值棧),同時(shí)說明了一個(gè)action里面只有一個(gè)值棧漓帅。
5.值棧的內(nèi)部結(jié)構(gòu)
值棧分為兩部分锨亏。第一部分是root,第二部分是context忙干,通過給成程序加斷點(diǎn)器予,我們可以看到如下的結(jié)果
context是OgnlContext的實(shí)例對(duì)象,root是CompoundRoot的實(shí)例對(duì)象捐迫,我們看看這兩個(gè)類的定義
public class CompoundRoot extends ArrayList {......}
public class OgnlContext extends Object implements Map {......}
這說明root其實(shí)本質(zhì)是一個(gè)ArrayList乾翔,而context本質(zhì)是一個(gè)Map。
root中一般存放數(shù)值施戴,而context一般存放對(duì)象的引用反浓。
下面是context的存儲(chǔ)示意圖
通過debug標(biāo)簽,可以查看值棧的內(nèi)部結(jié)構(gòu)赞哗。(要使用Struts2的標(biāo)簽雷则,必須在jsp開頭引入標(biāo)簽庫)
創(chuàng)建一個(gè)ValueStackAction.java
@SuppressWarnings("serial")
public class ValueStackAction extends ActionSupport {
@Override
public String execute() throws Exception {
return SUCCESS;
}
}
在struts.xml中配置Action
<action name="valueStack" class="com.codeliu.action.ValueStackAction">
<result name="success">/valueStack.jsp</result>
</action>
然后創(chuàng)建一個(gè)valueStack.jsp
<body>
<!-- 通過這個(gè)標(biāo)簽獲取值棧的信息 -->
<s:debug></s:debug>
</body>
運(yùn)行這個(gè)action之后就能看到一個(gè)鏈接,點(diǎn)進(jìn)去就能看到值棧的狀態(tài)
可以看到root內(nèi)部的棧頂是一個(gè)action實(shí)例肪笋。
action對(duì)象里有一個(gè)值棧對(duì)象月劈,值棧對(duì)象里有action引用度迂。
6.向棧中放數(shù)據(jù)
向值棧中放數(shù)據(jù)有三種方法,分別是使用set方法艺栈,push方法和使用action的變量英岭,下面來看一下。
(1)使用set方法
public class ValueStackAction extends ActionSupport {
@Override
public String execute() throws Exception {
/**
* 往值棧中放數(shù)據(jù)的三種方法
*/
// 第一種 使用set方法
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
stack.set("url", "www.codeliu.com");
return SUCCESS;
}
}
同樣使用debug標(biāo)簽查看值棧的狀態(tài)湿右,發(fā)現(xiàn)棧頂元素變成了我們插入的數(shù)據(jù)Map
(2)使用push方法
@SuppressWarnings("serial")
public class ValueStackAction extends ActionSupport {
@Override
public String execute() throws Exception {
/**
* 往值棧中放數(shù)據(jù)的三種方法
*/
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
// 第二種 使用push方法
stack.push("codeliu");
return SUCCESS;
}
}
再次查看诅妹,發(fā)現(xiàn)棧頂元素變成了一個(gè)String
(3)使用Action類的變量來放數(shù)據(jù)
@SuppressWarnings("serial")
public class ValueStackAction extends ActionSupport {
// 1. 定義變量
private String url;
// 2. 記得要get方法
public String getUrl() {
return url;
}
@Override
public String execute() throws Exception {
/**
* 往值棧中放數(shù)據(jù)的三種方法
*/
// 3.設(shè)置值
url = "www.codeliu.com";
return SUCCESS;
}
}
刷新查看值棧,結(jié)果如下
我們發(fā)現(xiàn)棧頂元素沒有變吭狡,但action實(shí)例中多了一行。
一般我們使用第三種方法更多丈莺,因?yàn)檫@樣更節(jié)省空間划煮,同時(shí)使用第三種方法,記得提供get方法缔俄,不然無法插入弛秋。
7.從棧中讀數(shù)據(jù)
現(xiàn)在我們看看使用OGNL+Struts2的標(biāo)簽從值棧中讀取使用上面第三種方法放入的數(shù)據(jù)。
(1)讀字符串的值
@SuppressWarnings("serial")
/**
* 從值棧中獲取字符串俐载、對(duì)象和List集合
* @author liu
*/
public class GetValueFromValueStackAction extends ActionSupport {
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public GetValueFromValueStackAction() {}
@Override
public String execute() throws Exception {
url = "www.codeliu.com";
return SUCCESS;
}
}
在struts.xml中增加一條記錄
<action name="getValue" class="com.codeliu.action.GetValueFromValueStackAction">
<result>/getvalue.jsp</result>
</action>
創(chuàng)建getvalue.jsp
<body>
<!-- OGNL集合Struts2的標(biāo)簽獲取值棧中的值 -->
<s:property value="url"/>
</body>
啟動(dòng)tomcat后蟹略,進(jìn)入網(wǎng)頁就能看到輸出了url的值。
(2)讀對(duì)象的值
還記得我們上篇文章中有一個(gè)User類遏佣,里面有username和password屬性挖炬,現(xiàn)在我們修改GetValueFromValueStackAction類
@SuppressWarnings("serial")
/**
* 從值棧中獲取字符串、對(duì)象和List集合
* @author liu
*/
public class GetValueFromValueStackAction extends ActionSupport {
private User user = new User();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public GetValueFromValueStackAction() {}
@Override
public String execute() throws Exception {
user.setUsername("CodeTiger");
user.setPassword("123456");
return SUCCESS;
}
}
在getvalue.jsp中添加如下代碼
<!-- 通過ognl獲取user對(duì)象的值 -->
<s:property value="user.username"/>
<s:property value="user.password"/>
運(yùn)行后状婶,輸出我們?cè)O(shè)置的值意敛。
(3)讀List集合的值
修改GetValueFromValueStackAction類的代碼如下
@SuppressWarnings("serial")
/**
* 從值棧中獲取字符串、對(duì)象和List集合
* @author liu
*/
public class GetValueFromValueStackAction extends ActionSupport {
private User user = new User();
private List<User> list = new ArrayList<User>();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
public GetValueFromValueStackAction() {}
@Override
public String execute() throws Exception {
user.setUsername("CodeTiger");
user.setPassword("123456");
list.add(user);
return SUCCESS;
}
}
讀取值棧中的List膛虫,一般有三種方法
<!-- 獲取List集合中的值 -->
<!-- 第一種方式 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/><br>
<!-- 第二種方式 -->
<s:iterator value="list">
<s:property value="username"/>
<s:property value="password"/>
</s:iterator><br>
<!-- 第三種方式 -->
<s:iterator value="list" var="user">
<!-- 每次遍歷出來的user對(duì)象草姻,都會(huì)放到context中去,使用OGNL取root中的數(shù)據(jù)稍刀,
可以不用#碴倾,但取context中的數(shù)據(jù),則要加上#
-->
<s:property value="#user.username"/>
<s:property value="#user.password"/>
</s:iterator>
注意第三種方式
下篇文章講OGNL掉丽,所以講OGNL之前得先熟悉了解一下值棧,才能更好的使用OGNL异雁。