//还会补充
首先要有一个意识 ,为什么要了解这个?:
struts2中的表单是怎么通过表达式(EL or OGNL)来传给Action 和 拿到Action的值的。
值栈(根)对象也可以直接使用EL表达式访问,比如这里可以直接通过${user.username}来获取username的值,我们知道el表达式只能访问四种scope范围内的对象,那为什么这里能访问到值栈对象呢?原因是struts2对HttpServletRequet进行了一次封装,封装的代码主要是重写了getAttribute方法,简述重写此方法的核心代码:首先在原始的HttpServletRequest对象中查找el表达式中的属性,如果找不到再通过ActionContext获取值栈对象,进而再从值栈对象中查找el表达式中要访问的属性。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
当Struts2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是
①先将Action类的相应属性放到ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。只是所有的属性值都是默认的值,如String类型的属性值为null,int类型的属性值为0等。处理完上述工作后,
②Struts2就会调用拦截器链中的拦截器,当调用完所有的拦截器后,最后会调用Action类的Action方法,在调用Action方法之前,会将
③ValueStack对象顶层节点中的属性值赋给Action类中相应的属性,注意,在这里就给我们呆了很大的灵活性。也就是说,在Struts2调用拦截器的过程中,可以改变ValueStack对象中属性的值,当改变某个属性之后,Action类的相应属性值就会变成在拦截器中最后改变该属性的这个值。(通过setValue方法可以改变)
1、值栈(ValueStack)
Struts2将OGNL上下文设置为Struts2中的ActionContext(内部使用的仍然是OgnlContext),并将值栈设为OGNL的根对象。valuestack是ONGL的跟对象
我们知道,OGNL上下文中的根对象(valuestack)可以直接访问,不需要使用任何特殊的“标记”,而引用上下文中的其他对象则需要使用“#”来标记。由于值栈是 上下文中的根对象,因此可以直接访问。那么对于值栈中的对象该如何访问呢?Struts2提供了一个特殊的OGNLPropertyAccessor,它 可以自动查找栈内的所有对象(从栈顶到栈底),直接找到一个具有你所查找的属性的对象。也就是说,对于值栈中的任何对象都可以直接访问,而不需要使用 “#”。
假设值栈中有两个对象:student和employee,两个对象都有name属性,student有学号属性number,而 employee有薪水属性salary。employee先入栈,student后入栈,位于栈顶,那么对于表达式name,访问的就是student 的name属性,因为student对象位于栈顶;表达式salary,访问的就是employee的salary属性。正如你所见,访问值栈中的对象属 性或方法,无须指明对象,也不用“#”,就好像值栈中的对象都是OGNL上下文中的根对象一样。这就是Struts2在OGNL基础上做出的改进。
2、[N]语法
如上所述,如果想要访问employee的name属性,应该如何写表达式呢?我们可以使用[N].xxx(N是从0开始的整数)这样的语法来指定从哪一个位置开始向下查找对象的属性,表达式[1].name访问的就是employee对象的name属性。
在使用[N].xxx语法时,要注意位置序号的含义,它并不是表示“获取栈中索引为N的对象”,而是截取从位置N开始的部分栈。
因为根栈结构是一个ArrayList,根据栈的数据结构,访问一个值是不断pop掉栈顶的值来做到访问该list的对象
4、访问静态成员
除了使用标准的OGNL表达式访问静态字段和静态方法(struts2从某版本开始需要在常量中注册struts.ognl.allowStaticMethodAccess 为true 才能调用静态方法)外,Struts2还允许你不指定完整的类名,而是通过“vs”前缀来调用保存在栈中的静态字段和静态方法。
@vs@FOO_PROPERTY
@vs@someMethod()
@vs1@someMethod()
<s: property value="@java.util.UUID@randomUUID()" />
vs表示ValueStack,如果只有vs,那么将使用栈顶对象的类;如果在vs后面跟上一个数字,那么将使用栈中指定位置处的对象类。
5、值栈中的Action实例
Struts2框架总是把Action实例放在栈顶。因为Action在值栈中,而值栈又是OGNL中的根,所以引用Action的属性可以省略“#”标记,这也是为什么我们在结果页面中可以直接访问Action的属性的原因。
个人总结:
1.首先拿到vs对象有三种方式在这里不说了, 查笔记
2.在actionContext(大Map)中有指向vs的key;而在vs中也有大map的Map<String,Object> getContext()应用 和 一个list;
3.综上所以vs 和 actionContext 构成了OGNL 访问数据的上下文!(一个大map结构!)<s:debug/>访问
4.针对用户每次访问动作类,struts的核心filter都会创建属于自己的vs对象。
////////////////////////////////////
关于ValueStack一些函数用法
void set(String key,Object value):先获取根栈栈顶的Map,如果不存在,压入一个新的Map,把key和value放到这个Map中。如果存在,直接放key和value。
void setValue(String ognlExp ,Object):String是一个OGNL表达式。如果表达式以#开头,操作contextMap。如果不是,设置根栈中对象的某个属性,从顶到尾依次搜寻
Object findValue(String expr):参数是一个OGNL表达式。如果以#开头,从contextMap中找key值所对应的对象。如果不是以#开头,搜索根栈中对象的属性(getter方法)
特别注意:如果编写的表达式不是以#开头,先搜索根栈对象的所有属性,如果没有找到,会把它当做key值到contextMap中找。
String findString(String expr):和findValue功能一样,但把OGNL表达式获取的对象转换成String