OGNL简介

OGNL,即Object-Graph Navigation Language,对象视图导航语言,是一种数据访问语言,比EL表达式更加强大:

  • EL只能从11个内置对象中取值,且只能获取属性,不能调用对象的方法。
  • OGNL可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图。

OGNL是可以单独使用的。OGNL并不属于Struts2,只不过Struts2觉得OGNL不错,把OGNL给整合进来了。

Struts2的8个核心jar包中已经包含了OGNL的jar包,不需要我们再导包。


ValueStack(值栈) 简介

ValueStack是Struts2的一个接口,用于存储Struts中的数据。ValueStack接口有一个实现类OgnlValueStack。

创建一个Action实例时,会自动为这个Action实例创建一个ActionContext实例,创建ActionContext实例时,又会自动创建一个ValueStack(OgnlValueStack)的实例,将OgnlValueStack的引用放到ActionContext中,将ActionContext的引用放到Action中。

这三者的生命周期是一致的。

ActionContext存储数据,实际是用ActionContext中的ValueStack来存储数据。


ValueStack的内部结构

ValueStack由2部分组成:root、context。

root部分是一个CompoundRoot对象,extends  ArrayList,内部维护了一个列表。

context部分是一个OgnlContext对象,implements Map,内部维护了一个Map,用来存放常用对象的引用,其中也包括root部分的引用,所以OgnlContext其实是可以访问到所有的数据的。

Ognl表达式使用的数据就是ValueStack中的数据。

ActionContext能获取到域对象(Map)、获取到原生的Servlet对象(request、response、session),就是因为ActionContext内部有ValueStack的引用,可以访问ValueStack中的数据(对象)。

可以在jsp中用<s:debug>标签显示ValueStack的调试信息。

平时说的操作值栈,是指操作root部分,因为context中这些常用对象的引用由struts自动管理,无需我们操作。

ValueStack,顾名思义,是一个栈,ValueStack的栈指的是root部分,栈是通过ArrayList实现的。


获取ValueStack对象的2种方式

  1. ValueStack valueStack = ActionContext.getContext().getValueStack();
  2.  
  3. Object attribute = ServletActionContext.getRequest().getAttribute("struts.valueStack");
  4. Object attribute1 = ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

获取ValueStack对象有2种方式:通过ActionContext对象、通过request对象。

AtionContext中有ValueStack的引用,能获取到;

Struts2对request进行了包装、增强(拦截器|过滤器),request中也有ValueStack的引用,也能获取到。

但request是以属性获取,返回值是Object,需要强转,且字符串常量不好记,通过ActionContext获取更方便。

字符串常量  ServletActionContext.STRUTS_VALUESTACK_KEY  即  "struts.valueStack"。

一个Action实例中,只有一个对应的ActionContext对象,只有一个对应的ValueStack对象。


ValueStack的数据存取

1、将数据设置为Action的成员变量,并提供getter方法

  1. public class LoginAction extends ActionSupport{
  2. private String name;
  3. private User user;
  4.  
  5. public String getName() {
  6. return name;
  7. }
  8.  
  9. public User getUser() {
  10. return user;
  11. }
  12.  
  13. @Override
  14. public String execute() throws Exception {
  15. name = "chy";
  16. user = new User("张三", 19);
  17. return "index";
  18. }
  19.  
  20. }

root部分是栈,Struts默认会把当前Action的实例压入栈中,所以能从ValueStack中取到此Action实例的属性。

取Action的属性,底层是调用此Action的getter方法,所以需要提供对应的getter方法。

在jsp中取值:

  1. <s:property value="name" />
  2. <s:property value="user.name" />

<s:property>是struts2的标签,value中写ognl表达式。

user.name底层是调用user对象的getter方法,所以User类需要提供对应的getter方法。

Struts2对request对象进行了增强,request中也有ValueStack的引用,所以request中也能获取到ValueStack中的数据。

  1. ${requestScope.name}
  2. ${requestScope.user.name}
  3.  
  4. <%=request.getAttribute("name") %>
  5. <%=(User)request.getAttribute("user") %>
  6.  
  7. <%
  8. String name = (String) request.getAttribute("name");
  9. out.print(name);
  10.  
  11. User user = (User)request.getAttribute("user");
  12. out.print(user.getName());
  13. %>

EL表达式可以不指定requestScope:

  1. ${name}
  2. ${user.name}

默认先在requestScope中找,找不到就到ValueStack中找。

此种方式是将数据存到ValueStack的root部分。

