Struts2.2 OGNL

OGNL ,作为Struts2 一大亮点,感觉也是Struts2 中相对最难理解的一部分了。所以这里认真的总结学习一下。

值栈分析:

MVC 请求处理流程中,牵涉的数据种类比较多,框架使用ValueStack 数据结构对这些数据结构进行有机的整合,便于统一管理。充分认识ValueStack 数据结构可以便于框架使用者轻松自如获取所需的数据。

ValueStack ValueStack ContentsStack Context 两部分构成

    每个请求都会生成一个对应的Action 实例,每一个动作在执行相应方法( 默认execute 方法) 之前,都会创建一个ValueStack 的对象。ValueStack 用来保存这个动作对象和其他对象( 请求处理所涉及的数据);

    ValueStack 对象相当于一个栈,它贯穿整个Action 的生命周期,每个Action 类的对象实例都会拥有一个ValueStack 对象。

    Struts2 接受到一个*.action 请求后,并不是直接调用Action 方法,而是先将Action 类的相应属性放到ValueStack 对象的顶层节点

    值栈也是位于内存中,它也是和parametersrequestsessionapplicationattr 对象放在一起的。值栈属于ONGLContext 里面的根对象。也就是说它位于整个内存中最最重要的地方,所以叫根对象

根对象和另外五个对象是有区别的,根对象可以省写# 号,比如<s:property value="user.username"/> 。值栈的生命周期与request 请求相关,每次请求产生一个值栈。默认所有的Action 会被自动放到值栈里

生命周期内置对象被封装在一个Map 结构中。

在跳转的页面上加一个struts 标签-<s:debug/> 可以看到ValueStack 结构。

 

务器跳转时共用值栈:

假设从一个Action1 通过服务器跳转到Action2 的话,就意味着这两个Action 是共享一个值栈的,因为一次请求只使用一个值栈。这时内存中情况是这样的:首先接收到Action1 请求后,会产生一个值栈,在栈顶存放Action1 对象以及它所有的属性,然后经过服务器跳转到Action2 ,这时就会把Action2 对象压入值栈的栈顶位置,此时Action1 对象以及它的所有属性就位于栈底了。

 

取值过程(原则:后进先出):

栈的特征是后进先出。所以首先到栈顶的对象里查找是否存在这个属性,如果栈顶的Action2 对象中不存在这个属性的话,它就会继续向下寻找直至栈底对象,一直查找是否存在这个属性,如果最后找到该属性的话,那么就会在JSP 页面中通过<s:property value="username"/> 输出属性值。如果在Action2Action1 都有一个同名的同类型的username 属性的话,那么将输出Action2 中的属性值。因为它是先从栈顶开始寻找属性的,值栈的特征就是后进先出 ,但有个前提:请求过程是通过服务器跳转的。

 

三个语法:

假设此时想要获取Action11 中的username 属性的话,就可以使用值栈的Top 语法 或者N 语法
1
、使用Top 语法 获取值栈中的第二个对象的属性:

<s:property value="[1].top.username"/>
2
、使用N 语法 获取值栈中的第二个对象的属性:<s:property value="[1].username"/>
3
@ 语法 ,例如使用@ 语法调用Action 中的静态方法:<s:property value="@vs@getVOMethod()"/>
@vs@get()
等价于@vs1@getVOMethod() ,指的是栈顶对象的静态getVOMethod() 方法
同理@vs2@getVOMethod() 就是取值栈中第二个对象的静态getVOMethod() 方法

 

客户端跳转时使用各自的值栈:

