Struts2中的valueStack



 Struts2中的ValueStack 

一、值栈 

 

值栈(ValueStack)是Struts 2  的一个核心概念,类似于正常的栈,符合后进先出的栈特点,可以在值栈中放入、删除和查询对象。Struts  2对OGNL进行了扩充,将值栈作为OGNL的根对象。  ValueStack实际上就是对OGNL的封装,OGNL主要的功能就是赋值与取值,Struts2正是通过ValueStack来进行赋值与取值的!

 


ValueStack是一个接口,而OgnlValueStack是strtus2中的缺省实现。ValueStack中的数据,分两个部分存放:root和context(这与OGNL中的概念一致),同时ValueStack暴露相关的接口:

void setValue(String expr, Object value);

Object findValue(String expr);

用来通过OGNL表达式对ValueStack中的数据进行操作!


二、栈的基本操作 

 

ValueStack中的root对象是CompoundRoot,CompoundRoot继承了ArraryList,提供了额外的方法:push()和pop()方法,用来对root对象中所包含的数据进行存取!

public class CompoundRoot extends ArrayList {

 

    public CompoundRoot() {

    }

 

    public CompoundRoot(List list) {

        super(list);

    }

 

 

    public CompoundRoot cutStack(int index) {

        return new CompoundRoot(subList(index, size()));

    }

 

    public Object peek() {

        return get(0);

    }

 

    public Object pop() {

        return remove(0);

    }

 

    public void push(Object o) {

        add(0, o);

    }

}
 

 

正是通过这两个方法,CompoundRoot变成了一个栈结构!压栈操作,将导致对象被放到CompoundRoot的第0个元素上(第0个元素 是栈顶),其它对象被依次往后移动;出栈操作,将导致CompoundRoot的第0个元素被移除(即栈顶元素被弹出),其它对象被依次往前移动!

 

OGNL不支持多个root对象,而struts2能够支持多个root对象,它对OGNL做了扩展。

如果某个OGNL表达式被传递给ValueStack(即调用ValueStack的setValue或findValue方法),而表达式中包含 有对root对象的访问操作,ValueStack将依次从栈顶往栈底搜索CompoundRoot对象中所包含的对象,看哪个对象具有相应的属性,找到 之后,立刻返回。

 

在Struts2中,一个请求在最终到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以Action对象是CompoundRoot中的一个元素。看下面的代码:

public class UserAction {

    private String username;

    private Integer age;

    private boolean valid;

    

    //查看用户的详细信息

    public String detail(){

       

       username = "张三";

       age = 18;

       valid = true;

       

       return "detail";

    }
 

在Action中,给Action的username/age/valid赋值。Detail页面如下:

username:<s:property value="username"/> <br/>

valid:<s:property value="valid"/> <br/>

age:<s:property value="age"/> <br/>
 

上述JSP页面将能正确将它们的值取出。<s:property  value=”ognl表达式”/>。在s:property标签中的OGNL表达式,最终会交给ValueStack来解释。username就 是一个OGNL表达式,意思是调用root对象的getUsername()方法。Struts2将自动搜索CompoundRoot中有哪些元素(从第 0个元素开始搜索),检测这些元素是否有getUsername()方法,如果第0个元素没有getUsername()方法,将继续搜索第1、2、 3……个元素是否有getUsername()方法。

 

在上面的例子中,CompoundRoot中只有一个对象,就是userAction对象,而这个对象中正好有getUsername()方法,所以,上述JSP代码将能够将值正确取出。

再看下面的例子:

public class UserAction {

    private String username;

    private String name;

    

    //查看用户的详细信息

    public String detail(){

       username = "张三";

       name = "王五";

       

       User u = new User();

       u.setUsername("赵毅");

       ActionContext.getContext().getValueStack().push(u);

       

       return "detail";

    }
 

在上面这个UserAction的代码中,我们直接调用 ActionContext.getContext().getValueStack().push()方法,把一个User对象(这个对象拥有 getUsername()和setUsername()方法)直接压入到ValueStack中,这时候,在ValueStack的 CompoundRoot中将有两个元素:第0个元素是刚刚压入的user对象[赵毅],而第1个元素是userAction对象[张三],如果在JSP 中使用下面的表达式来取值:

<s:property value=”username”/> ,那么输出的值将是“赵毅”!道理上面已经讲过了,struts2将会从第0个元素开始搜索CompoundRoot中的对象,第0个元素正是刚刚压入的那个user对象!

如果在JSP中使用<s:property value=”name”/>来取值,将取出“王五”,因为第0个元素user对象没有name属性,所以,会继续搜索第1个元素userAction对象,在这个对象中就有name属性了!

 

三、值栈中的Action对象 

Struts 2总是把Action实例放置在栈顶。因为Action在值栈中,而值栈又是OGNL的根,所有引用Action的属性可以省略 “#”标记,这就是可以在结果页面中直接访问Action的原因

   <s:property value="username"/>

如果访问ActionContext中的其他对象,则必须使用“#”标记,以便让OGNL知道不要在根对象中查找,而是查看其他非根对象