struts2中OGNL表达式

 OGNL表达式基础

  1. OGNL是ObjectGraphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言,只能用于struts框架。相对            EL表达式,它提供了平时我们需要的一些功能,如:
    支持对象方法调用,如xxx.sayHello();
    支持类静态方法调用值访问,表达式的格式为@[类全名(包括包路径)]@[方法名|值名],例如:@java.lang.String@format(‘foo%s’,’bar’)        @cn.hw.Constant@APP_NAME;
    操作集合对象

2.      Ognl有一个上下文(Context)概念,即上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图

context map{

         application

         session

         valuestack(root)

         request

         parameters

         attr(searchespage, request, session, then application scopes)

}

application对象:用于访问ServletContext的Map,例如#application.userName或者#application[‘userName’],相当于调用ServletContext的getAttribute(“username”)。

session对象:用来访问HttpSession的Map,例如#session.userName或者#session[‘userName’],相当于调用session.getAttribute(“userName”)。

request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request[‘userName’],相当于调用request.getAttribute(“userName”)。

parameters对象:用与访问HTTP的请求参数,例如#parameters.userName或者#parameters[‘userName’],相当于调用request.getParameters(“username”)。相当于EL表达式的paramValues内置对象。

attr对象:用于按pageàrequestàsessionàapplication顺序访问其属性。相当于PageContext的findAttribute()方法,也相当于EL表达式${}

3.      ★★struts接受一个请求时,会迅速创建ActionContextValueStackaction。然后action存放进ValueStack,所以action的实例变量可以被OGNL访问访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session。

1.1.1.2       ★★重点:OGNL中的值栈

1.      值栈(valueStack):值栈是依据静态注入生成的(OgnlValueStack)

(a)   值栈的获取ActionContext.getContext().getValueStack()

struts2把ValueStack对象保存在名为struts.valueStack的request域中,

(b)   值栈的生命周期:值栈的生命周期就是一次请求

(c)   struts2在后台将数据放到valueStack中,在前台把数据取出来,所以valueStack在struts2中充当传递数据的一种方式(相比在servlet中:request/session/application.getParameter())

