struts2中OGNL的使用
1、在Struts2中有一个称之为值栈的概念(ValueStack)
struts2值栈提供了[N]语法和TOP关键字
在struts2中,OGNL根对象就是ValueStack。在Struts2的任何流程当中,ValueStack中的最顶层对象一定是Action对象。
所以如果页面中有<s:property value="username" />这个username一定是Action中的username。
2、struts2除了值栈,还有定义了一些“命名对象”:
parameters,#parameters.username
request,#request.username
session,#session.username
application,#application.username
attr,#sttr.username
命名对象与valuestack的关系
命名对象与ValueStack是同级的关系,而在Struts2的OGNL中,ValueStack是根元素,所以要访问request中的属性,需要#request.name。
3、访问静态方法或静态成员变量的改进。
@vs@method,如果静态方法在值栈中
4、关于Struts2标签库中OGNL的使用举例:
创建一个action:OgnlAction:
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
-
- import org.apache.struts2.interceptor.ApplicationAware;
- import org.apache.struts2.interceptor.RequestAware;
- import org.apache.struts2.interceptor.SessionAware;
-
- import com.opensymphony.xwork2.ActionSupport;
-
- public class OgnlAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware
- {
- private String username;
-
- private String password;
-
- private Map<String,Object> requestMap;
-
- private Map<String,Object> sessionMap;
-
- private Map<String,Object> applicationMap;
-
- private List<Person> list;
-
-
-
- public List<Person> getList()
- {
- return list;
- }
-
- public void setList(List<Person> list)
- {
- this.list = list;
- }
-
- 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;
- }
-
- @Override
- public void setRequest(Map<String, Object> arg0)
- {
- System.out.println("setRequest invoke!");
- this.requestMap = arg0;
- }
-
- @Override
- public void setSession(Map<String, Object> arg0)
- {
- this.sessionMap = arg0;
- }
-
- @Override
- public void setApplication(Map<String, Object> arg0)
- {
- this.applicationMap = arg0;
- }
-
- @Override
- public String execute() throws Exception
- {
- requestMap.put("hello", "world");
- sessionMap.put("hello", "hello");
- applicationMap.put("hello", "world");
-
- Cat cat1 = new Cat("cat1",20,"red");
- Cat cat2 = new Cat("Cat2",21,"yellow");
-
- String[] friends1 = {"test1","test2","test3"};
- String[] friends2 = {"welcome1","welcome2","welcome3"};
-
- Map<String,String> map1 = new HashMap<String,String>();
- Map<String,String> map2 = new HashMap<String,String>();
-
- map1.put("test1", "test1");
- map1.put("test2", "test2");
-
- map2.put("hello1", "hello1");
- map2.put("hello2", "hello2");
-
- Person person1 = new Person("zhangsan",20,"beijing",friends1,cat1,map1);
- Person person2 = new Person("lisi",22,"shanghai",friends2,cat2,map2);
-
- list = new ArrayList();
-
- list.add(person1);
- list.add(person2);
-
- return SUCCESS;
- }
- }
这个action实现了三个接口:RequestAware,SessionAware,ApplicationAware,这是一个知识点,这三个接口中都提供了一个类似的方法:
setRequest(Map<String, Object> arg0);setSession(Map<String, Object> arg0);setApplication(Map<String, Object> arg0),在struts2的众多过滤器中,有一个过滤器对请求的Action进行检查,看是否实现了上述三个接口,如果实现了,就会自动调用其中的setXXX方法,将相应的request、session、application对象保存。这是访问request等对象的又一种方法。
struts配置文件进行相应的action配置:
- <action name="OgnlAction" class="com.cdtax.action.ognl.OgnlAction">
- <result name="success">ognl.jsp</result>
- </action>
然后创建一个ognl.jsp测试页面:
- <%@ page language="java" import="java.util.*,com.cdtax.action.ognl.*,com.opensymphony.xwork2.*,com.opensymphony.xwork2.util.*" pageEncoding="UTF-8"%>
- <%@ taglib prefix="s" uri="/struts-tags" %>
-
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
- %>
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <base href="<%=basePath%>">
-
- <title>My JSP 'ognl.jsp' starting page</title>
-
- <meta http-equiv="pragma" content="no-cache">
- <meta http-equiv="cache-control" content="no-cache">
- <meta http-equiv="expires" content="0">
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="This is my page">
- <!--
- <link rel="stylesheet" type="text/css" href="styles.css">
- -->
-
- </head>
-
- <body>
- username:<s:property value="username"/><br/>
- password:<s:property value="password"/><br/>
- _________________________________________________________<br/>
-
- username:<s:property value="#parameters.username"/><br/>
- password:<s:property value="#parameters.password"/><br/>
- _________________________________________________________<br/>
-
- request:<s:property value="#request.hello"/><br/>
- session:<s:property value="#session.hello"/><br/>
- application:<s:property value="#application.hello"/><br/>
- _________________________________________________________<br/>
-
- request:<%= ((Map)ActionContext.getContext().get("request")).get("hello") %><br/>
- session:<%= ActionContext.getContext().getSession().get("hello") %><br/>
- application:<%= ActionContext.getContext().getApplication().get("hello") %><br/>
-
- attr:<%= ((Map)ActionContext.getContext().get("attr")).get("hello") %>
-
- _________________________________________________________<br/>
-
- Person1:address:<s:property value="list[0].address"/><br/>
- person2:age:<s:property value="list[1].age"/><br/>
- Person1:cat1:name:<s:property value="list[0].cat.name"/><br/>
- person1:size:<s:property value="list.size"/><br/>
- isEmpty:<s:property value="list.isEmpty()"/><br/>
- _________________________________________________________<br/>
-
- Person1:address:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getAddress() %><br/>
- person2:age:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getAge() %><br/>
- Person1:cat1:name:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getCat().getName() %><br/>
-
- _________________________________________________________<br/>
-
- person2:friends:<s:property value="list[1].friends[2]"/><br/>
- person2:friends:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getFriends()[2] %><br/>
-
- _________________________________________________________<br/>
-
- person2:map2:<s:property value="list[1].map['hello2']"/><br/>
- _________________________________________________________<br/>
-
- filtering:<s:property value="list.{? #this.name.length() > 2}[0].name"/><br/>
- _________________________________________________________<br/>
- <s:iterator value="list.{? #this.name.length() > 2}">
-
- <s:property value="name"/><br/>
- <s:property value="cat.color"/><br/>
- <s:property value="friends[0]"/><br/>
-
- </s:iterator>
-
- _________________________________________________________<br/>
-
- projection:<br/>
- <s:iterator value="list.{age}">
-
- <s:property/><br/>
-
- </s:iterator>
- </body>
- </html>
相应用到的Person类和Cat类
- import java.util.Map;
-
- public class Person
- {
- private String name;
-
- private int age;
-
- private String address;
-
- private String[] friends;
-
- private Cat cat;
-
- private Map<String,String> map;
-
- public Person(String name,int age,String address,String[] friends,Cat cat,Map<String,String> map)
- {
- this.name = name;
- this.age = age;
- this.address = address;
- this.friends = friends;
- this.cat = cat;
- this.map = map;
- }
-
- public Person()
- {
-
- }
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public int getAge()
- {
- return age;
- }
-
- public void setAge(int age)
- {
- this.age = age;
- }
-
- public String getAddress()
- {
- return address;
- }
-
- public void setAddress(String address)
- {
- this.address = address;
- }
-
- public String[] getFriends()
- {
- return friends;
- }
-
- public void setFriends(String[] friends)
- {
- this.friends = friends;
- }
-
- public Cat getCat()
- {
- return cat;
- }
-
- public void setCat(Cat cat)
- {
- this.cat = cat;
- }
-
- public Map<String, String> getMap()
- {
- return map;
- }
-
- public void setMap(Map<String, String> map)
- {
- this.map = map;
- }
-
-
- }
- public class Cat
- {
- private String name;
-
- private int age;
-
- private String color;
-
- public Cat(String name,int age,String color)
- {
- this.name = name;
- this.age = age;
- this.color = color;
- }
-
- public Cat()
- {
-
- }
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public int getAge()
- {
- return age;
- }
-
- public void setAge(int age)
- {
- this.age = age;
- }
-
- public String getColor()
- {
- return color;
- }
-
- public void setColor(String color)
- {
- this.color = color;
- }
-
-
- }
struts2标签使用了OGNL表达式,对于:
username:<s:property value="username"/><br/>
password:<s:property value="password"/><br/>
<s:property value="username" />value值是OGNL表达式,因为没有使用#号,所以是直接从OGNL的根元素中寻找username,因为在struts2中,OGNL的根元素是值栈,即ValueStack,而ValueStack的最顶上元素一定是Action,这里即是OgnlAction,所以页面将显示OgnlAction中的username属性值。password同理。
对于:
username:<s:property value="#parameters.username"/><br/>
password:<s:property value="#parameters.password"/><br/>
这里使用了命名对象parameters,因为parameters不是根元素,所以要使用#parameters来指定搜索的元素,然后使用点加属性名确定最终的属性值,即#parameters.username
对于:
request:<s:property value="#request.hello"/><br/>
session:<s:property value="#session.hello"/><br/>
application:<s:property value="#application.hello"/><br/>
使用了另外三个命名对象:request,session和application,注意的是requestMap等就是对应的request等
对于:
request:<%= ((Map)ActionContext.getContext().get("request")).get("hello") %><br/>
session:<%= ActionContext.getContext().getSession().get("hello") %><br/>
application:<%= ActionContext.getContext().getApplication().get("hello") %><br/>
attr:<%= ((Map)ActionContext.getContext().get("attr")).get("hello") %>
这里使用了java来达到struts标签的效果,主要是演示struts标签的实现原理。这是使用了ActionContext类来访问servletAPI,((Map)ActionContext.getContext().get("request"))将获得request对象,是Map类型的
(在Struts2.0中,Action已经与Servlet API完全分离,这使得Struts2.0的Action具有了更加灵活和低耦合的特性,与Struts1.0相比较而言是个巨大的进步。虽然Struts2.0的Action已经与Servlet API完全分离,但我们在实现业务逻辑处理时经常需要访问Servlet中的对象,如Session、Application等。Struts2.0 提供了一个名字为ActionContext的类,在Action中可以通过该类获得Servlet API。
ActionContext是一个Action的上下文对象,Action运行期间所用到的数据都保存在ActionContext中(如Session,客户端提交的参数等信息)。
在Action中可以通过下面的代码来创建和使用ActionContext类,关于该类的方法介绍如下所示:
ActionContext ac=ActionContext.getContext();
)
对于:
Person1:address:<s:property value="list[0].address"/><br/>
person2:age:<s:property value="list[1].age"/><br/>
Person1:cat1:name:<s:property value="list[0].cat.name"/><br/>
person1:size:<s:property value="list.size"/><br/>
isEmpty:<s:property value="list.isEmpty()"/><br/>
_________________________________________________________<br/>
Person1:address:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getAddress() %><br/>
person2:age:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getAge() %><br/>
Person1:cat1:name:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getCat().getName() %><br/>
这是对列表使用的演示,上半部分使用标签OGNL表达式,下面是java实现
对于:
erson2:friends:<s:property value="list[1].friends[2]"/><br/>
person2:friends:<%= ((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getFriends()[2] %><br/>
是对数组的访问举例
对于:
person2:map2:<s:property value="list[1].map['hello2']"/><br/>
是对映射的使用
对于:
filtering:<s:property value="list.{? #this.name.length() > 2}[0].name"/><br/>
_________________________________________________________<br/>
<s:iterator value="list.{? #this.name.length() > 2}">
<s:property value="name"/><br/>
<s:property value="cat.color"/><br/>
<s:property value="friends[0]"/><br/>
</s:iterator>
是OGNL过滤的演示,注意这里使用了iterator迭代标签,在iterator标签内的property,其value应该是迭代对象的属性,如这里的<s:property value="name"/><br/>迭代对象是Person,那么就是person的name,相对应的,如下迭代:
projection:<br/>
<s:iterator value="list.{age}">
<s:property/><br/>
</s:iterator>
这是OGNL的映射,迭代的是age集合,迭代对象是一个个age,所以<s:property/><br/>的value不用写,如果写成<s:property value=“age”/><br/>就错了,因为迭代对象age没有一个age属性。
5、关于struts2标签库属性值的%与#的关系:
如果标签的属性值是OGNL表达式,那么无需加上%{}
如果标签的属性值是字符串类型,那么在字符串当中凡出现的%{}都会被解析成OGNL表达式,解析完毕后再与其它的字符串进行拼接构造出最后的字符串值
我们可以在所有的属性之上加%{},这样如果该属性值是OGNL表达式,那么标签处理类就会将%{}忽略掉。
如:
<s:a href="getsinglePerson.action?id=%{#person.id}"><s:property value="username" /></s:a>
如果这里不加上%{},那么#person.id就直接解释成单纯的字符串了,起不到动态赋值的作用
6、如果一个Action执行时间很长,前端页面显示是空白的,这时可以使用一个等待页面,这时要用到一个拦截器:ExcuteAndWaitInterceptor
如果配置了ExcuteAndWaitInterceptor拦截器,在执行Action时,服务器后台会另起一个线程,定期的监控这个Action是否执行完毕,如果没有执行完毕,就显示一个等待页面
配置Action拦截器:
- <action name="OgnlAction" class="com.cdtax.action.ognl.OgnlAction">
- <interceptor-ref name="defaultStack"></interceptor-ref>
- <interceptor-ref name="execAndWait"></interceptor-ref>
- <result name="success">ognl.jsp</result>
- <result name="wait">/wait.jsp</result>
- </action>
然后新建一个等待jsp:
- <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- String path = request.getContextPath();
- String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
- %>
-
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
- <html>
- <head>
- <base href="<%=basePath%>">
-
- <title>My JSP 'wait.jsp' starting page</title>
- <span style="color:#ff0000;"><meta http-equiv="refresh" content="5;url=<s:url includeParams="all" />"/>
- </span>
- <meta http-equiv="pragma" content="no-cache">
- <meta http-equiv="cache-control" content="no-cache">
- <meta http-equiv="expires" content="0">
- <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
- <meta http-equiv="description" content="This is my page">
- <!--
- <link rel="stylesheet" type="text/css" href="styles.css">
- -->
-
- </head>
-
- <body>
- 等待界面<span style="color:#ff0000;">,<a href="<s:url includeParams="all" />">Click </a></span> if this page does not reload automatically <br>
- </body>
- </html>
注意红色的代码行,是等待页面的关键,每5秒钟自动刷新一次。
修改OgnlAction的excute方法,增加一个睡眠时间,模拟长时间操作:
- public String execute() throws Exception
- {
- <span style="color:#ff0000;">Thread.sleep(20000);
- </span>
- // <span style="color:#3333ff;">requestMap.put("hello", "world");
- </span> sessionMap.put("hello", "hello");
- applicationMap.put("hello", "world");
-
- Cat cat1 = new Cat("cat1",20,"red");
- Cat cat2 = new Cat("Cat2",21,"yellow");
-
- String[] friends1 = {"test1","test2","test3"};
- String[] friends2 = {"welcome1","welcome2","welcome3"};
-
- Map<String,String> map1 = new HashMap<String,String>();
- Map<String,String> map2 = new HashMap<String,String>();
-
- map1.put("test1", "test1");
- map1.put("test2", "test2");
-
- map2.put("hello1", "hello1");
- map2.put("hello2", "hello2");
-
- Person person1 = new Person("zhangsan",20,"beijing",friends1,cat1,map1);
- Person person2 = new Person("lisi",22,"shanghai",friends2,cat2,map2);
-
- list = new ArrayList();
-
- list.add(person1);
- list.add(person2);
-
- return SUCCESS;
- }
注意,requestMap.put("hello", "world"); 这一行要注释掉,否则会出现空指针异常
|