欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Struts2 OGNL表达式、ValueStack

程序员文章站 2022-06-19 20:03:38
OGNL简介 OGNL,即Object-Graph Navigation Language,对象视图导航语言,是一种数据访问语言,比EL表达式更加强大: EL只能从11个内置对象中取值,且只能获取属性,不能调用对象的方法。 OGNL可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图。 OG ......

 

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的内部结构

Struts2  OGNL表达式、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种方式

valuestack valuestack = actioncontext.getcontext().getvaluestack();
        
object attribute = servletactioncontext.getrequest().getattribute("struts.valuestack");
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方法

public class loginaction extends actionsupport{
    private string name;
    private user user;

    public string getname() {
        return name;
    }

    public user getuser() {
        return user;
    }

    @override
    public string execute() throws exception {
        name = "chy";
        user = new user("张三", 19);
        return "index";
    }

}

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

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

 

在jsp中取值:

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

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

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

 

 

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

  ${requestscope.name}
  ${requestscope.user.name}

  <%=request.getattribute("name") %>
  <%=(user)request.getattribute("user") %>

  <%
    string name = (string) request.getattribute("name");
    out.print(name);

    user user = (user)request.getattribute("user");
    out.print(user.getname());
  %>

 

 

el表达式可以不指定requestscope:

  ${name}
  ${user.name}

默认先在requestscope中找,找不到就到valuestack中找。

 

 

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

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

 

 

 

 

2、直接操作valuestack

public class loginaction extends actionsupport{

    @override
    public string execute() throws exception {
        valuestack valuestack = actioncontext.getcontext().getvaluestack();
        string name = "chy";
        user user = new user("张三", 18);
        valuestack.set("user",user);
        valuestack.set("name",name);
        return "index";
    }

}

 

jsp中取值:

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

 

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

 

 

或者使用push():

public class loginaction extends actionsupport{

    @override
    public string execute() throws exception {
        valuestack valuestack = actioncontext.getcontext().getvaluestack();
        user user = new user("张三", 18);
        valuestack.push(user);
        return "index";
    }

}
<s:property value="name" />

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

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

 

 

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

        valuestack.push(user1);
        valuestack.push(user2);

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

 

 

 

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

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

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

public class loginaction extends actionsupport{

    @override
    public string execute() throws exception {
        valuestack valuestack = actioncontext.getcontext().getvaluestack();
        arraylist<string> list = new arraylist<>();
        list.add("刘");
        list.add("关");
        list.add("张");
        valuestack.set("list",list);
        return "index";
    }

}

 

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

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

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

 

 

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

 

 

 

 

 

3、存取context中的数据

public class loginaction extends actionsupport{

    @override
    public string execute() throws exception {
        httpservletrequest request = servletactioncontext.getrequest();
        request.setattribute("user",new user("chy",18));
        request.setattribute("group","vip");
        return "index";
    }

}

 

  <s:property value="#request.group" />
  <s:property value="#request.user" />
  <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中获取请求参数:

 <s:property value="#parameters.user" />
  <s:property value="#request.parameters.user" />
  <%=request.getparameter("user")%>

 

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

 

  

 

 


 

 

 

ognl表达式

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

 

访问valuesatck中的数据:

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

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

 

 

 

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

 

遍历list:

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

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

 

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

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

hello <s:property value="item" />!
<div class="">
    <p>
     hello   <s:property value="item" />
   </p> <img src="" /> </div>

 

 

 

构建map:

<s:iterator var="entry" value="#{'name':'刘备','age':40,'group':'蜀'}">
    <s:property value="entry" />
   <s:property value="entry.key" />
   <s:property value="entry.value" /> </s:iterator> <s:iterator value="#{'name':'刘备','age':40,'group':'蜀'}"> <s:property value="key" />:<s:property value="value" /> </s:iterator>

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

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

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

 

 

单选按钮:

<s:radio list="{'男','女'}" name="gender" label="性别" />
<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作为字符串原样显示。

<%
    session.setattribute("user","chy");
%>

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

 

 

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

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

 

 

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

%{'#session.user'}

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

 

 

 

 

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

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

 

.properties配置文件:

user=${#session.user.name}

 

xml配置文件:

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

 

 

 

 

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

<%
user user=new user("曹操",40);
session.setattribute("user",user);
%>

<s:property value="#session.user.name" />
<s:property value="#session.user.getname()" />
<s:property value="#session.user.setname('chy')" />
<s:property value="'hello'.length()" />

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

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

 

 

 

 

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

<s:property value="@java.lang.math@pi" />
<s:property value="@java.lang.math@abs(-10)" />

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

 

 

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

<struts>
    <constant name="struts.ognl.allowstaticmethodaccess" value="true"></constant>

    <package name="action" namespace="/" extends="struts-default">
    
    </package>

</struts>

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

 

 

和el表达式一样,ognl表达式没有空指针异常、没有数组越界,如果没有指定的变量、方法,不会出现异常。

ognl比el更强大。