首页 > 代码库 > 关于Struts2中的值栈与OGNL表达式

关于Struts2中的值栈与OGNL表达式

1.1.1    OGNL概述:

Object Graphic Navigation Language(对象图导航语言)的缩写

* EL     :OGNL比EL功能强大很多倍.

它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

OGNL相对其它表达式语言具有下面几大优势:

   1、支持对象方法调用,如xxx.doSomeSpecial();

   2、支持类静态的方法调用和值访问,表达式的格式:

      @[类全名(包括包路径)]@[方法名 |  值名],例如:

             @java.lang.String@format(‘foo %s‘, ‘bar‘)

             或@tutorial.MyConstant@APP_NAME;

      设置 struts.ognl.allowStaticMethodAccess=true

   3、访问OGNL上下文(OGNL context)和ActionContext;

   4、支持赋值操作和表达式串联,如price=100, discount=0.8,

        calculatePrice(),这个表达式会返回80;

   5、操作集合对象。

1.1.2    访问类的方法:

<s:property value="http://www.mamicode.com/‘helloworld‘.length()"/><br/>

1.1.3    访问类的静态方法:

开启一个常量:

<constant name="struts.ognl.allowStaticMethodAccess" value="http://www.mamicode.com/true"/>

语法:

@类的全路径@方法名

<s:property value="http://www.mamicode.com/@java.lang.Math@random()"/><br/>

<s:property value="http://www.mamicode.com/@java.lang.Math@max(12,15)"/><br/>

<s:property value="http://www.mamicode.com/@java.lang.String@format(‘%s,你好‘,‘小明‘)"/><br/>

1.1.4    访问OGNL的上下文:(值栈ValueStack )

什么是值栈?

ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个  ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前   Action 对象和其他相关对象.

Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中

 

结论:

Action何时创建:每次访问的时候创建.Action多实例的.没次访问都会创建一个Action.每个Action中有一个ValueStack对象的引用.

值栈对象ValueStack在request域中有一份.名字struts.valueStack

值栈:Action--->JSP传递值的.

OGNL:获得值栈的数据.

 

值栈的内部结构?

在 ValueStack 对象的内部有两个逻辑部分:

ObjectStack: Struts  把动作和相关对象压入 ObjectStack 中--List

ContextMap: Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中

Struts 会把下面这些映射压入 ContextMap 中

parameters: 该 Map 中包含当前请求的请求参数

request: 该 Map 中包含当前 request 对象中的所有属性

session: 该 Map 中包含当前 session 对象中的所有属性

application:该 Map 中包含当前 application  对象中的所有属性

attr: 该 Map 按如下顺序来检索某个属性: request, session, application

 

值栈ValueStack 和 ActionContext关系? --- 值栈的创建

StrutsPrepareAndExecuteFilter:核心过滤器:(预处理和执行)

核心过滤器 init  和 doFilter 两个方法.服务器启动的时候init就执行了 .每次访问doFilter执行.

Action每次访问的时候会创建.每次请求doFilter都会执行.(Action的创建的代码在doFilter)中.

在doFilter的代码中:

* prepare.createActionContext(request, response);--- 创建了ActionContext对象.

* ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack(); --- 创建了一个ValueStack对象

* ctx = new ActionContext(stack.getContext()); --- 将值栈对象的引用保存到ActionContext中.

***** 所以可以从ActionContext对象中获得到值栈对象.

 

* 将ValueStack存request域中:

request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

 

如何获得值栈对象?

两种方式:

// 1.ActionContext对象中有值栈的引用.

    ValueStack valueStack1 = ActionContext.getContext().getValueStack();

   

// 2.从request域中获得值栈对象.

    ValueStack valueStack2 = (ValueStack) ServletActionContext.getRequest()

            .getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

   

向值栈保存数据?

push(Object obj);    --- 将对象压入到栈顶.

set(String key,Object); --- 创建一个Map集合,将Map集合压入到(root)栈中

 

***** Action对象默认是在栈中的!!!那么在Action中定义的属性呢?