假如中间某一个步骤中出现了客户端跳转的话,那么两个Action 所使用的就是两个不同的值栈了。所以在Action2 中就不能再使用Action1 中的属性了,在最后跳转到的JSP 页面中也就无法获取Action1 的属性了。即从Action2 跳转到JSP 页面时使用的是redirect 的话,那么最后值栈中是没有任何的Action 对象的。这个时候我们可以通过链接传参,比如<result type="redirect">test.jsp?netname=${username}</result>
意思就是取出Action2 中的username 属性作为参数,通过浏览器地址栏传递到JSP 页面中
然后使用OGNL 中的# 获取Paraments 对象的属性,即<s:property value="#parameters.netname"/> 就可以取到值了。

 

手工向值栈中压入对象:

常情况下值栈保存的是Action 对象,而我们也可以直接往值栈中添加其它对象,这时可以在Action 中添加如下代码向值栈中添加对象:

ActionContext.getContext.getValueStack().push(new Student("xdwang",23));
而且我们手工往值栈中添加的Student 对象会位于栈顶 。这是因为Struts2 会首先初始化Action ,然后才能调用它的方法。初始化Action 的时候,便把Action 放到值栈中了,然后在执行它的execute() 方法时,就又往值栈中添加了Student 对象。

 

OGNL 历史:

    OGNL 最初是为了能够使用对象的属性名来建立 UI 组件 (component) 和 控制器 (controllers) 之间的联系,简单来说就是:视图与控制器之间数据的联系 。后来为了应付更加复杂的数据关系。

 

什么是OGNL

OGNL Object-Graph Navigation Language 的缩写, 对象图形导航语言 , ,从语言角度来说:它是一种 操作复杂数据结构的常用语言 ,它旨在提供一个更高抽象度语法来对 java 对象图进行导航。

可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性;

    对象通过OgnlContext上下文对象来管理。

    OGNL可以让我们用非常简单的表达式访问对象层。

 

OGNL 应用:

1 、作为 GUI 元素(textfield,combobox, 等)到模型对象的绑定语言;

2 、数据库表到 Swing TableModel 的数据源语言;

3 web 组件和后台 Model 对象的绑定语言 (WebOGNL,Tapestry,WebWork,WebObjects)

4 、作为 Jakarata Commons BeanUtils 或者 JSTL 的表达式语言的一个更具表达力的替代语言;

 

为什么需要表达式语言 (EL)

表达式语言(EL)本质上被设计为:帮助你使用简单的表达式来完成一些“常用”的工作。通常情况下,ELs 可以在一些框架中找到,它被是用来简化我们的工作。例如:大家熟知的 Hibernate,使用 HQL(Hibernate Query Language) 来完成数据库的操作,HQL 成了开发人员与复查的 SQL 表达式之间的一个桥梁。 在 web 框架下,表达式语言起到了相似的目的。它的存在消除了重复代码的书写。例如:当没有 EL 的时候,为了从 session 中得到购物车并且将 ID 在网页上呈现出来,当直接在 jsp 中使用 java 代码来完成的时候,一般是:

<% 
    ShoppingCart cart = (ShoppingCart) session.get("cart"); 
    int id = cart.getId(); 
    %> 
    <%= id%>

你也可以将这些 code 压缩成一句,如下,但是现在代码就很不直观,且不可读。另外,虽然变成了一句,但是与上面的原始的例子一样,也包含了同样的表达式。例如:类型转换:转换 成 ShoppingCart 。这里只不过是将原来的三个表达式变成了一句,其复杂度是没有得到简化的。

<%= ((ShoppingCart) session.get("cart")).getId() %>

当在 web 框架中使用表达式语言的时候,则可以有效的处理这种代码的复杂性。而不需要你,调用 servelet API,类型转换,然后再调用 getter 方法,多数的 Els 都可将这个过程简化为类似于:#session.cart.id 这中更可读的表达式。 表达式:#session.cart.id 与 java 代码不一样的是:没有 java 代码的 get 方法调用和类型转换。因为这些操作是非常“常用”的,这时候使用 EL 就顺理成章了,使用 EL 可以“消除”这些代码。

 

OGNL标识符:

    “$”有两个主要的用途:

1、 用于在国际化资源文件中,引用OGNL表达式:

