Struts 2框架使用OGNL作为默认的表达式语言
使用 OGNL,可以用简洁的语法来完成对 java 对象的导航。通常来说:通过一个“路径”来完成对象信息的导航,这个“路径”可以是到 java bean 的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get 或者 set 方法来完成
在struts2中,OGNL表达式需要配合Struts标签才可以使用
OGNL三要素
- 表达式:OGNL根据表达式解析该干什么,表达式就是有语法结构的字符串
- Root对象:也是ValueStack(值栈),可以理解为OGNL的操作对象。当我们指定了一个表达式的时候,需要针对Root对象来进行OGNL表达式的计算并且返回结果。
- 上下文(context):有lRoot对象和表达式,我们就可以使用OGNL进行简单的操作了,如对Root对象的赋值与取值操作。但是,实际上在OGNL的内部,所有的操作都会在一个特定的数据环境中运行。这个数据环境就是上下文环境(Context)。OGNL的上下文环境是一个Map结构,称之为OgnlContext。Root对象也会被添加到上下文环境当中去
Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map接口
Struts 2中的OGNL Context实现者为ActionContex。当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action ,然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
1. 访问值栈中的action的普通属性
首先struts.xml文件如下:配置文件模块化,包含ognl.xml
<?xml version="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>
<constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="true" />
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<include file="com/bjsxt/struts2/ognl/ognl.xml"/>
</struts>
ognl.xml配置如下:把constant常量的配置放在主配置文件struts2.xml文件里,模块的配置文件就不需要在配置常量了
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="xidianlili.struts2.user.action.UserAction">
<result>/ognl.jsp</result>
</action>
</package>
</struts>
找到对应的action类是UserAction类:有两个属性,可以进行值接受参数,当struts2接到请求,先创建actioncontext,valuestack,在加载这个action类,再把类中的内容放到valuestack中
package xidianlili.struts2.user.action;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {
private String name;
private String password;
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setName(String name) {
this.name = name;
}
}
ognl.jsp文件如下:
<?xml version="1.0" encoding="GB18030" ?>
<%@ page language="java" contentType="text/html; charset=GB18030"
pageEncoding="GB18030"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GB18030" />
<title>OGNL表达式语言学习</title>
</head>
<body>
<ol>
<li>访问值栈中的action的普通属性: name = <s:property value="name"/> </li>
<li>访问值栈中的action的普通属性: password = <s:property value="password"/> </li>
</ol>
<s:debug></s:debug>
</body>
</html>
访问的url是http://localhost:8088/myStrutsDemo03/user/user?name=lili&password=666666
这里都是搭配struts2的property标签,用来输出指定的值
结果:可以看到值栈中的内容是action类中的内容,根据 <s:property value="name"/>可以获得。其中vlaue的值就是ognl的表达式,value属性被定义成object对象,所以struts不会把"name"解析成字符串。
2.访问值栈中对象的普通属性
在action类UserAction中添加属性User,以及其set get方法
User类的代码如下:有属性age以及空构造器
package com.bjsxt.struts2.ognl;
public class User {
private int age = 8;
public User() {
}
public User(int age) {
super();
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "user" + age;
}
}
ognl.jsp文件如下:
<li>访问值栈中对象的普通属性(get set方法):<s:property value="user.age"/> </li>
这里的ognl表达式是user.age,我们想通过ognl表达式来访问user.age的值,这里区别于domin model接受参数,下面会讲到。那么访问结果是什么样的
可以看到这个时候值栈的user是空的,我们并没有访问到age ,按理说我们可以访问到值栈中的password和name就应该可以访问user,但是这里并没有根据ognl的表达式给我们构造user对象,让我们用
回顾domin model接受参数,我们也并没有对user进行初始化构造,但是我们通过在url后面传入参数就可以接受,所以这里的原因就是我们没有给user对象传递参数。
修改url,后面传入user.age=18,可以看到我们访问到对象,所以我们可以得到ognl的结论 :
- 我们使用如user.age这样的ognl表达式,必须通过向domin model那样先传入参数,才会构造user对象,调用其age的set get等方法让我们访问到值,这个时候要注意,在user里面一定要有参数为空的构造方法,否则user也为空
- 要是不在url后面传递参数,也可以选择在Action类中自己new User对象
- 这样结果就是:访问到user中age的默认值,当然也可以在user里添加有参数的构造器来指定age
3.访问值栈中对象的普通属性(为什么叫OGNL)
我们在action类中在添加一个属性,并添加set get方法
这个时候我们看cat类是这样定义的:它里面有一个属性是Dog类型的,以及一个普通方法
package xidianlili.struts2.user.action;
public class Cat {
private Dog friend;
public Dog getFriend() {
return friend;
}
public void setFriend(Dog friend) {
this.friend = friend;
}
public String miaomiao() {
return "miaomiao";
}
}
那我们在看Dog类的定义:有name属性,set get方法 构造器
package xidianlili.struts2.user.action;
public class Dog {
private String name;
public Dog() {
}
public Dog(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "dog: " + name;
}
}
这个时候ognl.xml中的连接:
<li>访问值栈中对象的普通属性(get set方法): <s:property value="cat.friend.name"/></li>
ognl的表达式是cat.friend.name,我们根据结构UserAction对象包含Cat,Cat包含Dog,所以这个ognl全称是Object graph Navigation Language对象导航图语言就是说明了对象之间的关系,通过表达式中的"."可以看出来
我们看一下UserAction中值栈的内容,增加了Cat的内容但是为空,根据上面的内容我们没有传递所以是空的
进行参数传递:可以访问对象到dog的name,这里进行值传递的时候,我们是从cat开始的,cat在值栈中有标签,然后根据ognl表达式一直找到name进行赋值
4.访问值栈中对象的普通方法
上面两个内容都是通过ognl表达式访问值栈对象的属性,比如name,password,我们也可以通过ognl表达式访问这样对象的普通方法。访问password是String类,有length(),方法,以及Cat类中我们自定义一个miaomiao()方法,我们就通过ognl表达式访问这些方法的返回值
- <li>访问值栈中对象的普通方法:<s:property value="password.length()"/></li>
<li>访问值栈中对象的普通方法:<s:property value="cat.miaomiao()" /></li>
结果:注意的是这里也要给cat传递参数要不然没有cat对象
或者就在在Action类中自己构建Cat对象
就可以直接进行访问:
5.访问Action中对象的普通方法
在UserAction中定义一个普通方法
我们就可以通过ognl表达式来访问,直接给出方法返回的字符串,这个时候值栈中的内容并没有增加
<li>访问值栈中action的普通方法:<s:property value="m()" /></li>
6.访问静态方法 静态属性以及Math中的静态方法
-
普通类中的静态属性和方法
- 不需要在Action类中添加有静态属性和方法的类的对象作为属性
首先定义一个类,包含静态属性,静态方法如下:
package xidianlili.struts2.user.action;
public class S {
public static String STR = "STATIC STRING";
public static String s() {
return "static method";
}
}
然后用ognl表达式访问:第一个@后面加类名第二个@后面加要访问的静态属性和静态方法
<li>访问静态方法:<s:property value="@xidianlili.struts2.user.action.S@s()"/></li>
<li>访问静态属性:<s:property value="@xidianlili.struts2.user.action.S@STR"/></li>
但是结果我们并没有访问到静态方法
问题:找到源文件的常量说明发现静态加载默认是false
解决:在struts.xml文件中添加就可以成功访问
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
-
Math类中的静态方法
固定用法,只有math可以使用的ognl表达式的格式:就是两个@@后加Math类的静态方法
<li>访问Math类的静态方法:<s:property value="@@max(2,3)" /></li>
7.OGNL表达式投影(过滤)就是根据List来访问元素
首先在Action类中定义一个List叫users,元素的属性是User类,里面有一个属性age,有带参数的构造方法
我们在UserAction的构造方法里初始化users,增加元素
OGNL表达式为:
<li>投影(过滤):<s:property value="users.{?#this.age==1}[0]"/></li>
<li>投影:<s:property value="users.{^#this.age>1}.{age}"/></li>
<li>投影:<s:property value="users.{$#this.age>1}.{age}"/></li>
<li>投影:<s:property value="users.{$#this.age>1}.{age} == null"/></li>
1. 是正则表达式的知识,把users中的对象挨个拿过来匹配,直到对象的age==1取出这样的集合,[0]的第一个返回
#this.age>1 是意思是把users里面的对象age大于1的拿出来,我们这里是uesr2和user3满足 。
^是取出开始元素 $是取出末尾元素 ==null 是判断满足条件的集合是否为空
<li>投影(过滤):<s:property value="users.{?#this.age==1}[0].{age}"/></li>
<li>投影:<s:property value="users.{?#this.age>1}"/></li>
8.OGNL表达式访问list set map元素
<li>访问List:<s:property value="users"/></li>
<li>访问List中某个元素:<s:property value="users[1]"/></li>
<li>访问List中元素某个属性的集合:<s:property value="users.{age}"/></li>
<li>访问List中元素某个属性的集合中的特定值:<s:property value="users.{age}[0]"/> |
<s:property value="users[0].age"/></li>
<li>访问Set:<s:property value="dogs"/></li>
<li>访问Set中某个元素:<s:property value="dogs[1]"/></li>
<li>访问Map:<s:property value="dogMap"/></li>
<li>访问Map中某个元素:<s:property value="dogMap.dog101"/> | <s:property value="dogMap['dog101']"/> | <s:property value="dogMap[\"dog101\"]"/></li>
<li>访问Map中所有的key:<s:property value="dogMap.keys"/></li>
<li>访问Map中所有的value:<s:property value="dogMap.values"/></li>
<li>访问容器的大小:<s:property value="dogMap.size()"/> | <s:property value="users.size"/> </li>
9.[]访问action对象
<li>[]:<s:property value="[0].name"/></li>
<li>[]:<s:property value="[0]"/></li> [0]返回的值栈中所有的action对象
比如我们利用服务器端跳转action,
<struts>
<package name="user" namespace="/user" extends="struts-default">
<action name="user" class="xidianlili.struts2.user.action.UserAction">
<result>/ognl.jsp</result>
</action>
<action name="test" class="xidianlili.struts2.user.action.TestAction">
<result type="chain">user</result>
</action>
</package>
</struts>
访问http://localhost:8088/myStrutsDemo03/user/test,结果还是到ognl.jsp,利用[]访问action对象,将用到的action对象依次压入值栈中。