如果存储的数据个数较多,Action中会有大量的成员变量、getter方法,很冗杂,一般不用这种。

2、直接操作ValueStack

  1. public class LoginAction extends ActionSupport{
  2.  
  3. @Override
  4. public String execute() throws Exception {
  5. ValueStack valueStack = ActionContext.getContext().getValueStack();
  6. String name = "chy";
  7. User user = new User("张三", 18);
  8. valueStack.set("user",user);
  9. valueStack.set("name",name);
  10. return "index";
  11. }
  12.  
  13. }

JSP中取值:

  1. <s:property value="name" />
  2. <s:property value="user.name" />

此种方式是将数据都放到一个Map中,将此Map压入栈顶,在JSP直接通过Map的key来获取对应的value。

或者使用push():

  1. public class LoginAction extends ActionSupport{
  2.  
  3. @Override
  4. public String execute() throws Exception {
  5. ValueStack valueStack = ActionContext.getContext().getValueStack();
  6. User user = new User("张三", 18);
  7. valueStack.push(user);
  8. return "index";
  9. }
  10.  
  11. }
  1. <s:property value="name" />

直接将push的对象压入栈顶,JSP中通过属性名来获取值。

底层是调用对象的getter方法来获取属性值,所以对象需要提供getter方法。

一次push就向栈顶压入一个对象,取对象属性的时候不能带对象名,是从栈顶开始向栈底寻找这个属性,找到就返回。

  1. valueStack.push(user1);
  2. valueStack.push(user2);

比如push2次, <s:property value="name" /> ,取到的是靠近栈顶的user2的name属性。

int、String、Array、List、Map等对象push到栈中,能获取到length、size这些属性值,但获取不到这些对象本身,也获取不到数组、集合中的元素,因为这些数组、集合中的元素不是属性,没有属性名。

set()是将数据都放到一个Map中,将此Map压入栈顶,数据都在栈顶。

set()根据Map中的key来取元素,能获取到对象本身,如果对象是数组、集合,也能获取到数组、集合中的元素。

  1. public class LoginAction extends ActionSupport{
  2.  
  3. @Override
  4. public String execute() throws Exception {
  5. ValueStack valueStack = ActionContext.getContext().getValueStack();
  6. ArrayList<String> list = new ArrayList<>();
  7. list.add("刘");
  8. list.add("关");
  9. list.add("张");
  10. valueStack.set("list",list);
  11. return "index";
  12. }
  13.  
  14. }
  1. <s:property value="list" />
  2. <s:property value="list[0]" />

可通过key获取对象本身,也可以通过下标获取Array、List的某个元素,可通过key获取Map对象中某个键值对的value。

set()比push()更优,推荐使用。

既然是栈,操作的自然是root部分,存取的是root部分的数据。

3、存取context中的数据

  1. public class LoginAction extends ActionSupport{
  2.  
  3. @Override
  4. public String execute() throws Exception {
  5. HttpServletRequest request = ServletActionContext.getRequest();
  6. request.setAttribute("user",new User("chy",18));
  7. request.setAttribute("group","vip");
  8. return "index";
  9. }
  10.  
  11. }
  1. <s:property value="#request.group" />
  2. <s:property value="#request.user" />
  3. <s:property value="#request.user.name" />

需要加#,#表示是从context(几个域对象)中取数据。

获取原生的Servlet对象,setAttribute()存入数据,在JSP从对应的对象中取出来即可。

请求参数封装在request对象的parameters对象中,不是直接封装在request对象中,request中直接封装的是setAttribute()存入的数据。

把request作为一个大Map,里面还有一个小Map,小Map用于封装请求参数。 Map<String, String[]> parameterMap = request对象.getParameterMap(); 。

比如表单字段: 用户名:<input type="text" name="user" />

Object obj=request对象.getAttribute("user");  获取的是setAttribute()存入request中的数据。

String user = request对象.getParameter("user"); 获取的才是请求参数(从小Map中查找数据)。

在JSP中获取请求参数:

  1.  <s:property value="#parameters.user" />
  2. <s:property value="#request.parameters.user" />
  3. <%=request.getParameter("user")%>

<s:property value="#request.user" /> 获取的不是请求参数,而是setAttribute()存入request中的数据。


OGNL表达式

OGNL是一种数据访问语言,可直接使用(写在Java代码中,即可获取值,也能设置值),也可配合Struts2标签使用,写在Struts2标签中叫做OGNL表达式,用于获取值。

访问ValueSatck中的数据:

  1. <s:property value="name" />
  2. <s:property value="user.name" />
  3. <s:property value="#parameters.user" />

