现在的位置: 首页 > 综合 > 正文

OGNL表达式和Struts2标签

2018年06月05日 ⁄ 综合 ⁄ 共 6329字 ⁄ 字号 评论关闭

OGNL的全称是Object Graph Navigation Language(对象图形导航语言),它是一种强大的表达式语言,开发者可以通过简单一致的表达式语法来读取和设置java对象的属性值,调用对象的方法,遍历整个对象的结构。

操作对象!

OGNL有一个上下文(Context)概念,通俗的说就是一个Map结构,它实现了java.util.Map接口,在struts2中上下文(Context)的实现为ActionContext。即Struts2中OGNL Context实现者为ActionContext,它的结构示意图如下:

当Struts2接受一个请求时,会迅速创建ActionContext,然后创建ValueStack,再创建action。接着把action存放到ValueStack中,所以action中的实例变量可以被OGNL表达式直接访问。

OGNL表达式访问各个命名空间的属性:

1.访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#Session...

2.另外OGNL会设定一个根对象(root对象),在struts2中根对象就是ValueStack(值栈)。如果要访问根对象(即值栈ValueStack)中对象的属性,则可以省略#命名空间,直接访问该对象的属性即可。

3.在struts2中,根对象ValueStack的实现类为OgnlValueStack,该对象不是存放单个值,而是存放一组对象。在OgnlValueStack类里面有一个List类型的root变量,就是使用它来存放一组对象,如图:

4.在root变量中处于第一位的对象叫做栈顶对象。通常我们在OGNL表达式里直接写上熟悉你的名称即可访问root变量里对象的属性,搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象开始寻找,依次往下访问,知道找到为止。

如:要访问存在栈顶中的一个name属性,我们不需要用到#命名空间的方式,可以直接使用对象属性名称的方式访问,即写个name即可,但是这样写又是无效的,在struts2中,OGNL表达式需要配合struts2标签才可以使用,应该写成这样:<s:property value="name">,这个name就是OGNL表达式。

5.访问值栈ValueStack中的对象,除了直接写属性名称以外,还可以使用EL表达式直接访问,如上面的name,可以这样访问:${name}。

注:EL表达式只限于访问值栈ValueStack中的对象的属性,如果要访问其他域的属性还得使用#命名空间的方式。

Application对象:用于访问ServletContext,例如:#application.userName或者#application['userName'](注【】的形式在一些特殊字符的时候使用,如#applicaiton['u-name']),这样相当于调用了ServletContext的getAttribute("username");

session对象:用来访问HttpSession,例如:#sesion.userName或者#session['userName'],相当于调用session.getAttribute("userName");

request对象:用来访问HttpServletRequest属性,例如:#request.userName或者#request['userName'],相当于调用request.getAttribute("userName");

parameters对象:用来访问Http的请求参数,例如:#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("userName");

attr对象:用于按page->request->session->application顺序访问属性。

在JSP中使用strus2的标签,必须要引入标签声明:

<%@taglib prefix="s" uri="/struts-tags" %>

1.set标签:用于将某个值放入指定的范围。

参数:

