zoukankan      html  css  js  c++  java
  • struts2之OGNL用法

    浅析OGNL
    OGNL是Object-GraphNavigation Language的缩写,是一种功能强大的表达式语言
    通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能
    OGNL用得最多的地方就是和Struts2的标签绑定,也可以在配置文件中通过${}使用OGNL表达式

     

    OGNL$号的使用
    1..
    在国际化资源文件中,引用OGNL表达式
    2..在struts.xml文件中,引用OGNL表达式

     

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

    OGNL#号的使用
    OGNL中的#号可以取出堆栈上下文中存放的对象

    名称

    作用

    例子

    attr

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

    #attr.userName相当于按顺序从三个范围读取userName属性直到找到为止

    request

    包含当前HttpServletRequest的属性的Map

    #request.userName相当于request.getAttribute("userName")

    session

    包含当前HttpSession的属性的Map

    #session.userName相当于session.getAttribute("userName")

    application

    包含当前应用的ServletContext的属性的Map

    #application.userName相当于application.getAttribute("userName")

    parameters

    包含当前HTTP请求参数的Map

    #parameters.id[0]相当于request.getParameter("id")

     

    获取Action中的属性值或者Action中的对象的某某属性值
    利用<s:property/>标签可以直接获取Action中的引用类型user里面的username属性
    同样可以通过user.address.addr获取user中引用类型address中的addr属性的值
    像这种一层一层往下传递的访问方式,即所谓的导航,也就是一步步的往下调用

     

    调用Action的对象里面的普通方法
    默认的会把Action放到值栈里面,而值栈在访问的时候,并不需要值栈的名字
    当我们调用<s:propertyvalue="user.getVOMethod()"/>的时候
    它会自动到值栈里面查找Action对象里面有没有user对象,然后它就发现有user
    然后它就再找user里面有没有getVOMethod()方法,然后它发现有,于是调用getVOMethod()
    实际上调用User中的getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的
    都是到值栈里面查找,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法

     

    调用Action中的静态方法
    同样我们也可以在JSP页面中写一个OGNL表达式调用Action中的静态方法
    调用Action中的静态方法时,与调用user对象的getVOMethod()方法的过程,是截然不同的
    此时value的写法是固定的,以@开头,后面跟上具体的包名,然后@加上静态方法
    比如<s:propertyvalue="@com.jadyer.action.LoginAction@getStatic()"/>
    另外user对象是LoginAction中的一个属性,这个属性会自动的放到值栈里面
    而值栈调用的时候,不用加上@或者包名等等,所以直接user.getVOMethod()就可以了

     

    调用JDK类中的静态方法
    可以使用<s:propertyvalue="@@floor(46.58)"/>输出floor()的执行结果
    这就意味着如果不在@@中指定类的话,默认的就表示java.lang.Math
    当前大多数情况下,我们都不会省略这个类,都会写全了的,然后在后面加上静态方法

     

    集合的伪属性
    OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBean模式,例如size()、length()
    当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性
    比如获取List的大小:<s:propertyvalue="testList.size"/>
          List的伪属性:
    size、isEmpty、iterator
           Set的伪属性:size、isEmpty、iterator
           Map的伪属性:size、isEmpty、keys、values
      Iterator的伪属性:next、hasNext
    Enumeration伪属性:next、hasNext、nextElement、hasMoreElements

     

    获取集合中元素的实质就是调用它的toString()方法
    它还可以直接获取集合中的元素,事实上是在调用集合的toString()方法
    所以我们可以根据实际情况通过重写集合的toString()方法来实现个性化输出
    甚至它还可以像访问数组那样,直接testList[2]获取集合中的元素
    但这种方法只适用于List,不适用于Map。因为Map的索引是key,不是数值
    另外,由于HashSet中的元素是没有顺序的,所以也不能用下标获取单个元素

     

    Lambda表达式
    补充一下:使用Lambda表达式可以在OGNL中书写递归式子,在帮助中对它有很详细的说明
    打开帮助中的//struts-2.0.14-all//struts-2.0.14//docs//index.html页面
    在左侧的Documentation下面点击Guides链接,然后在这个页面中点击OGNL
    最后跳转到//struts-2.0.14-all//struts-2.0.14//docs//docs//ognl.html
    将这个页面右侧的下拉条拖放到最下面,就会看到它的说明了,它举的例子如下所示
    <s:property value="#fib =:[#this==0? 0 : #this==1 ? 1 : #fib(#this-2)+#fib(#this-1)], #fib(11)" />
    Lambda表达式的语法是:[...] ,中括号前面有一个冒号,所有东西都在中括号里面写
    也就是说我们只要看到一个冒号跟着一个中括号,就表示这里使用的是Lambda表达式
    #this指的是表达式的参数
    所以这个例子可以这样理解:先判断这个参数是否等于零,如果等于零,那么它的值最后就是零
    如果参数不等于零,就再判断它是否等于壹。如果参数等于壹,那么它的值最后就是壹
    如果参数不等于壹,就继续调用#fib。注意这里已经用中括号将整体的值赋给了fib
    实际上很少能够用得到Lambda表达式

     

    利用投影获取属性
    利用投影获取List中对象的username属性时,其中{}表示的是一个集合
    stus.{username}就表示将suts中所有的username属性取出组成一个新的列表

     

    利用选择获取属性
    OGNL表达式是很灵活的,可以同时使用选择技术投影技术获取属性
    使用选择技术时,#this代表当前元素,问号?是把所有满足条件的元素都取出来
    上箭头^是开始的意思,所以stus.{^#this.grade>=60}.{username}输出的是[张三]
    注意,此时输出文本中包含中括号,这表示它是一个列表
    stus.{?#this.grade>=60}.{username}[0]输出的是张三,是字符串,二者是不同的
    美元符号$是结束的意思,所以stus.{$#this.grade>=60}.{username}输出的是[王五]
    这三个符合:问号、上箭头、美元符所返回的都是List

     

     

    浅析值栈
    ValueStack对象
    相当于一个,它贯穿整个Action的生命周期,每个Action类的对象实例都会拥有一个ValueStack对象
    当Struts2接收到一个*.action请求后,并不是直接调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点
    值栈也位于内存中
    ,它也是和parametersrequestsessionapplicationattr对象放在一起的
    值栈属于ONGL Context里面的根对象。也就是说它位于整个内存中最最重要的地方,所以叫根对象
    根对象和另外五个对象是有区别的,根对象可以省写#号,比如<s:propertyvalue="user.username"/>
    值栈的生命周期与request请求相关,每次请求产生一个值栈。默认所有的Action会被自动放到值栈里

     

    服务器跳转时共用值栈
    假设从一个Action11通过服务器跳转到Action22的话,就意味着这两个Action是共享一个值栈的,因为一次请求只使用一个值栈
    这时内存中情况是这样的:首先接收到Action11请求后,会产生一个值栈,在栈顶存放Action11对象以及它所有的属性
    然后经过服务器跳转到Action22,这时就会把Action22对象压入值栈的栈顶位置,此时Action11对象以及它的所有属性就位于栈底了

     

    取值过程
    栈的特征是后进先出。于是首先到栈顶的对象里查找是否存在这个属性,如果栈顶的Action22对象中不存在这个属性的话
    它就会继续向下寻找直至栈底对象,一直查找是否存在这个属性
    如果最后找到该属性的话,那么就会在JSP页面中通过<s:propertyvalue="username"/>输出属性值
    如果在Action22和Action11都有一个同名的同类型的username属性的话,那么将输出Action22中的属性值
    因为它是先从栈顶开始寻找属性的,值栈的特征就是后进先出,但有个前提:请求过程是通过服务器跳转的

     

    三个语法
    假设此时想要获取Action11中的username属性的话,就可以使用值栈的Top语法或者N语法
    使用Top语法
    获取值栈中的第二个对象的属性:<s:property value="[1].top.username"/>
    使用 N 语法
    获取值栈中的第二个对象的属性:<s:propertyvalue="[1].username"/>
    另外值栈还有一个@语法,例如使用@语法调用Action中的静态方法:<s:property value="@vs@getVOMethod()"/>
    @vs@get()等价于@vs1@getVOMethod()
    ,指的是栈顶对象的静态getVOMethod()方法
    同理@vs2@getVOMethod()就是取值栈中第二个对象的静态getVOMethod()方法

     

    客户端跳转时使用各自的值栈
    假如中间某一个步骤中出现了客户端跳转的话,那么两个Action所使用的就是两个不同的值栈了
    所以在Action22中就不能再使用Action11中的属性了,在最后跳转到的JSP页面中也就无法获取Action11的属性了
    也即从Action22跳转到JSP页面时使用的是redirect的话,那么最后值栈中是没有任何的Action对象的
    这个时候我们可以通过链接传参,比如<result type="redirect">test.jsp?netname=${username}</result>
    意思就是取出Action22中的username属性作为参数,通过浏览器地址栏传递到JSP页面中
    然后使用OGNL中的#获取Paraments对象的属性,即<s:propertyvalue="#parameters.netname"/>就可以取到值了

     

    手工向值栈中压入对象
    正常情况下值栈保存的是Action对象,而我们也可以直接往值栈中添加其它对象,这时可以在Action中添加如下代码
    向值栈中添加对象:ActionContext.getContext.getValueStack().push(new Student("沈浪",22));
    而且我们手工往值栈中添加的Student对象会位于栈顶。这是因为Struts2会首先初始化Action,然后才能调用它的方法
    初始化Action的时候,便把Action放到值栈中了,然后在执行它的execute()方法时,就又往值栈中添加了Student对象

     

    补充
    1..
    当OGNL取不到值的时候,它不会报错,而是什么都不显示
    2..<s:property value="[0]"/>返回的是ValueStack中从上至下的所有的Object
        <s:propertyvalue="[1]"/>返回的是ValueStack中从上至下的第二个Object
    3..<s:property value="[0].username"/>返回的是成员变量username的值
        假设ValueStack中存在两个Action的话,如果第一个Action如果没有username变量
        那么它会继续找第二个Action。那么在什么情况下ValueStack中会存在两个Action呢
        答案是在struts.xml中配置的是从一个Action通过<resulttype="chain">跳转到另一个Action
    4..<constantname="struts.ognl.allowStaticMethodAccess"value="true"/>
        在Struts2.1.6中必须设置struts.ognl.allowStaticMethodAccesstrue之后
        才允许使用OGNL访问静态方法。而在Struts2.0.11则无需设置,即可直接访问

     

     

    eg:User对象属性获取
    如User中有username和password字段
    获取username属性<s:property value="user.username" />
    获取password属性<s:property value="user.password" />

    若User中又包含定义了address对象,address对象中包含有addr属性,则可以这样访问
    获取addr属性<s:property value="user.address.addr" />

    若User中还包含一个get()的普通方法,可以这样调用
    <s:property value="user.get()" />
    以上是调用值栈中对象的普通方法,user为值栈中的对象

    调用action中的静态方法get(),普通方法不能直接调用
    <s:property value="@com.netshuai.action.ManagerAction@get()" />
    以上为调用非值栈中的静态方法

    调用JDK中类的静态方法<s:property value="@java.lang.Math@floor(32.56)" />
    上例也可写成<s:property value="@@floor(32.56)" />,省略前面的类则默认使用java.lang.Math类,其他类不可省略

    调用普通类中的静态属性<s:property value="@com.netshuai.model.Address@city" />
    address中的city静态属性要用public声明

    调用普通类的构造方法,如构造方法为
    public User(String username)
    {
          this.username=username;
    }
    调用方法为<s:property value="new com.netshuai.model.User('hello').username" />,则返回username值为hello

    获取List<s:property value="list" />
    获取List中的某一个元素<s:property value="list[0]" />
    获取List的大小<s:property value="list.size" />
    获取Set<s:property value="set" />
    无法获取Set中的某一个元素,因为Set没有顺序
    获取Map<s:property value="map" />
    获取Map中所有key的值<s:property value="map.keys" />
    获取Map中所有value的值<s:property value="map.values" />
    获取Map中的某一个元素<s:property value="map['k1']" />

    获取List所有对象<s:property value="listObject" />,需要重写toString()方法才能正常显示对象的值 
    利用投影获取List中所有对象的username属性<s:property value="listObject.{username}" />
    利用投影获取List中第一个对象的username属性<s:property value="listObject.{username}[0]" />
    利用选择获取List中年龄大于30的对象<s:property value="listObject.{?#this.age>30}" />
    利用选择获取List中年龄大于30的对象的username<s:property value="listObject.{?#this.age>30}.{username}" />
    利 用选择获取List中年龄大于30的第一个对象的username<s:property value="listObject.{?#this.age>30}.{username}[0]" />或<s:property value="listObject.{^#this.age>30}.{username}" />
    利用选择获取List中年龄大于30的最后一个对象的username<s:property value="listObject.{$#this.age>30}.{username}" />

    获取parameters中的属性<s:property value="#parameters.name" />
    获取request中的属性<s:property value="#request.name" />
    获取session中的属性<s:property value="#session.name" />
    获取application中的属性<s:property value="#application.name" />
    <s:property value="#attr.name" />按顺序遍历上面四个对象,然后返回首先找到的值

    %{}可以取出存在值堆栈中的Action对象,直接调用它的方法,如%{getText('key')}可以取出国际化信息

    ${}可以用在国际化资源文件中和struts2配置文件中

    使用top获取值栈中第二个对象<s:property value="[1].top.user"/>
    使用top获取值栈中第二个对象的属性<s:property value="[1].user"/>

    调用值栈中action的静态方法get()<s:property value="@vs@get()"/>,vs也可写做vs1
    调用值栈中第二个action的静态方法get()<s:property value="@vs2@get()"/>

    将一个对象放入值栈
    ActionContext.getContext().getValueStack().push(user);
     
    总结:
    1.当使用OGNL调用静态方法的时候。需要按照如下语法编写表达式:@package.classname@methodname(parameter)
    2.对于OGNL来说。java.lang.Math是其的默认类。如果调用java.lang.Math的静态方法时。无需指定类的名字。比如@@min(4,10)
    3.对于OGNL来说,数组和集合是一样的。都是通过下标索引来访问的。构造集合的时候用{...}形式
    4.使用OGNL来映射(Map)的语法格式如下所示:#{'key1':'value1','key2','value2'}
    5.过滤(filtering):conllection.{?,表达式}这是针对集合来处理的。当“?”被"^"代替时表示获取集合中的第一个对象。当“?”被"$"代替时表示获取集合中的最后一个对象。
    6.OGNL针对集合提供了一些伪属性(如size,isEmpty),让我们可以通过属性的方式来调用方法。(本质原因在于集合当中的很多方法并不符合javaBean的命名规则),但我们依然可以通过调用方法来实现与伪属性相同的目的
    7.在使用过滤操作的时候。我们通常使用#this.该表达式用于代表当前正在迭代的集合中的对象
    8.过滤(projection):collection.{expression}
    9.过滤与投影的区别:类比于数据库中的表。过滤是取行的操作,而投影是取列的操作。
    10.在struts2中有个称之为值栈的概念(valueStack)
    11.在struts2中,根对象就是valueStack,在struts2的任何流程中。valueStack中的最顶层对象一定是Action对象。
    12.访问静态方法或是静态成员变量的:@vs@method
    13.关于struts2标签库属性值的%和#号的关系,如果标签的属性值是OGNL表达式,那么无需加上%{}
    如果 标签的属性值的是字符串类型的。那么在字符串当中凡是出现%{}都会被解析成OGNL表达式,解析完毕后再与其他的字符串进行拼接构造出最后的字符串值。我们可以再所有的属性值加上%{},这样如果该属性值是OGNL表达式,那么标签处理类就会将%{}忽略掉
  • 相关阅读:
    【Python数据分析】NumPy之数组对象基础
    【Oracle11g】20_函数
    【Word】排版技巧
    cache介绍
    cache verilog实现
    在verilog中使用格雷码
    同步fifo与异步fifo
    AHB总线协议(二)
    Android Handler 消息机制原理解析
    值得推荐的开源C/C++框架和库
  • 原文地址:https://www.cnblogs.com/sxxjyj/p/6093405.html
Copyright © 2011-2022 走看看