不带#的是从root中取值,带#的是从context中取值。

特殊字符#:从context中取值,构建Map。

遍历List:

  1. <s:iterator var="item" value="{'刘备','关羽','张飞'}">
  2. <s:property value="item" />
  3. </s:iterator>

var指定临时变量,表示一项,value指定Array、List。<s:iterator>的元素体即循环体。

不能 <s:property value="hello+item" /> 或者 <s:property value="hello"+"item" /> 这样来指定格式,这样解析不了临时变量。

可以配合其他标签来指定格式,比如:

  1. hello <s:property value="item" />!
  1. <div class="">
  2. <p>
         hello
  3.   <s:property value="item" />
       </p>
  4. <img src="" />
  5. </div>

构建Map:

  1. <s:iterator var="entry" value="#{'name':'刘备','age':40,'group':'蜀'}">
  2. <s:property value="entry" />
       <s:property value="entry.key" />
       <s:property value="entry.value" />
  3. </s:iterator>
  4.  
  5. <s:iterator value="#{'name':'刘备','age':40,'group':'蜀'}">
  6. <s:property value="key" />:<s:property value="value" />
  7. </s:iterator>

#表示这玩意儿是Map。Map默认var为key、value,所以可缺省 var="key,value" 。

如果指定了var="entry",可通过entry.key,entry.value来引用属性。

IDEA下可能会报红,这是IDEA的问题,代码本身没有错误。

单选按钮:

  1. <s:radio list="{'男','女'}" name="gender" label="性别" />
  2. <s:radio list="#{'male':'男','female':'女'}" name="gender" label="性别" />

使用List时,<input type="radio" />的value、选项文字都是list中的元素。

使用Map时,Map的key作为<input type="radio" />的value,Map的value作为选项文字。

构建Map时,key必须引,value是字符、字符串才引。

特殊符号%:强制解析、不解析OGNL表达式

有的Struts标签默认会解析OGNL表达式,有的Struts标签默认不会解析OGNL表达式。

比如<s:textfield />默认不会解析OGNL表达式,会将#session.user作为字符串原样显示。

  1. <%
  2. session.setAttribute("user","chy");
  3. %>
  4.  
  5. <s:textfield name="user" value="#session.user" label="用户名" />

将OGNL表达式放在%{   }中,会作为OGNL表达式处理,强制解析。

  1. <s:textfield name="user" value="%{#session.user}" label="用户名" />

有的Struts标签默认会解析OGNL表达式,如果不想解析OGNL表达式:

  1. %{'#session.user'}

放在%{'     '}中即可,会作为字符串处理。

特殊符号$:在配置文件中使用OGNL表达式取值

将OGNL表达式放在${   }中即可。

