struts2 ognl表达式详解

OGNL中的#%$符号

#%$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分。在这里我们简单介绍它们的相应用途。

1#符号的三种用法

1访问非根对象属性,例如示例中的#session.msg表达式,由于Struts2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext.getContext()#session.msg表达式相当于ActionContext.getContext().getSession().getAttribute("msg")

2用于过滤和投影(projecting)集合,如示例中的persons.{?#this.age>20},persons.{?#this.name=='pla1'}.{age}[0]

3用来构造Map,例如示例中的#{'foo1':'bar1','foo2':'bar2'}

2%符号

%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。如下面的代码所示:

<h3>构造Map</h3>

<s:setname="foobar"value="#{'foo1':'bar1','foo2':'bar2'}"/>

<p>Thevalueofkey"foo1"is<s:propertyvalue="#foobar['foo1']"/></p>

<p>不使用%:<s:urlvalue="#foobar['foo1']"/></p>

<p>使用%:<s:urlvalue="%{#foobar['foo1']}"/></p>

运行界面如下所示。

hevalueofkey"foo1"isbar1

不使用%#foobar['foo1']

使用%bar1

3$符号

$符号主要有两个方面的用途。

1在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}${max}之间。

2Struts2框架的配置文件中引用OGNL表达式,例如下面的代码片断所示:

</pre><pre name="code" class="html"><validators>  
  
    <field name="intb">  
  
            <field-validator type="int">  
  
            <param name="min">10</param>  
  
            <param name="max">100</param>  
  
            <message>BAction-test校验:数字必须为${min}为${max}之间!</message>  
  
        </field-validator>  
  
    </field>  
  
</validators>  



总结OGNL的使用方法:

访问属性

名字属性获取:<s:property value="user.username"/><br>

地址属性获取:<s:property value="user.address.addr"/><br>


访问方法

调用值栈中对象的普通方法:<s:property value="user.get()"/><br>


访问静态属性和方法

调用Action中的静态方法:<s:property value="@struts.action.LoginAction@get()"/>

调用JDK中的类的静态方法:<s:property value="@java.lang.Math@floor(44.56)"/><br>

调用JDK中的类的静态方法(同上):<s:property value="@@floor(44.56)"/><br>

调用JDK中的类的静态方法:<s:property value="@java.util.Calendar@getInstance()"/><br>

调用普通类中的静态属性:<s:property value="@struts.vo.Address@TIPS"/><br>


访问构造方法

调用普通类的构造方法:<s:property value="new struts.vo.Student('李晓红' , '美女' , 3 , 25).username"/>


访问数组

获取List:<s:property value="testList"/><br>

获取List中的某一个元素(可以使用类似于数组中的下标获取List中的内容):

<s:property value="testList[0]"/><br>

获取Set:<s:property value="testSet"/><br>

获取Set中的某一个元素(Set由于没有顺序,所以不能使用下标获取数据):

<s:property value="testSet[0]"/><br> ×

获取Map:<s:property value="testMap"/><br>

获取Map中所有的键:<s:property value="testMap.keys"/><br>

获取Map中所有的值:<s:property value="testMap.values"/><br>

获取Map中的某一个元素(可以使用类似于数组中的下标获取List中的内容):

<s:property value="testMap['m1']"/><br>

获取List的大小:<s:property value="testSet.size"/><br>


访问集合 – 投影、选择(? ^ $)

利用选择获取List中成绩及格的对象:<s:property value="stus.{?#this.grade>=60}"/><br>

利用选择获取List中成绩及格的对象的username:

<s:property value="stus.{?#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的第一个对象的username:

<s:property value="stus.{?#this.grade>=60}.{username}[0]"/><br>

利用选择获取List中成绩及格的第一个对象的username:

<s:property value="stus.{^#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的最后一个对象的username:

<s:property value="stus.{$#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的第一个对象然后求大小:

<s:property value="stus.{^#this.grade>=600}.{username}.size"/><br>


集合的伪属性

OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBeans模式,例如size(),length()等等. 当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性.

集合

伪属性

Collection(inherited by Map, List & Set)

size ,isEmpty

List

iterator

Map

keys , values

Set

iterator

Iterator

next , hasNext

Enumeration

next , hasNext , nextElement , hasMoreElements



Lambda :[…]

格式::[…]

使用Lambda表达式计算阶乘:

<s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/><br>


OGNL中#的使用

#可以取出堆栈上下文中的存放的对象.

名称

作用

例子

parameters

包含当前HTTP请求参数的Map

#parameters.id[0]作用相当于

request.getParameter("id")

request

包含当前HttpServletRequest的属性(attribute)的Map

#request.userName相当于

request.getAttribute("userName")

session