validation.require=${getText(fileName)} is required

2、 在Struts 2配置文件中,引用OGNL表达式:

<action name="AddPhoto" class="addPhoto">
     <result type="redirect">
        ListPhotos.action?albumId=${albumId}
     </result>
</action>

# ”, 一般用于取出堆栈上下文中存放的对象和过滤、投影集合。这里我们可以将 # 理解为 ActionContext.getContext()

1 、取出堆栈上下文:

名称

作用

Demo

attr

用于按 request>>session>>application 顺序访问其属性

#attr.userName 相当于按顺序从三个范围读取 userName 属性直到找到为止

request

包含当前 HttpServletRequest 的属性的 Map

#request.userName 相当于 request.getAttribute("userName")

session

包含当前 HttpSession 的属性的 Map

#session.userName 相当于 session.getAttribute("userName")

application

包含当前应用的 ServletContext 的属性的 Map

#application.userName 相当于 application.getAttribute("userName")

parameters

包含当前 HTTP 请求参数的 Map

#parameters.id[0] 相当于 request.getParameter("id")

2、 用于过滤和投影(projecting)集合

person.{?#this.age>20}

? -- 获取集合中所有满足选择逻辑的对象(sql 来做比例就是"select * from xxx where age>20")

^ -- 获取集合中第一个满足选择逻辑的对象(sql 来做比例就是"select top(1) from xxx where age>20")

$ -- 获取集合中最后一个满足选择逻辑的对象

 

    %:用途是在标识的属性为字符串类型时,计算OGNL表达式的值,即将原本的文本属性解析为ognl,对于本来就是ognl的属性不起作用

<s:url value="test.jsp?age=#userlist['admin']">→test.jsp?#userlist['admin']---可见当字符串与OGNL表达式串起来时,只会被当作字符串对待,并不执行
<s:url value="test.jsp?age=%{#userlist['admin']}">→test.jsp?age=44---使用了该符号,就可以使得OGNL表达式被执行
 
<s:set name="hello" value="5"></s:set>
<s:property value="#hello" /> 
<s:property value="%{#hello}" /> 
<s:if test="%{#hello==5}">你好</s:if>
<s:if test="#hello==5">你好</s:if>

<s:set name="china" value="'你好'"></s:set>
<s:property value="#china" /> 
<s:property value="%{#china}" /> 
<s:if test="%{#china=='你好'}">你好1</s:if>
<s:if test="#china=='你好'">你好2</s:if>

注意上面的你好需要加引号,否则没有值;

 

获取Action 中的属性值或Action 对象的某某属性值

利用 Struts2 标签的 <s:property> 可以直接获取 Action 中的引用类型 user 里面的 name 属性。同样可以通过 user.address.addr 获取 user 中引用类型 address 中的 addr 属性的值
像这种一层一层往下传递的访问方式 即所谓的导航 也就是一步步的往下调用

 

调用Action 的对象里面的普通方法:

默认的会把 Action 放到值栈里面 而值栈在访问的时候 并不需要值栈的名字
当我们调用 <s:property value="user.getVOMethod()"/> 的时候。它会自动到值栈里面查找Action对象里面有没有user对象,然后它就发现有user。然后它就再找user里面有没有getVOMethod()方法,然后它发现有,于是调用getVOMethod()。实际上调用User中的getVOMethod()方法的过程与获取表单中的姓名密码的方式都是相同的, 都是到值栈里面查找 ,找是否存在user对象,如果存在,接着查找user中是否存在某某属性或方法。

 

调用Action 中的静态方法:

    同样我们也可以在 JSP 页面中写一个 OGNL 表达式调用 Action 中的静态方法 调用 Action 中的静态方法时 与调用 user 对象的 getVOMethod() 方法的过程 是截然不同的。此时 value 的写法是固定的 @ 开头 后面跟上具体的包名 然后 @ 加上静态方法 比如 <s:property value="@com.jadyer.action.LoginAction@getStatic()"/> 另外 user 对象是 LoginAction 中的一个属性 这个属性会自动的放到值栈里面, 而值栈调用的时候 不用加上 @ 或者包名等等 所以直接 user.getVOMethod() 就可以了。

 

调用JDK 类中的静态方法:

    以使用 <s:property value="@@floor(46.58)"/> 输出 floor() 的执行结果。这就意味着 如果不在@@中指定类 的话, 默认的就表示java.lang.Math类 当前大多数情况下,我们都不会省略这个类,都会写全了的,然后在后面加上静态方法。

 

集合的伪属性:

OGNL 能够引用集合的一些特殊的属性 这些属性并不是 JavaBean 模式 例如 size() length() 当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性
比如获取List的大小:
<s:property value="testList.size"/>
List的伪属性: size、isEmpty、iterator
Set的伪属性: size、isEmpty、iterator
Map的伪属性: size、isEmpty、keys、values
Iterator的伪属性: next、hasNext
Enumeration伪属性: next、hasNext、nextElement、hasMoreElements

 

说明:

1 、获取集合中元素的实质就是调用它的toString() 方法;

       2 、当OGNL 取不到值的时候,它是不会报错的,而是什么都不显示出来;

       3 <s:property value="[0]"/> 返回的是ValueStack 中从上至下的所有的Object<s:property value="[1]"/> 返回的是ValueStack 中从上至下的第二个Object

       4 <s:property value="[0].username"/> 返回的是成员变量username 的值。假设ValueStack 中存在两个Action 的话,如果第一个Action 如果没有username 变量,那么它会继续找第二个Action 。那么在什么情况下ValueStack 中会存在两个Action 呢?答案是在struts.xml 中配置的是从一个Action 通过<result type="chain"> 跳转到另一个Action

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

Struts2.1.6 、Struts2.2 中必须设置struts.ognl.allowStaticMethodAccesstrue 之后才允许使用OGNL 访问静态方法。而在Struts2.0.11 则无需设置,即可直接访问;

通过下面的Demo发现2.2版本中如果不在Struts.xml中配置< constant name = "struts.ognl.allowStaticMethodAccess" value = "true" /> 会出现普通类中的静态属性和方法可以访问,而Action中的静态属性和方法以及jdk中的静态属性方法都无法访问。

 

Demo

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>OGNLDemo</display-name>
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<welcome-file-list>
		<welcome-file>login.jsp</welcome-file>
	</welcome-file-list>
</web-app>

struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
    "http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
	<constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
	<package name="ognl" extends="struts-default">
		<action name="login" class="com.iflytek.action.LoginAction">
			<result name="input">/login.jsp</result>
			<result name="success">/loginSuc.jsp?netname=xdwang</result>
			<!-- <result name="success" type="redirect">/loginSuc.jsp?netname=xdwang</result> 
				<result name="success" type="redirect">/loginSuc.jsp?netname=${user.username}</result> -->
		</action>
	</package>
</struts>  

 

 

Address.java:

package com.iflytek.entity;

/**
 * @author xdwang
 * 
 * @ceate 2012-6-27 上午12:29:38
 * 
 * @description Address实体
 * 
 */
public class Address {
	public static final String TIPS = "xdwang";

	private String addr;

	public String getAddr() {
		return addr;
	}

	public void setAddr(String addr) {
		this.addr = addr;
	}
}

Student.java:

package com.iflytek.entity;

/**
 * @author xdwang
 * 
 * @ceate 2012-6-27 上午12:31:07
 * 
 * @description Student实体
 * 
 */
public class Student {

	private String username;
	private int grade;

	public Student() {
	}

	public Student(String username, int grade) {
		this.username = username;
		this.grade = grade;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public int getGrade() {
		return grade;
	}

	public void setGrade(int grade) {
		this.grade = grade;
	}

	@Override
	public String toString() {
		// 如果不重写它的toString()方法的话,默认调用toString()将输出【类型+@+内存地址的哈希值】
		return "{学生姓名:" + username + ",成绩:" + grade + "}";
	}

}

User.java:

package com.iflytek.entity;

/**
 * 
 * @author xdwang
 * 
 * @ceate 2012-6-27 上午12:29:11
 * 
 * @description User实体
 * 
 */
public class User {
	private String username;
	private String password;
	private Address address;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public Address getAddress() {
		return address;
	}

	public void setAddress(Address address) {
		this.address = address;
	}

	public String getVOMethod() {
		return "这是User类中的一个普通方法";
	}
}

 

LoginAction.java:

package com.iflytek.action;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.SessionAware;

import com.iflytek.entity.Student;
import com.iflytek.entity.User;
import com.opensymphony.xwork2.ActionSupport;

/**
 * @author xdwang
 * 
 * @ceate 2012-6-27 上午12:33:18
 * 
 * @description 登陆Action
 * 
 */
@SuppressWarnings("serial")
public class LoginAction extends ActionSupport implements RequestAware,
		SessionAware {
	private User user;
	private List<String> testList = new ArrayList<String>();
	private Set<String> testSet = new HashSet<String>();
	private Map<String, String> testMap = new HashMap<String, String>();
	private List<Student> stus = new ArrayList<Student>();

	private Map<String, String> request;
	private Map<String, String> session;

	public void setRequest(Map request) {
		this.request = request;
	}

	public void setSession(Map session) {
		this.session = session;
	}

	public static String getStatic() {
		return "这是LoginAction中的一个静态方法";
	}

	public String getCommon() {
		return "这是LoginAction中的一个普通方法";
	}

	@Override
	public String execute() throws Exception {
		if (user.getUsername().trim().equalsIgnoreCase("xdwang")
				&& user.getPassword().equals("1111")) {
			testList.add("list11");
			testList.add("list22");
			testList.add("list33");
			testList.add("list44");
			testList.add("list55");

			testSet.add("set11");
			testSet.add("set22");
			testSet.add("set33");
			testSet.add("set22");
			testSet.add("set11");

			testMap.put("m11", "map11");
			testMap.put("m22", "map22");
			testMap.put("m33", "map33");
			testMap.put("m44", "map44");
			testMap.put("m55", "map55");

			stus.add(new Student("张三", 88));
			stus.add(new Student("李四", 77));
			stus.add(new Student("王五", 66));
			stus.add(new Student("马六", 55));

			request.put("req", "这是通过OGNL中的#号获取的request属性范围的值");
			session.put("ses", "这是通过OGNL中的#号获取的session属性范围的值");
			request.put("BB", "这是通过OGNL中的#号获取的request属性范围的BB");
			session.put("BB", "这是通过OGNL中的#号获取的session属性范围的BB");
			return SUCCESS;
		} else {
			return INPUT;
		}
	}

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public List<String> getTestList() {
		return testList;
	}

	public void setTestList(List<String> testList) {
		this.testList = testList;
	}

	public Set<String> getTestSet() {
		return testSet;
	}

	public void setTestSet(Set<String> testSet) {
		this.testSet = testSet;
	}

	public Map<String, String> getTestMap() {
		return testMap;
	}

	public void setTestMap(Map<String, String> testMap) {
		this.testMap = testMap;
	}

	public List<Student> getStus() {
		return stus;
	}

	public void setStus(List<Student> stus) {
		this.stus = stus;
	}

}

login.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<title>OGNL Demo</title>
</head>
<body>
	<h1>这是测试OGNL使用的登录页面</h1>
	<h3>
		<font color="red">提示:</font>程序设定的用户名和密码各为<font color="blue"><strong>xdwang</strong></font>和<font
			color="blue"><strong>1111</strong></font>
	</h3>
	<h3>
		<font color="red">注意:</font>用户名和密码不正确时将停留在页面不动
	</h3>
	<form action="<%=request.getContextPath()%>/login.action" method="POST">
		<%--这里user.username匹配的是LoginAction中的引用类型user里面的username属性--%>
		<%--查看标签库说明的话,就知道name中指定的是对象。这里它不是字符串,而是OGNL表达式--%>
		姓名:<input type="text" name="user.username"><br> 密码:<input
			type="text" name="user.password"><br> 地址:<input
			type="text" name="user.address.addr"><br> <input
			type="submit" value="测试OGNL的输出">
	</form>
</body>
</html>

loginSuc.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<title>OGNL Demo</title>
</head>
<body>
	<h1>这是使用OGNL输出的结果页面</h1>
	<table border="9">
		<tr>
			<td align="right">获取姓名属性:</td>
			<td align="left"><s:property value="user.username" /></td>
			<%-- 另外还有两种写法也是可以正常输出值栈中对象的普通属性的 --%>
			<%-- <s:property value="user['username']"/> --%>
			<%-- <s:property value="user[/"username/"]"/> --%>
			<%-- 但是如果写成下面这种形式的话,就什么都不会输出了 --%>
			<%-- <s:property value="user[username]"/> --%>
		</tr>
		<tr>
			<td align="right">获取地址属性:</td>
			<td align="left"><s:property value="user.address.addr" /></td>
		</tr>
		<tr>
			<td align="right">调用值栈中的对象的普通方法:</td>
			<td align="left"><s:property value="user.getVOMethod()" /></td>
		</tr>
		<tr>
			<td align="right">调用值栈中Action的普通方法:</td>
			<td align="left"><s:property value="getCommon()" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">获取普通类的静态属性:</td>
			<td align="left"><s:property value="@com.iflytek.entity.Address@TIPS" /></td>
		</tr>
		<tr>
			<td align="right">访问普通类的构造方法:</td>
			<td align="left"><s:property
					value="new com.iflytek.entity.Student('xdwang',23).username" /></td>
		</tr>
		<tr>
			<td align="right">调用Action中的静态方法:</td>
			<td align="left"><s:property value="@com.iflytek.action.LoginAction@getStatic()" /></td>
		</tr>
		<tr>
			<td align="right">调用JDK中的类的静态方法:</td>
			<td align="left"><s:property
					value="@java.util.Calendar@getInstance().time" /></td>
		</tr>
		<tr>
			<td align="right">调用JDK中的类的静态方法:</td>
			<td align="left"><s:property
					value="@java.lang.Math@floor(46.58)" /></td>
		</tr>
		<tr>
			<td align="right">调用JDK中的类的静态方法:</td>
			<td align="left"><s:property value="@@floor(46.58)" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">获取List中的所有元素:</td>
			<td align="left"><s:property value="testList" /></td>
		</tr>
		<tr>
			<td align="right">获取Set中的所有元素:</td>
			<td align="left"><s:property value="testSet" /></td>
		</tr>
		<tr>
			<td align="right">获取Map中的所有元素:</td>
			<td align="left"><s:property value="testMap" /></td>
		</tr>
		<tr>
			<td align="right">获取Map中的某个m22元素:</td>
			<td align="left"><s:property value="testMap['m22']" /></td>
			<%-- 另外还有两种写法也是可以正常获取Map中的某个具体元素的 --%>
			<%-- <s:property value="testMap.m22"/> --%>
			<%-- <s:property value="testMap[/"m22/"]"/> --%>
		</tr>
		<tr>
			<td align="right">获取Set中的某个元素:</td>
			<%-- 由于Set中的元素是无顺序的,所以不能使用下标获取数据,所以这里什么也得不到 --%>
			<td align="left"><s:property value="testSet[2]" /></td>
		</tr>
		<tr>
			<td align="right">获取List中的某个元素:</td>
			<td align="left"><s:property value="testList[2]" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">获取List的大小:</td>
			<td align="left"><s:property value="testList.size" /></td>
		</tr>
		<tr>
			<td align="right">获取Set的大小:</td>
			<td align="left"><s:property value="testSet.size" /></td>
		</tr>
		<tr>
			<td align="right">获取Map的大小:</td>
			<td align="left"><s:property value="testMap.size" /></td>
		</tr>
		<tr>
			<td align="right">获取Map中所有的键:</td>
			<td align="left"><s:property value="testMap.keys" /></td>
		</tr>
		<tr>
			<td align="right">获取Map中所有的值:</td>
			<td align="left"><s:property value="testMap.values" /></td>
		</tr>
		<tr>
			<td align="right">Lambda计算4的阶乘:</td>
			<td align="left"><s:property
					value="#f= :[#this==1?1 : #this*#f(#this-1)],#f(4)" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">获取List中的所有对象:</td>
			<td align="left"><s:property value="stus" /></td>
		</tr>
		<tr>
			<td align="right">利用投影获取List中对象的名字:</td>
			<td align="left"><s:property value="stus.{username}" /></td>
		</tr>
		<tr>
			<td align="right">利用投影获取List中第二个对象的名字:</td>
			<%-- 使用<s:property value="stus[1].{username}"/>获取到的值为:[李四] --%>
			<%-- 二者的区别在于:后者比前者多了一个中括号 --%>
			<td align="left"><s:property value="stus.{username}[1]" /> <s:property
					value="stus[1].{username}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的所有对象:</td>
			<td align="left"><s:property value="stus.{?#this.grade>=60}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的第一个对象:</td>
			<td align="left"><s:property value="stus.{^#this.grade>=60}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的最后一个对象:</td>
			<td align="left"><s:property value="stus.{$#this.grade>=60}" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">利用选择获取List中成绩及格的所有对象的名字:</td>
			<td align="left"><s:property
					value="stus.{?#this.grade>=60}.{username}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的第二个对象的名字:</td>
			<td align="left"><s:property
					value="stus.{?#this.grade>=60}.{username}[1]" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的第一个对象的名字:</td>
			<td align="left"><s:property
					value="stus.{^#this.grade>=60}.{username}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的最后一个对象的名字:</td>
			<td align="left"><s:property
					value="stus.{$#this.grade>=60}.{username}" /></td>
		</tr>
		<tr>
			<td align="right">利用选择获取List中成绩及格的第一个对象然后求大小:</td>
			<td align="left"><s:property
					value="stus.{^#this.grade>=60}.{username}.size" /></td>
		</tr>
	</table>
	<hr />
	<table border="9">
		<tr>
			<td align="right">利用OGNL中的#号获取attr中的属性:</td>
			<td align="left"><s:property value="#attr.BB" /></td>
		</tr>
		<tr>
			<td align="right">利用OGNL中的#号获取request范围中的属性:</td>
			<td align="left"><s:property value="#request.req" /></td>
		</tr>
		<tr>
			<td align="right">利用OGNL中的#号获取session范围中的属性:</td>
			<td align="left"><s:property value="#session.ses" /></td>
		</tr>
		<tr>
			<td align="right">利用OGNL中的#号获取Paraments对象的属性:</td>
			<td align="left"><s:property value="#parameters.netname" /></td>
		</tr>
		<tr>
			<td align="right">使用&#60;&#37;=request.getParameter&#40;""&#41;&#37;&#62;或者&#36;&#123;param.name&#125;获取链接参数值:</td>
			<td align="left">${param.netname} <%=request.getParameter("netname")%>
			</td>
		</tr>
		<tr>
			<td align="right">查看值栈中的信息:</td>
			<td align="left"><s:debug /></td>
		</tr>
	</table>
</body>
</html>
 

猜你喜欢

转载自xdwangiflytek.iteye.com/blog/1568669