.properties配置文件:

  1. user=${#session.user.name}

xml配置文件:

  1. <param>${#session.user.name}</param>

使用OGNL表达式访问成员属性、调用成员方法

  1. <%
    User user=new User("曹操",40);
    session.setAttribute("user",user);
    %>
  2.  
  3. <s:property value="#session.user.name" />
    <s:property value="#session.user.getName()" />
    <s:property value="#session.user.setName('chy')" />
  1. <s:property value="'hello'.length()" />

访问成员变量,底层其实是调用对应的getter方法。

如果方法有返回值,会用返回值替换原来的OGNL表达式。

使用OGNL表达式访问静态成员(static)

  1. <s:property value="@java.lang.Math@PI" />
  2. <s:property value="@java.lang.Math@abs(-10)" />

以  @全限定类名@静态变量|静态方法 的方式调用,必须是全限定类名,可以是java自带的类,也可以是自定义的类。

访问静态变量不用进行常量配置,但调用静态方法必须在struts.xml中进行常量配置:

  1. <struts>
  2. <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
  3.  
  4. <package name="action" namespace="/" extends="struts-default">
  5.  
  6. </package>
  7.  
  8. </struts>

允许静态方法调用,输入ognl就出来了,将value设置true(默认为false)。

和EL表达式一样,OGNL表达式没有空指针异常、没有数组越界,如果没有指定的变量、方法,不会出现异常。但OGNL比EL更强大。

OGNL可以单独使用,但OGNL表达式常常需要配合Struts标签使用,在html标签中单独使用OGNL表达式无效,比如<p>#request.name</p>会原样显示OGNL表达式,不会解析OGNL表达式,加上%也不会强制解析:<p>%{#request.name}</p>。

Struts2 OGNL表达式、ValueStack的更多相关文章

  1. struts2 OGNL表达式

    一.OGNL OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者调用对 ...

  2. struts2 OGNL 表达式

    一.Struts 2支持以下几种表达式语言: OGNL(Object-Graph Navigation Language),可以方便地操作对象属性的开源表达式语言:JSTL(JSP Standard ...

  3. struts2 ognl表达式访问值栈

    1:简单的说,值栈是对应每一个请求对象的轻量级的数据存储中心,在这里统一管理着数据,供Action.Result.Interceptor等Struts2的其他部分使用,这样数据被集中管理起来而不凌乱. ...

  4. JSTL标签,EL表达式,OGNL表达式,struts2标签 汇总

    一下纯属个人总结摘抄,总结一起方便查看,解决疑问,有遗漏或错误,还请指出.       1,JSTL标签总结: a).JSTL标签有什么用?          JSTL是由JCP(Java Commu ...

  5. struts2 与 OGNL 表达式,jsp中 利用ognl 在valuestack中取值

    在Struts2中,一个请求在终于到达Action的方法之前,Action对象本身会被压入ValueStack(实际上就是放到ValueStack的CompoundRoot中),所以Action对象是 ...

  6. struts2(六)之ognl表达式与ActionContext、ValueStack

    前言 前面已经把struts2讲内容说了一半了,我写的很详细,希望对博友们有帮助. 一.OGNL表达式语言概述 1.1.OGNL表达式简介 百度上是这样说: OGNL是Object-Graph Nav ...

  7. 【Struts2五】ValueStack以及ognl表达式二(经常使用标签)

    Ognl经常使用标签:   1.s:debug       假设把该标签放入到s:iterator中能够看到当前正在迭代的元素的状态    2.s:property       1.输出       ...

  8. Struts2的OGNL表达式语言

    一.OGNL的概念 OGNL是Object-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者 ...

  9. Struts2的标签库(二)——OGNL表达式

    Struts2的标签库(二) --OGNL表达式 1.Struts2中的OGNL表达式增加了ValueStack的支持. 注:ValueStack--实际上是一个容器对象,该对象在启动Struts2框 ...

随机推荐

  1. MySQL数据库(一)索引

    索引的作用是操作数据库时避免全表扫描. 索引的机制 B Tree与B+Tree索引 B(blance) 树可以看作是对2-3查找树的一种扩展,即他允许每个节点有M-1个子节点. 根节点至少有两个子节点 ...

  2. Linux PXE + Kickstart 自动装机

    大规模装机时,使用无人值守装机便可大大简便人工操作,提高效率. PXE 网络安装 配置双网卡 这里ens33为nat网络,ens37为仅主机网络,配置ens37 [root@localhost ~]# ...

  3. Java重定向标准输入/输出

    在System类中提供了三个重定向标准输入/输出的方法static void setErr(PrintStream err) 重定向“标准”错误输出流static void setIn(InputSt ...

  4. oracle 循环插入数据

    参考链接:oracle 行转列 pivot函数基本用法 --建表 --drop table SalesList; create table SalesList( keHu varchar2(20), ...

  5. 文件名工具类 MoFileNameUtil

    文件名工具类 MoFileNameUtil MoFileNameUtil public class MoFileNameUtil { //不包含点号 public static String getF ...

  6. Python 链表(linked list)

    链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 链表由一系列结点组成,结点可以在运行时动态生成 优点 由于不必须按顺序存储,链表在插入.删除的时候 ...

  7. 为了Runtime Broke 关了一堆东西

    可是,好像还是不行啊?CPU还是用了 10-20% 还得写这个随笔,怕自己关东西关多了,以后还得回复. https://www.drivereasy.com/knowledge/runtime-bro ...

  8. css3之水波效果

    这些效果可谓多种多样,当然用canvas.svg也都能实现奈何对这些有不熟悉(尴尬),不过咱们用css来写貌似也没想象中的那么难吧. 一  悬浮球水波效果 效果图 css .container { w ...

  9. 线性结构之习题选讲-ReversingLinkedList

    目录 一.什么是抽象的链表 二.单链表的逆转 三.测试数据 3.1 边界测试 更新.更全的<数据结构与算法>的更新网站,更有python.go.人工智能教学等着你:https://www. ...

  10. 解决静态方法调用注入的service

    在使用jpa的复杂查询时,声明了specification时声明为静态方法,导致注入的service无法使用,故想到俩种方式,一种手动注入,一种注解注入,此文使用的时注解注入: 解决静态方法调用注入的 ...