包含当前HttpSession的属性(attribute)的Map

#session.userName相当于

session.getAttribute("userName")

application

包含当前应用的ServletContext的属性(attribute)的Map

#application.userName相当于

application.getAttribute("userName")

attr

用于按request > session > application顺序访问其属性(attribute)




















获取Paraments对象的属性:<s:property value="#parameters.username"/>


OGNL中%的使用

用%{}可以取出存在值堆栈中的Action对象,直接调用它的方法.
例如你的Action如果继承了ActionSupport .那么在页面标签中,用%{getText('key')}的方式可以拿出国际化信息.

OGNL中$的使用

“$”有两个主要的用途
l 用于在国际化资源文件中,引用OGNL表达式
l 在Struts 2配置文件中,引用OGNL表达式


值栈

ValueStack对象。这个对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当 Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到 ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。
在Action中获得ValueStack对象:ActionContext.getContext().getValueStack()
l Top语法
使用Top获取值栈中的第二个对象:<s:property value="[1].top.对象"/>
l N语法
使用N获取值栈中的第二个对象:<s:property value="[1].对象"/>
l @语法
调用action中的静态方法:<s:property value="@vs1@静态方法"/> vs:值栈 1:表示第一个。


DEMO:

web.xml

<?xml version="1.0" encoding="UTF-8"?>  
<web-app version="2.5"   
    xmlns="http://java.sun.com/xml/ns/javaee"   
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee   
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">  
    <filter>  
        <filter-name>struts2</filter-name>  
        <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>  
    </filter>  
    <filter-mapping>  
        <filter-name>struts2</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping>  
    <welcome-file-list>  
        <welcome-file>login.jsp</welcome-file>  
    </welcome-file-list>    
</web-app>  


login.jsp(用于输入用户名和密码等信息的测试页面)

<%@ page language="java" pageEncoding="UTF-8"%>  
<h1>这是测试OGNL使用的登录页面</h1>  
<h3><font color="red">提示:</font>程序设定的用户名和密码各为<font color="blue"><strong>admin</strong></font>和<font color="blue"><strong>jadyer</strong></font></h3>  
<h3><font color="red">注意:</font>用户名和密码不正确时将停留在页面不动</h3>  
<form action="<%=request.getContextPath()%>/login.action" method="POST">  
    <%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>  
    <%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>  
    姓名:<input type="text" name="user.username"><br>  
    密码:<input type="text" name="user.password"><br>  
    地址:<input type="text" name="user.address.addr"><br>  
    <input type="submit" value="测试OGNL的输出">  
</form>  


loginSuc.jsp(用于显示OGNL处理结果)

<%@ page language="java"pageEncoding="UTF-8"%> 
<%@ taglib prefix="s"uri="/struts-tags"%> 
<h1>这是使用OGNL输出的结果页面</h1> 
<table border="9"> 
    <tr> 
        <tdalign="right">获取姓名属性:</td> 
        <tdalign="left"><s:propertyvalue="user.username"/></td> 
        <%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%> 
        <%-- <s:propertyvalue="user['username']"/> --%> 
        <%-- <s:propertyvalue="user[/"username/"]"/> --%> 
        <%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%> 
        <%-- <s:propertyvalue="user[username]"/> --%> 
    </tr> 
    <tr> 
        <tdalign="right">获取地址属性:</td> 
        <tdalign="left"><s:propertyvalue="user.address.addr"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用值栈中的对象的普通方法:</td> 
        <tdalign="left"><s:propertyvalue="user.getVOMethod()"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用值栈中Action的普通方法:</td> 
        <tdalign="left"><s:propertyvalue="getCommon()"/></td> 
    </tr> 
</table> 
<hr/> 
<table border="9"> 
    <tr> 
        <tdalign="right">获取普通类的静态属性:</td> 
        <tdalign="left"><s:propertyvalue="@com.jadyer.vo.Address@TIPS"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">访问普通类的构造方法:</td> 
        <tdalign="left"><s:propertyvalue="new com.jadyer.vo.Student('张小三',22).username"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用Action中的静态方法:</td> 
        <tdalign="left"><s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用JDK中的类的静态方法:</td> 
        <tdalign="left"><s:propertyvalue="@java.util.Calendar@getInstance().time"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用JDK中的类的静态方法:</td> 
        <tdalign="left"><s:propertyvalue="@java.lang.Math@floor(46.58)"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">调用JDK中的类的静态方法:</td> 
        <tdalign="left"><s:propertyvalue="@@floor(46.58)"/></td> 
    </tr> 
</table> 
<hr/> 
<tableborder="9"> 
    <tr> 
        <tdalign="right">获取List中的所有元素:</td> 
        <tdalign="left"><s:propertyvalue="testList"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Set中的所有元素:</td> 
        <tdalign="left"><s:propertyvalue="testSet"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Map中的所有元素:</td> 
        <tdalign="left"><s:propertyvalue="testMap"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Map中的某个元素:</td> 
        <tdalign="left"><s:propertyvalue="testMap['m22']"/></td> 
        <%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%> 
        <%-- <s:propertyvalue="testMap.m22"/> --%> 
        <%-- <s:propertyvalue="testMap[/"m22/"]"/> --%> 
    </tr> 
    <tr> 
        <tdalign="right">获取Set中的某个元素:</td> 
        <%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%> 
        <tdalign="left"><s:propertyvalue="testSet[2]"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取List中的某个元素:</td> 
        <tdalign="left"><s:propertyvalue="testList[2]"/></td> 
    </tr> 
</table> 
<hr/> 
<table border="9"> 
    <tr> 
        <tdalign="right">获取List的大小:</td> 
        <tdalign="left"><s:propertyvalue="testList.size"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Set的大小:</td> 
        <tdalign="left"><s:propertyvalue="testSet.size"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Map的大小:</td> 
        <tdalign="left"><s:propertyvalue="testMap.size"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Map中所有的键:</td> 
        <tdalign="left"><s:propertyvalue="testMap.keys"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">获取Map中所有的值:</td> 
        <tdalign="left"><s:propertyvalue="testMap.values"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">Lambda计算4的阶乘:</td> 
        <tdalign="left"><s:propertyvalue="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)"/></td> 
    </tr> 
</table> 
<hr/> 
<tableborder="9"> 
    <tr> 
        <tdalign="right">获取List中的所有对象:</td> 
        <tdalign="left"><s:propertyvalue="stus"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用投影获取List中对象的名字:</td> 
        <tdalign="left"><s:propertyvalue="stus.{username}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用投影获取List中第二个对象的名字:</td> 
        <%-- 使用<s:propertyvalue="stus[1].{username}"/>获取到的值为:[李四] --%> 
        <%-- 二者的区别在于:后者比前者多了一个中括号 --%> 
        <tdalign="left"> 
            <s:propertyvalue="stus.{username}[1]"/>       
            <s:propertyvalue="stus[1].{username}"/> 
        </td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的所有对象:</td> 
        <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的第一个对象:</td> 
        <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的最后一个对象:</td> 
        <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}"/></td> 
    </tr> 
</table> 
<hr/> 
<tableborder="9"> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的所有对象的名字:</td> 
        <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的第二个对象的名字:</td> 
        <tdalign="left"><s:propertyvalue="stus.{?#this.grade>=60}.{username}[1]"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的第一个对象的名字:</td> 
        <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的最后一个对象的名字:</td> 
        <tdalign="left"><s:propertyvalue="stus.{$#this.grade>=60}.{username}"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td> 
        <tdalign="left"><s:propertyvalue="stus.{^#this.grade>=60}.{username}.size"/></td> 
    </tr> 
</table> 
<hr/> 
<table border="9"> 
    <tr> 
        <tdalign="right">利用OGNL中的#号获取attr中的属性:</td> 
        <tdalign="left"><s:propertyvalue="#attr.BB"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用OGNL中的#号获取request范围中的属性:</td> 
        <tdalign="left"><s:propertyvalue="#request.req"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用OGNL中的#号获取session范围中的属性:</td> 
        <tdalign="left"><s:propertyvalue="#session.ses"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">利用OGNL中的#号获取Paraments对象的属性:</td> 
        <tdalign="left"><s:propertyvalue="#parameters.netname"/></td> 
    </tr> 
    <tr> 
        <tdalign="right">使用<%=request.getParameter("")%>或者${param.name}获取链接参数值:</td> 
        <tdalign="left"> 
            ${param.netname}       
            <%=request.getParameter("netname")%> 
        </td> 
    </tr> 
    <tr> 
        <tdalign="right">查看值栈中的信息:</td> 
        <tdalign="left"><s:debug/></td> 
    </tr> 
</table> 

struts.xml

<?xmlversion="1.0"encoding="UTF-8"?> 
<!DOCTYPE struts PUBLIC 
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" 
    "http://struts.apache.org/dtds/struts-2.0.dtd"> 
<struts> 
    <packagename="ognl"extends="struts-default"> 
        <actionname="login"class="com.jadyer.action.LoginAction"> 
            <resultname="input">/login.jsp</result> 
            <resultname="success">/loginSuc.jsp?netname=hongyu</result> 
            <!-- 
            <resultname="success"type="redirect">/loginSuc.jsp?netname=hongyu</result> 
            <resultname="success"type="redirect">/loginSuc.jsp?netname=${user.username}</result>  
             --> 
        </action> 
    </package> 
