最近学习了struts2中OGNL(Object Graph Navigation Language)对象图表导航语言。
1.OGNL是用来干什么的呢?
①把GUI(图形用户界面)元素绑定到模型对象,以及把数据值从一种类型转换到另外一种类型。
②把通用标签与模型对象绑定到一起。
③即使创建List和Map的映射关系与GUI对象配合使用。
④调用对象的方法,而不是仅限于对对象属性的读取和设置的方法。
2.OGNL从哪里获得对象或者说从哪里获得数据呢?
其实我们的struts2中有一个很重要的对象,它是OGNL操作数据对象的来源。他就是我们的Value Stack被称之为值栈。
3.值栈的生命周期
当浏览器没发出一次请求action的时候,struts2都为为每一个action创建一个与之对应的value stack对象,在struts2对Action实例进行属性设置和其他操作之前,value stack就已经被创建并且等待struts2将数据往里面存储。所以简而言之,value stack的生命周期是一次action请求,值栈相当于数据的中转站,在其中保存Action实例和其他对象,当请求结束与之对应的value stack也就被销毁。
4.值栈中包含哪些内容呢?
说了这么多值栈到底包括哪些内容,其实值栈中包含两个逻辑部分,一个是Object Stack另一个是Context Map,如下图所示:
①Object Stack是一个CompoundRoot类型的对象,是一个真正意义的stack,其中存储的是Action实例和与之相关的对象,或者是我们添加到栈中的对象。
②Context Map实际上是对ActionContext对象的引用,是一个OgnlContext类型的对象实际是个map,里面存储的是各种各样的map映射关系。其中尤其和使用比较多的有如下几个:
session:该map包含session域对象中存储的属性
request:该map包含request域对象中存储的属性
parameters:该map包含请求的请求参数
application:该map包含application域对象中存储的属性
attr:该map按照如下顺序检索某个属性---->request,session,application
5.值栈中的属性值
①Object Stack中的都是对象栈中的某个对象的属性
②Context Map中的是request,session,application,parameter中的属性值
6.那么我们如何通过OGNL来访问值栈中的数据,并且在GUI中做显示呢?
①首先我们来说一说通过OGNL来获取Object Stack对象栈中的对象的属性。
1)访问的形式有如下三种:object.propertyName,object['propertyName'],object["propertyName"]
2)Object Stack中的对象可以使用从0~n的下表来引用。例如Object Stack中栈顶的对象就可以通过使用[0]来引用,栈顶下面的元素就可以通过[1]来引用,依次往后推。
3)这里需要注意的一点是例如[n].message它的含义是从第n个对象开始检索message属性值,而不是只检索第n个。如果第n个对象中包含message属性那么就返回该值,如果没有message属性值那么就从n继续往后检索message属性值。
4)如果从栈顶开始检索属性值则可以省略[0]部分例如从栈顶开始检索message属性的值,就可以直接写成message即可。
5)知道了如何获得对象属性值,我们就只需要结合OGNL的<s:property />标签就可以在GUI中来显示这些属性值了。例如<s:property value="[0].message" />或者<s:property value="message" />
6)默认情况下Action实例会被放到Object Stack对象的栈顶。
②接下来就要说一下如何通过OGNL来获得Context Map里面的属性值了。
1)访问的形式和访问Object Stack有唯一的区别就是需要在之前加上#,其访问的形式也有三种#object.propertyName,#object['propertyName'],#object["propertyName"],例如我需要访问session中的code属性#session.code,需要返回request中user属性的name属性#request.user.name,按照request,session,application顺序检索code属性#attr.code。
2)同样结合OGNL的<s:property />标签就可以在GUI中来显示这些属性值了。例如<s:property value="#request.user.message" />或者<s:property value="#attr.user.message" />
7.上面我们大致的知道了如何获得Object Stack和Context Map值栈中对象的属性,那么接下来我们具体讲讲如何调用字段和方法呢?
①可以利用OGNL调用任何一个普通java类的公共静态方法和静态属性和被压入到Object Stack栈中对象的公共方法和属性。
1)如何调用一个普通java类的公共静态方法和公共静态的属性呢?
首先struts2默认是禁止调用公共静态方法的,所以我们需要在struts.xml文件中做如下配置允许调用公共静态方法,配置截图如下:
具体的调用公共静态属性的语法如下:@fullyQulifiedClassName@fieldName例如:@java.lang.Math@PI
具体调用公共静态方法的语法如下:@fullyQulifiedClassName@methodName()例如:@java.lang.Math@cos(0)
2)调用Object Stack中对象的属性和方法则更简单,object是Object Stack中的一个对象,语法如下:
调用对象栈中对象的属性object.filedName例如[0].message,调用对象栈中对象的方法object.methodName(param)例如[0].setAge(age)。
8.如果我们值栈中属性是个数组对象我们该如何访问其属性?
①我们通过下标的形式访问数组对象的属性例如对象为colors={'a','b','c'},可以通过colors[2]获得数组属性c。
②可以通过调用length属性获得数组的长度,例如colors.length。
9.如果我们值栈中属性是个List对象我们该如何访问其属性呢?
①我们通过下标的形式访问List对象的属性例如对象为colors=['a','b','c'],可以通过colors[2]获得List属性c。
②可以通过size()方法和size属性来获得List对象的长度,例如colors.size或者colors.size();
③可以通过isEmpty方法和isEmpty属性来获得List对象是否为空。例如colors.isEmpty()或者colors.isEmpty。
10.如果我们值栈中属性是个Map对象我们该如何访问其属性呢?
①我们通过下标的形式访问List对象的属性例如对象为colors={'age':“13”,“name”:"user"},可以通过colors['age']获得属性age对象的键值‘13’。
②可以通过size()方法和size属性来获得Mapt对象的长度,例如colors.size或者colors.size();
③可以通过isEmpty方法和isEmpty属性来获得Map对象是否为空。例如colors.isEmpty()或者colors.isEmpty。
11.最后一点也是很重要的,我们可以使用原始的EL来访问值栈中属性,例如 <s:property value="#request.message" />可以写程${message},所以EL和OGNL结合使用才会更方便。下面就可大家展示一个java代码实例有助于理解:
index.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">
<title>首页</title>
</head>
<body>
<form action="/Struts2_4_2/user/user-login.action" method="post">
用户名<input type="text" name="name"><br>
爱好<input type="checkbox" name="hobby" value="basketball">篮球<br/>
<input type="checkbox" name="hobby" value="fish">钓鱼<br/>
<input type="submit" value="提交">
</form>
</body>
</html>
struts.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>
<!-- 设置允许使用ognl调用静态方法 -->
<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>
<package name="user" extends="struts-default" namespace="/user">
<action name="user-login" class="com.yd.action.User" method="getObject">
<result name="user">/show.jsp</result>
</action>
</package>
</struts>
Action类User的代码:
package com.yd.action;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String hobby;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "User [name=" + name + ", hobby=" + hobby + "]";
}
public String getObject(){
//System.out.println(this);
//获得值栈
ValueStack valueStack=ActionContext.getContext().getValueStack();
//获得Context Map contextmap其实就是actioncontext的一个引用里面的内容一样
Map<String, Object> contextMap=valueStack.getContext();
contextMap.put("test", "test");
Map<String, Object> request=(Map<String, Object>) contextMap.get("request");
Object user=contextMap.get("action");
//String name=(String) contextMap.get("name");
//System.out.println(contextMap+"上下文Map中的hobby:"+hobby+",name:"+name);
//contextMap.put("name", "My name is dog");
//System.out.println(request.get("name")+"==="+user);
//获得对象栈Object Stack
CompoundRoot root=valueStack.getRoot();
//创建一个stack对象
Stack stack=new Stack();
stack.setLength("99");
stack.setName("My name is list");
stack.setUser((User)user);
root.push(stack);
//在值栈中加入一个数组
List<String> list=new ArrayList<>();
list.add("AA");
list.add("BB");
root.push(list);
String[] strs={"AA","BB","CC","DD"};
root.push(strs);
return "user";
}
}
普通java类Stack用于往Object Stack中存储的对象,java代码如下:
package com.yd.action;
import java.util.ArrayList;
import java.util.List;
import com.sun.corba.se.impl.orbutil.StackImpl;
public class Stack extends ArrayList{
public static String age="ssss";
private String length;
private String name;
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public static String getAge(){
return age;
}
public String getLength() {
return length;
}
public void setLength(String length) {
this.length = length;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
show.jsp页面的代码:
<%@page import="com.yd.action.User"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.List"%>
<%@page import="java.util.ArrayList"%>
<%@ 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">
<title>Insert title here</title>
</head>
<body>
<!-- 方法对象栈中的name属性 -->
<s:property value="[0]['name']"/><br/>
<!-- 方法上下文map中的action对象的name属性 -->
<s:property value="#action.name"/>
<!-- 调用对象栈中的方法 -->
对象栈的方法:<s:property value="[0].getAge()"/><br>
<!-- 访问静态变量 -->
<s:property value="@com.yd.action.Stack@age"/>
<!-- 访问静态变量的方法 -->
<s:property value="@com.yd.action.Stack@getAge()"/>
<br>
<%
//创建一个数组
String[] strs={"AA","BB","CC","DD"};
//创建一个list
User user=new User();
user.setName("aa");
user.setHobby("bb");
List list=new ArrayList();
list.add("QQ");
list.add("TEL");
list.add(user);
//创建一个map
Map map=new HashMap();
map.put("id","001");
map.put("age", "27");
request.setAttribute("strs", strs);
request.setAttribute("list", list);
request.setAttribute("map", map);
%>
<!-- ognl来访问数组 -->
数组元素:<s:property value="#request.strs[3]"/><br>
链表元素:<s:property value="#request.list[2].hobby"/><br>
map元素:<s:property value="#request.map['id']"/><br>
<s:property value="#test"/>
<s:debug></s:debug>
</body>
</html>
运行结果如下: