4. ValueStack 和 OGNL
1. 属性哪来的
- 当我们通过Action处理完用户请求以后,可以直接在页面中获取到 action 的属性值。
- 如果我们在页面中尝试遍历四个域中的属性,会发现域中并没有username之类的Action中的属性。
- 但是我们自己又没有在域中进行设置,经过研究发现request域中出现了一个奇怪属性 属性的名字:struts.valueStack
- 属性的类型:OgnlValueStack
ValueStack
翻译过叫做值栈,顾名思义就是存储值的栈 Struts
在每次处理请求都会创建一个新的ValueStack
用来存储这个请求过程中所要用到的属性及对象。 像我们熟悉ActionContext
就是值栈的一部分。 2. ValueStack(值栈)
- 所谓值栈就是一个 OgnlValueStack 类型的对象,他以struts.valueStack为键保存在request域中。Struts2 会将 Action 的实例保存值栈中。
- 值栈实际是由两部分组成 Object Stack (CompoundRoot ) 和 Map Context (Map<String, Object>) context是一个Map,里边保存着三个域、请求参数等对应的Map对象。
- root 实际就是一个List,Action对象就保存在这个List中。
- Struts 会把下面这些映射压入 ContextMap 中 parameters: 该 Map 中包含当前请求的请求参数
- request: 该 Map 中包含当前 request 对象中的所有属性
- session: 该 Map 中包含当前 session 对象中的所有属性
- application:该 Map 中包含当前 application 对象中的所有属性
- attr: 该 Map 按如下顺序来检索某个属性: request, session, application
/** * A Stack that is implemented using a List. * * @author plightbo * @version $Revision$ */ public class CompoundRoot extends CopyOnWriteArrayList<Object> { private static final long serialVersionUID = 8563229069192473995L; 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); } }
- 值栈的结构
- 首先,从request域中查找属性,如果有直接返回。
- 然后,如果域中没有找到指定属性,则去值栈中查找(这里的值栈主要指CompoundRoot),
- 因为值栈中可能有多个对象,所以会先从索引值为0的对象开始找,直到找到了需要的属性,如果找到直接返回。
- 最后,如果值栈中依然没有找到指定属性接下来去context中查找,如果找到直接返回,如果也没找到则直接返回null。
3. OGNL (Object-Graph Navigation Language)
- Object-Graph Navigation Language
- 这是一种从Java对象中获取或设置属性的表达式语言。
- Struts2内部使用OGNL表达式从而大大增强了Struts2的数据访问功能。
- Struts2 利用 s:property 标签和 OGNL 表达式来读取值栈中的属性值
- 值栈中的属性值: 对于对象栈: 对象栈中某一个对象的属性值Map 栈: request, session, application 的一个属性值 或 一个请求参数的值.
- 读取对象栈中对象的属性: 若想访问 Object Stack 里的某个对象的属性. 可以使用以下几种形式之一: object.propertyName ;object['propertyName'] ;object["propertyName"]
- ObjectStack 里的对象可以通过一个从零开始的下标来引用. ObjectStack 里的栈顶对象可以用 [0] 来引用,
- 它下面的那个对象可以用 [1] 引用. [0].message[n] 的含义是从第 n 个开始搜索, 而不是只搜索第 n 个对象
- 若从栈顶对象开始搜索, 则可以省略下标部分: message
- 结合 s:property 标签: <s:property value="[0].message" /> <s:property value="message" />
- 默认情况下, Action 对象会被 Struts2 自动的放到值栈的栈顶.
- 我们可以试着改变值栈的栈顶对象
//改变对象栈,栈顶的对象 ActionContext context = ActionContext.getContext(); ValueStack valueStack = context.getValueStack(); valueStack.push(User.builder().username("猪八戒").address("高老庄").build());
- 获取对象栈中的数据:
<!-- 可以直接获取栈顶对象的属性,如果栈顶对象没有就会继续往下找,再没有就从Map栈中找 --> 用户名 : <s:property value="user.username"></s:property> <br /> <br /> 年龄 : <s:property value="age"></s:property> <br /> <br /> 地址 : <s:property value="address"></s:property> <br /> <br /> <hr> <!-- 对于被我们改变的栈顶对象,我们可以用下标的方式 --> 用户名 : <s:property value="[1].username"></s:property> <br /> <br /> 地址 : <s:property value="[1].address"></s:property> <br /> <br /> <hr> <!-- 另外两种方式 object['filedName'] 或者 object["filedName"] --> 用户名 : <s:property value="[1]['username']"></s:property> <br /> <br /> 地址 : <s:property value="[1]['address']"></s:property> <br /> <br />
- 读取 Context Map 里的对象的属性 如果希望从map栈中查找属性,只需要在表达式的开头加个#例如:我们要从session域中查找一个属性 #session.hello
<% session.setAttribute("hello", "你好"); application.setAttribute("key", "appKey"); session.setAttribute("key", "sessKey"); request.setAttribute("key", "reqKey"); %> <hr><br><br> <!-- Map栈中Session数据 --> 获取到Session域中属性: <s:property value="#session.hello"></s:property><br><br> 获取请求参数: <s:property value="#parameters.username"></s:property><br><br> <!-- attr 会从小到大的范围去查找 --> 通过attr获取属性值:<s:property value="#attr.key"/>
- OGNL 调用字段和方法 可以利用 OGNL 调用 任何一个 Java 类里的静态字段或方法.
- 被压入到 ValueStack 栈的对象上的公共字段和方法.
<!-- 开启静态方法访问 --> <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
- 调用静态字段或方法需要使用如下所示的语法: **@fullyQualifiedClassName@fieldName: @java.util.Calendar@DECEMBER**
- **@fullyQualifiedClassName@methodName(argumentList): @app4.Util@now()**
<!-- 调用静态方法和字段 --> 调用静态字段: <s:property value="@java.util.Calendar@WEEK_OF_YEAR"></s:property><br> <!-- 对于调用静态方法,我们需要去 struts.xml 文件中配置--> 调用静态方法: <s:property value="@org.pan.struts2.entity.User@sayHello('张三丰')"></s:property>
- 调用 ValueStack 栈的对象的 非静态方法和字段(公共字段和方法.)
<!-- 调用栈顶对象的 公共方法和属性(属性就是我们之前访问的字段值) --> 调用公共方法: <s:property value="sayYou('巨无霸')"></s:property>
- OGNL 获取 数组、List、Map 信息
- OGNL 访问数组类型的属性 有些属性将返回一个对象数组而不是单个对象, 可以像读取任何其他对象属性那样读取它们. 这种数组型属性的各个元素以逗号分隔, 并且不带方括号可以使用下标访问数组中指定的元素: colors[0]可以通过调用其 length 字段查出给定数组中有多少个元素: colors.length
<!-- OGNL 访问数组类型的属性 --> <% String[] names = new String[]{"aa","bb","cc","dd"}; request.setAttribute("names", names); %> length:<s:property value="#attr.names.length"/> <br/> names[1]:<s:property value="#attr.names[1]"/>
- OGNL 访问 List 类型属性 有些属性将返回的类型是 java.util.List, 可以像读取任何其他属性那样读取它们. 这种 List 的各个元素是字符串, 以逗号分隔, 并且带方括号可以使用下标访问 List 中指定的元素: colors[0]可以通过调用其 size 方法或专用关键字 size 的方法查出给定List 的长度: colors.size 或 colors.size()可以通过使用 isEmpty() 方法或专用关键字 isEmpty 来得知给定的 List 是不是空. colors.isEmpty 或 colors.isEmpty()还可以使用 OGNL 表达式来创建 List, 创建一个 List 与声明一个 Java 数组是相同的: {“Red”, “Black”, “Green”}
<% List<String> colors = new ArrayList<String>(); colors.add("Red"); colors.add("Black"); colors.add("Green"); request.setAttribute("colors", colors); %> isEmpty: <s:property value="#request.colors.isEmpty()"></s:property><br><br> size: <s:property value="#request.colors.size"></s:property><br><br> colors: <s:property value="#request.colors[1]"></s:property>
- OGNL 访问Map 类型属性 读取一个 Map 类型的属性将以如下所示的格式返回它所有的键值对:若希望检索出某个 Map 的值, 需要使用如下格式: map['key']可以使用 size 或 size() 得出某个给定的 Map 的键值对的个数可以使用 isEmpty 或 isEmpty() 检查某给定 Map 是不是空.可以使用 #{key1:value1, key2:value2, key3:value3}的方式创建一个Map
<!-- OGNL 访问Map类型属性 --> <% Map<String,String> letters = new HashMap<String,String>(); letters.put("AA", "aa"); letters.put("BB", "bb"); letters.put("CC", "cc"); request.setAttribute("letters", letters); %> isEmpty: <s:property value="#request.letters.isEmpty"></s:property><br><br> size:<s:property value="#attr.letters.size()"/><br><br/> AA:<s:property value="#attr.letters['AA']"/><br><br> 创建Map: <s:set var="testMap" value="#{'AA':'aa', 'BB':'bb', 'CC':'cc'}"></s:set><br><br> 读取创建的Map: <s:property value="#attr.testMap.AA"></s:property>
相关推荐
cuterabbitbaby 2020-05-12
zhangbeizhen 2019-06-28
匆匆忙忙 2012-02-28
81314797 2010-11-26
88251546 2010-09-20
Nishinoshou 2019-06-25
GATSBYER 2010-06-02
gsl 2013-04-26
being 2010-03-15
liulang 2016-06-07
wujimiao 2019-04-23
唧唧歪歪 2013-11-27
人丑就该多读书 2018-02-22
不鳥萬如一的各種垃圾彙總 2017-12-02