* 对属性提供了相应get方法.获得到属性? -- Action的属性也在栈中.

在页面通过struts2标签 获取值栈内容?

获得root区域值:不需要加#

<s:property value=http://www.mamicode.com/”name”/>

获得context区域的值:需要加#

<s:property value=http://www.mamicode.com/”#request.username”/>

通过EL表达式可以访问值栈数据?

底层的代码:StrutsRequestWrapper

public class StrutsRequestWrapper extends HttpServletRequestWrapper {

       public StrutsRequestWrapper(HttpServletRequest req) {

           super(req);

       }

       public Object getAttribute(String s) {

        ......

        ActionContext ctx = ActionContext.getContext();

        Object attribute = super.getAttribute(s);//先从request范围获取属性值

        if (ctx != null) {

            if (attribute == null) {

//如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值

               ......

               ValueStack stack = ctx.getValueStack();

               attribute = stack.findValue(s);

               ......

            }

        }

        return attribute;

    }

 }

1.1.5    OGNL:获得值栈的数据.

#号的用法:

1.获的值栈context中的值

<s:property value="http://www.mamicode.com/#request.name"/>

<s:property value="http://www.mamicode.com/#session.name"/>

<s:property value="http://www.mamicode.com/#application.name"/>

<s:property value="http://www.mamicode.com/#attr.name"/>

<s:property value="http://www.mamicode.com/#parameters.name"/>

 

2.投影集合:(对集合中的数据进行过滤)

<h3>遍历整个list集合</h3>

<s:iterator  var="p" value="http://www.mamicode.com/list">

<s:property value="http://www.mamicode.com/name"/>---<s:property value="http://www.mamicode.com/price"/><br/>

<s:property value="http://www.mamicode.com/#p.name"/>---<s:property value="http://www.mamicode.com/#p.price"/><br/>

</s:iterator>

 

<h3>过滤要集合的所有的name属性</h3>

<s:iterator value="http://www.mamicode.com/list.{name}" var="pname">

<s:property value="http://www.mamicode.com/pname"/>

</s:iterator>

 

<h3>遍历集合中价格大于1500的商品</h3>

<s:iterator value="http://www.mamicode.com/list.{?#this.price > 1500}">

<s:property value="http://www.mamicode.com/name"/>---<s:property value="http://www.mamicode.com/price"/>

</s:iterator>

 

<h3>遍历集合中价格大于1500的商品名称</h3>

<s:iterator value="http://www.mamicode.com/list.{?#this.price>2000}.{name}" var="pname">

<s:property value="http://www.mamicode.com/pname"/>

</s:iterator>

 

3.构建一个map集合.

<h3>构建一个List集合</h3>

<!-- 构建一个list集合 -->

<s:iterator value="http://www.mamicode.com/{‘aa‘,‘bb‘,‘cc‘,‘dd‘}" var="i" >

<s:property value="http://www.mamicode.com/i"/>

</s:iterator>

<h3>构建Map集合</h3>

<s:iterator value="http://www.mamicode.com/#{ ‘aa‘:‘name1‘,‘bb‘:‘name2‘,‘cc‘:‘name3‘ }">

<s:property value="http://www.mamicode.com/key"/>---<s:property http://www.mamicode.com/value="value"/>

</s:iterator>

%号用法:

1.告诉运行环境是一个OGNL表达式:

<% request.setAttribute("name", "张三"); %>

<s:textfield name="name" value="http://www.mamicode.com/%{#request.name}" label="用户名"/>

 

2.告诉运行环境不是一个OGNL表达式:

<% request.setAttribute("foo", "foo"); %>

<s:property value="http://www.mamicode.com/%{‘#request.foo‘}"/>

$号用法:

1.在国际化文件中使用OGNL表达式

itcast.test=${\#request.name}

页面中:

<s:i18n name="message">

<s:text name="itcast.test"></s:text>

</s:i18n>

2.在配置文件XML中使用OGNL表达式

<param name="contentType">${contentType}</param>

 

关于Struts2中的值栈与OGNL表达式