(d)   值栈的内存结构对象栈(是一个list用username取)、 map(是一个map用#username取)

对照上面的图:

ActionContext.getContext().getValueStack().getContext();//包含:【contextOgnlContext

ActionContext.getContext().getValueStack().getRoot();//获取对象栈【rootCompoundRoot

2.      对象栈的说明

(1)   如果将一个对象放到对象栈中,则这个对象的属性就暴露出来了,所以处于对象栈的对象的属性是可以直接访问的,如果在对象栈中有和访问字段名称相同的属性,struts2内部就会从栈顶开始查找,直到找到为止。利用这个特点能很好的解决jsp页面数据回显的问题,所以要进行回显的数据应该放在对象栈中,这样做的效率会比较高

(a)   场景分析1

如果在对象栈中放了两个Person对象(person1和person2),这两个Person对象的属性相同,但是值不一样。当jsp页面需要访问该属性时,struts2会到对象栈从栈顶开始查找,只要找到了(不管值是哪一个的)它就不会再找了

(2)   对象栈获取数据和在对象栈中存入元素的方式有以下几种:

//对象栈其实就是一个List,用add(Object)方法把对象放到【对象栈栈底】
ActionContext.getContext().getValueStack().getRoot().add(useList);
//add(0,Object)方法是将元素放到【对象栈栈顶】
ActionContext.getContext().getValueStack().getRoot().add(0,userLiset);
//push()方法是对add(0,Object)方法进行的简单的封装,所以是放入【对象栈栈顶】
ActionContext.getContext().getValueStack().push(userList);
ActionContext.getContext().getValueStack().getRoot().get(0); ///get(0)取出栈顶元素
//peek()是对get(0)进行简单封装,也是取出【对象栈栈顶】元素
ActionContext.getContext().getValueStack().peek();//获取【对象栈栈顶】元素
ActionContext.getContext().getValueStack().pop();//移除【对象栈栈顶】元素
ActionContext.getContext().getValueStack().getRoot().romove(0);  
//把一个map放入到【对象栈的栈顶】
ActionContext.getContext().getValueStack().set(key,obj);

3P 都是操作栈顶,不指定位置的 add 是放入栈底 。其它方法是集合本身方法

(3)   页面访问方式:用ognl表达式访问对象栈,直接用属性名称就可以了,不用加#

3.      map说明

(1)   map栈中的内容

reuqestsessionapplication都在map栈中

可以把一个对象放入到map中;

当前请求Action在map栈中也存放了一份。

(2)   ognl表达式访问map栈中的内容的方式

如果一个对象放在request#request.对象的key.属性

如果一个对象直接放入到map#对象的key.属性

(说明:把一个对象放入到map栈中,是不能直接访问该对象的属性

(3)   把对象放入map栈中的方式

//把一个对象放到map栈中

ActionContext.getContext.put("departmentList", departmentList);

ServletActionContext.getRequest().setAttribute("departmentList", departmentList);

(4)   ★★▲关于jsp页面的遍历:<iterator>[value属性:迭代对象的key值]

(a)   当前正在迭代的元素的在栈顶:如果没有放任何一个对象在对象栈中,则当前请求的action在栈顶,但用<iterator>标签遍历对象时,当前迭代的元素优先级比当前action更高,居于栈顶,其属性可以直接访问。

(b)   如果value属性不写,则默认迭代栈顶的元素。这一点可以解释,在action层将一个对象放入到对象栈中,当在页面要进行迭代的时候,虽然没有value属性对迭代对象key值的指定,仍可以迭代指定对象属性。

(c)   如果value值为top,则也是迭代栈顶元素

【UserAction.java】

public class UserAction implements ModelDriven<User> {
    public String setValue() {
       List<User>userList = new ArrayList<User>();
       List<List<User>> users = new ArrayList<List<User>>();
       User user = new User();
       user.setId(1L);
       user.setName("hyc");
       User user1 = new User();
       user1.setId(2L);
       user1.setName("xjk");
       userList.add(user);
       userList.add(user1);
       users.add(userList);
       ActionContext.getContext().put("userList", userList);
       Map<String,List<User>> map = new HashMap<String,List<User>>();
       map.put("userList", userList);
       ActionContext.getContext().put("users",users);
       return "index";
    }
}
【index.jsp】

<!-- ★★利用当前正在迭代的元素在对象栈的栈顶,所以id和name前面不要用#-->
<!—userList放在map栈中,迭代:List<User> -->
<s:iterator value="#userList">
    <s:property value="id" />
    <s:property value="name" /><br/>
</s:iterator>
<hr/>
<!-- users放在map栈中,迭代:List<List<User>> -->
<s:iterator value="#users">
    <s:iterator>
       <s:property value="id" />
       <s:property value="name"  /><br/>
    </s:iterator>
</s:iterator >
<hr/>
<!-- users放在map栈中,迭代:Map<String,List<User>> -->
<s:iterator value="#map">
    <s:property value="key"/>
    <s:iterator value="value">
       <s:property value="id"/>
       <s:property value="name" /><br/>
    </s:iterator>
</s:iterator>
<!-- users放在map栈中,迭代:List<Map<String,User> -->
<s:iterator value="#users">
    <s:iterator>
       <s:property value="key" />
       <s:property value="value.name"  /><br/>
    </s:iterator>
</s:iterator >
<hr/>

4.      补充

注意:★★Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value=“name”/>

      相当于jstl核心标签中的:<c:outvalue=”${sessionScope.user}”/>

小技巧:★★在页面中使用<s:debug/>,然后再浏览器中点击debug,出来的就是ActionContext,可以查看上下文中的对象。

5.      对于集合类型,OGNL表达式可以使用innot in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中

6.      解答:为何使用EL表达式能够访问valueStack中对象的属性

原因:是Struts2对HttpServletRequest作了进一步的封装。简略源代码如下:

public class StrutsRequestWrapper extendsHttpServletRequestWrapper{
    public StrutsRequestWrapper(HttpServletRequestreq){
        super(req);
    }
public Object getAttribute(Strings){
         ……
       ActionContext ctx = ActionContext.getContext();
        Objectattribute = super.getAttribute(s);//先从request范围获取属性值
        if(ctx!=null){
            if(attribute==null){
/*★★★如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值*/
                         ……
                ValueStack stack = ctx.getValueStack();
               attribute = stack.findValues(s);
……
            }
        }
        return attribute;
    }
}

1.1.1.3       ★★OGNL创建List/Map集合对象

如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。使用如下代码直接

1.      生成一个List对象

Set标签用于将某个值放入指定范围。

scope:指定变量被放置的范围,该属性可以接受application、session、request、page或action。value:赋给变量的值。如果没有设置该属性,则将ValueStack栈顶的值赋给变量。

<s:set var="list1"value='{"a","b","c"}'></s:set><br/>

<!-- 创建集合,如果不指定范围默认放到了ActionContext上下文件中,scope="action"-->

<s:set var="list2"value="{'aa','bb','cc'}"scope="session"/><!--指定范围-->

<s:iterator value="#session.list2"var="l">

    <s:property value="#l"/><br/>

</s:iterator>

2.      生成一个Map对象

<s:set var="map1" value="#{'a':'valuea','b':'valueb'}" scope="session"/>
<!-- 打印valueb:用#map1.b取不到 -->
<s:iterator value="#session.map1" var="me">
    <s:property value="#me.key"/>=<s:property value="#me.value"/><br/>
</s:iterator>
<!-- 作用如同forEach  -->
<c:forEach items="${sessionScope.map1}" var="me">
   ${me.key }=${me.value }<br/>
</c:forEach>

1.1.1.4       OGNL表达式的投影功能(不是很重要)
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1.      除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。</span>

?:获得所有符合逻辑的元素

^:获得符合逻辑的第一个元素

$:获得符合逻辑的最后一个元素

2.      例如代码:

       <s:iteratorvalue=“books.{?#this.price>35}”>

              <s:propertyvalue=“title”/>-$<s:property value=“price”/><br/>

       </s:iterator>

在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合需要对大集合books进行迭代,this代表当前迭代的元素。本例的表达式用于获取集合中价格大于35的书集合。

public classBookAction extends ActionSupport{

       private List<Book> books;

       public String execute(){

              books = newArrayList<Book>();

              books.add(new Book(“a”,”spring”,67));

              books.add(new Book(“b”,”ejb”,15));

       }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值