</struts> 


用到的三个VO类

package com.jadyer.vo; 
publicclass User { 
    private String username; 
    private String password; 
    private Address address; 
    /* 三个属性的setter和getter略 */ 
    public String getVOMethod(){ 
        return"这是User类中的一个普通方法"; 
    } 
} 
 
 
package com.jadyer.vo; 
publicclass Address { 
    //如果将TIPS设为private的话,loginSuc.jsp中就无法获取它的属性值了 
    //事实上将一个静态的final属性设为private是毫无意义的 
    //因为既然设置成了静态,那么就是供他人调用的,如果再设成private的话,别的地方根本就无法调用了 
    //即使OGNL再怎么强大,它也不可能违反Java的规则,所以不要将静态的属性设为私有 
    publicstaticfinal String TIPS = "玄玉加油!!"; 
    //addr属性的setter和getter略 
    private String addr; 
} 
 
 
package com.jadyer.vo; 
publicclass Student { 
    private String username; 
    privateint grade; 
    /* 两个属性的setter和getter略 */ 
     
    //只要是重写一个类的构造方法,就必须要为这个类保留空的构造方法 
    //因为框架默认的都会去调用无参的空的构造方法 
    public Student(){}; 
    public Student(String username,int grade){ 
        this.username = username; 
        this.grade = grade; 
    } 
    @Override 
    public String toString() { 
        //如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】 
        return"{学生姓名:" + username +",成绩:" + grade + "}"; 
    } 
} 


LoginAction.java(用来提供OGNL测试的数据)

package com.jadyer.action; 
 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.HashSet; 
import java.util.List; 
import java.util.Map; 
import java.util.Set; 
 
import org.apache.struts2.interceptor.RequestAware; 
import org.apache.struts2.interceptor.SessionAware; 
 
import com.jadyer.vo.Student; 
import com.jadyer.vo.User; 
import com.opensymphony.xwork2.ActionSupport; 
 
@SuppressWarnings({"serial","unchecked"}) 
publicclass LoginActionextends ActionSupport implements RequestAware,SessionAware { 
    private User user; 
    private List testList = new ArrayList(); 
    private Set testSet =new HashSet(); 
    private Map testMap = new HashMap(); 
    private List stus = new ArrayList(); 
     
    /* 以上五个属性的setter和getter略 */ 
     
    private Map request; 
    private Map session; 
    publicvoid setRequest(Map request) { 
        this.request = request; 
    } 
    publicvoid setSession(Map session) { 
        this.session = session; 
    } 
     
    publicstatic String getStatic(){ 
        return"这是LoginAction中的一个静态方法"; 
    } 
    public String getCommon(){ 
        return"这是LoginAction中的一个普通方法"; 
    } 
     
    @Override 
    public String execute() throws Exception { 
        if(user.getUsername().trim().equalsIgnoreCase("admin") && user.getPassword().equals("jadyer")){ 
            testList.add("list11"); 
            testList.add("list22"); 
            testList.add("list33"); 
            testList.add("list44"); 
            testList.add("list55"); 
             
            testSet.add("set11"); 
            testSet.add("set22"); 
            testSet.add("set33"); 
            testSet.add("set22"); 
            testSet.add("set11"); 
             
            testMap.put("m11", "map11"); 
            testMap.put("m22","map22"); 
            testMap.put("m33", "map33"); 
            testMap.put("m44","map44"); 
            testMap.put("m55", "map55"); 
             
            stus.add(new Student("张三",88)); 
            stus.add(new Student("李四",77)); 
            stus.add(new Student("王五",66)); 
            stus.add(new Student("马六",55)); 
             
            request.put("req","这是通过OGNL中的#号获取的request属性范围的值"); 
            session.put("ses", "这是通过OGNL中的#号获取的session属性范围的值"); 
            request.put("BB","这是通过OGNL中的#号获取的request属性范围的BB"); 
            session.put("BB", "这是通过OGNL中的#号获取的session属性范围的BB"); 
            return SUCCESS; 
        }else{ 
            return INPUT; 
        } 
    } 
}
注意:这边将这些变量进行了初始化(new)。也可以不初始化,让框架帮你初始化,你只需要完成两件事情1 属性地类型必须是一个满足javabean规范的类,因为它要提供一个没有参数的构造方法。2 属性必须要满足javabean规范,提供对应的设置方法。


参考链接:

http://www.cnblogs.com/xly1208/archive/2011/11/19/2255500.html

http://blog.csdn.net/songylwq/article/details/7568859

http://www.360doc.com/content/10/1027/10/573136_64386997.shtml

http://blog.csdn.net/wxwlife2006/article/details/8242459


你可能感兴趣的:(struts2)