注:如果没有设置scope范围,那么默认为OGNL Context(访问时不需要命名空间,使用#即可)。

测试代码:

<body>
   		<s:set name="age" value="22"></s:set>
  </body>

注:上述代码没有指定范围,即将age放入OGNL Context中,访问时使用#age即可。

2.property标签:用于输出指定的值:

value属性:可选,指定需要输出的属性值,如果没有该属性,则默认输出ValueStack栈顶的值(这个非常重要,有些时候不写value也可以输出,是因为要访问的属性在栈顶)。

测试代码1(访问request范围的属性):

<body>
	<%
		request.setAttribute("name", "习近平");
	%> 
	
	<!-- 访问request范围内的属性,要使用#命名空间的形式 -->
	名称:<s:property value="#request.name"/> 		
  </body>

效果:

测试代码2(访问Session范围的属性):

 <body>
	<%
		session.setAttribute("name", "李克强");
	%> 
	
	<!-- 访问session范围内的属性,要使用#命名空间的形式 -->
	名称:<s:property value="#session.name"/> 		
  </body>

效果:

测试代码3(访问值栈中的属性):

/**
 * 在请求访问action的时候,系统会迅速创建ActionContext->valueStack->action
 * 并且把action存放在valueStack中,这就是为什么OGNL表达式可以直接以属性名称的方式访问属性。
 * 因为action存放在了valueStack中。
 * @author Liao
 *
 */
public class UserAction extends ActionSupport {

	private static final long serialVersionUID = 1L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public String execute(){
		
		this.setName("胡锦涛");
		
		return this.SUCCESS;
	}
}

在界面访问:

 <body>
	<!-- 访问valueStack中的属性,不需要使用#命名空间的形式,直接通过属性名的方式即可访问 -->
	名称:<s:property value="name"/> 	<br>
	<!-- 值栈的值也可以直接通过EL表达式来访问 -->
	通过EL表达式获取的名称:${name}	
  </body>

效果:

3.Iterator迭代标签:用于遍历集合(java.util.Collection)或者枚举值(java.util.iterator)。

参数:

注:value为可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。

在演示之前我们先看另外一个知识点:通过OGNL表达式来创建List/Map集合。

测试代码:

<body>
  	<!-- 通过OGNL可以创建List和Map集合value="{'邓小平','胡锦涛','习近平'}"表示一个List集合 -->
  	<s:set  name="list" value="{'邓小平','胡锦涛','习近平'}"/>
  	
  	<!-- 上述集合没有指定范围就表示OGNL Context范围内的变量,使用#即可 ,iterator标签中的value表示要迭代的集合-->
  	<s:iterator value="#list">
  	<!-- 注:Iterator标签在迭代集合时,会把当前迭代的对象放在值栈的栈顶,所以使用property标签输出时可以不用value -->
  		<s:property /><br>
  	</s:iterator>
  </body>

注:一定要记住,iterator标签在迭代集合时会把当前迭代的对象放在值栈的栈顶,这就是为什么使用property输出值时可以不写value属性的原因。

 效果:

使用OGNL创建Map集合:

测试代码【通过OGNL可以创建List和Map集合value="#{'key1':'邓小平','key2':'胡锦涛','key3':'习近平'}"表示一个map集合(注意书写方式)】:

测试代码:

<body>

	<s:set name="maps" value="#{'key1':'邓小平','key2':'胡锦涛','key3':'习近平'}" />

	<!-- 上述集合没有指定范围就表示OGNL Context范围内的变量,使用#即可 ,iterator标签中的value表示要迭代的集合-->
	<s:iterator value="#maps">
		<!-- 注:Iterator标签在迭代集合时,会把当前迭代的对象放在值栈的栈顶,所以使用property标签输出时可以不用value -->
		<s:property value="key" />=<s:property value="value" />
		</br>
	</s:iterator>
</body>

效果:

OGNL表达式的投影功能,常用操作符:

1.?表示获得所有符合逻辑的元素。

2.^表示符合逻辑的第一个元素。

3.$表示符合逻辑的最后一个元素。

测试案例:

User对象:

public class User {

	private Integer uid;
	private String uname;
	private Integer age;

	public User() {
	}

	public User(Integer uid, String uname, Integer age) {
		this.uid = uid;
		this.uname = uname;
		this.age = age;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	public Integer getUid() {
		return uid;
	}

	public void setUid(Integer uid) {
		this.uid = uid;
	}

	public String getUname() {
		return uname;
	}

	public void setUname(String uname) {
		this.uname = uname;
	}

}

UserAction.java:

/**
 * 在请求访问action的时候,系统会迅速创建ActionContext->valueStack->action
 * 并且把action存放在valueStack中,这就是为什么OGNL表达式可以直接以属性名称的方式访问属性。
 * 因为action存放在了valueStack中。
 * 这个类中的users属性可以直接通过属性名称的方式访问
 * @author Liao
 *
 */
public class UserAction extends ActionSupport {

	private static final long serialVersionUID = 1L;

	private List<User> users;
	
	public List<User> getUsers() {
		return users;
	}

	public void setUsers(List<User> users) {
		this.users = users;
	}

	public String execute(){
		
		users = new ArrayList<User>();
		users.add(new User(1, "习近平", 20));
		users.add(new User(1, "胡锦涛", 30));
		users.add(new User(1, "邓小平", 40));
		
		return this.SUCCESS;
	}
}


前台投影测试:

<body>

	<!-- users是action中的属性,即存放在ValueStack中,所以访问users不需要使用#命名空间的形式 -->
	<s:iterator value="users.{?#this.age > 30}">
		<s:property value="uname" />:<s:property value="age" />
		</br>
	</s:iterator>
</body>

注:users是action中的属性,当然也是ValueStack中的对象,所以可以用属性名称的方式直接访问。在上述代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}的表达式用于获取符合条件的元素,this指的是为了从大集合users帅选数据到小集合,需要对大集合users进行迭代,this代表当前迭代的元素。

效果:

iterator标签中的status属性用来指定迭代时的IteratorStatus实例,该方法包含如下集合方法:

int getCount(),返回当前迭代了几个元素。
int getIndex(),返回当前迭代元素的索引。
boolean isEven(),返回当前被迭代元素的索引是否是偶数
boolean isOdd(),返回当前被迭代元素的索引是否是奇数
boolean isFirst(),返回当前被迭代元素是否是第一个元素。
boolean isLast(),返回当前被迭代元素是否是最后一个元素。

有了这些方法,我么可以做一些特殊效果:

测试代码:

 <body>
	<s:set name="list" value="{'邓小平','胡锦涛','习近平'}" />
		
	<s:iterator value="#list" status="s">
	<!-- 如果是奇数就为红色,否则为蓝色 -->
	<font color=<s:if test="#s.odd">red</s:if>
				<s:else>blue</s:else>>
	<s:property/>
	</font>
	
	</s:iterator>  		
  </body>

效果:

4.if elseif else 标签:执行基本的条件流转。

参数:

测试代1:

<body>
  
   		<s:set name="age" value="22"></s:set>
   		
   		<!-- 使用ognl接收值 -->
   		<s:if test="#age > 20">
   			您的青春已经让狗给吃了!
   		</s:if>
   		
   		<s:elseif test="#age > 35">
   			七年之痒,勿出轨!
   		</s:elseif>
   			
   		<s:else>
   			青春年华,无限风光!
   		</s:else>
   		
  </body>

效果:

OGNL表达式可以使用in和not in两个元素符号,in表达式用来判断某个元素是否在指定的集合对象中,not in判断某个元素是否不在某个集合对象中。

测试代码2:

 <body>
   		<!-- OGNL表达式in的测试 -->
   		<s:if test="'liao' in {'liao','zhong','min'}">
   			您中大奖啦!
   		</s:if>
   		<s:else>
   			您被坑啦!
   		</s:else>
   		
   		<!-- OGNL表达式not in的测试 -->
   		<s:if test="'liao' not in {'lavimer','hello'}">
   			你不在啊!
   		</s:if>
   		<s:else>
   			你在啊!
   		</s:else>
  </body>

注:<s:select>下拉框、<s:checkboxlist>复选框、<s:radio>单选框在Web开发中经常使用,将在后面的文章中以专题的形式详细讨论。

抱歉!评论已关闭.