Struts2 OGNL表达式、ValueStack
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种方式
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更强大。
上一篇: 按摩复溜穴的神奇功效
下一篇: 大家知道吃凤梨减肥吗
推荐阅读
-
Struts2 OGNL调用公共静态方法详细介绍
-
Struts2 OGNL表达式、ValueStack
-
jsp脚本、jsp声明、jsp输出表达式、javascript、jsp标签、struts2标签
-
Struts2中表达式与值栈
-
Struts2 ognl 标签详解
-
jsp脚本、jsp声明、jsp输出表达式、javascript、jsp标签、struts2标签、struts2 action传值问题
-
Struts2 OGNL调用公共静态方法详细介绍
-
Struts2 (三) — OGNL与值栈
-
OGNL, JSTL, STRUTS2标签中符号#,$,%的用法示例
-
OGNL, JSTL, STRUTS2标签中符号#,$,%的用法示例