ognl是跟struts2的标签一起使用的。Struts2结合了ognl,在ognl中有根元素的概念,在Struts2中,根对象就是ValueStack,在任何流程当中,ValueStack最顶层的对象,一定是Action对象。除了ValueStack根对象外,Struts2还提供了几个常用的非根对象,叫做命名对象:parameters, request, session, application, attr。
若访问根对象,那么在表达式中直接访问即可,若访问的不是根对象,那么就要在要访问的对象的前面加上“#”,表示访问的不是根对象。
如何访问值栈中的对象的属性?若访问的是值栈中的对象的属性,那么struts2会从栈的顶部往下寻找和表达式中指定的属性匹配的属性,若找到,就不再继续往下找。也可以不从顶部开始找起,这时就要用到方括号去指定从哪里开始找起。
下面结合例子,看一下在Struts2中,ognl是怎么使用的:
package com.suo.action;
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 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 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;
}
}
package com.suo.action;
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;
}
}
package com.suo.action;
import java.util.ArrayList;
/**
* 实现了RequestAware,SessionAware,ApplicationAware接口,是为了取得Servlet API中的request等对象,
* 这也是取得这些对象的一种方法。
* 注意,这些属性一定要有对应的set方法。
* @author hackerain
*/
public class OgnlAction extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String,Object> request;
private Map<String, Object> application;
private Map<String, Object> session;
private String username;
private String password;
private List<Person> list;
public List<Person> getList() {
return list;
}
public void setList(List<Person> list) {
this.list = list;
}
@Override
public void setRequest(Map<String, Object> request) {
this.request=request;
}
@Override
public void setApplication(Map<String, Object> application) {
this.application=application;
}
@Override
public void setSession(Map<String, Object> session) {
this.session=session;
}
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 String execute() throws Exception {
request.put("hello", "suo");
session.put("hello", "piao");
application.put("hello", "rachel");
Cat cat1=new Cat("cat1", 12, "red");
Cat cat2=new Cat("cat2", 11, "blue");
String[] friends1=new String[]{"gg1","gg2","gg3"};
String[] friends2=new String[]{"mm1","mm2","mm3"};
Map<String,String> map1=new HashMap<String,String>();
Map<String,String> map2=new HashMap<String,String>();
map1.put("key11", "value11");
map1.put("key12", "value12");
map2.put("key21", "value21");
map2.put("key22", "value22");
Person person1=new Person("suo",23,"changsha",friends1,cat1,map1);
Person person2=new Person("piao",21,"changchun",friends2,cat2,map2);
list=new ArrayList<Person>();
list.add(person1);
list.add(person2);
return SUCCESS;
}
}
login.jsp:
<body>
<form action="OgnlAction">
username: <input type="text" name="username" width="20"><br>
password: <input type="password" name="password" width="20"><br>
<input type="submit" value="submit">
</form>
</body>
ognl.jsp:
<%@ page language="java" import="java.util.*, com.opensymphony.xwork2.*, com.suo.action.OgnlAction" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>My JSP 'ognl.jsp' starting page</title>
</head>
<body>
--------------------------------------------<br>
标签库实现:<br>
username: <s:property value="username"/><br>
password: <s:property value="password"/><br>
<!-- 因为此处ValueStack为根对象,而Action对象又保存到ValueStack的最顶层,所以此处不用#号指定属性的对象 -->
--------------------------------------------<br>
用parameters命名对象实现:<br>
username: <s:property value="#parameters.username"/><br>
password: <s:property value="#parameters.password"/><br>
<!--
此处用的是parameters命名对象,它和ValueStack根对象是处在同一个地位的,只是它不是根对象而已,所以
要访问命名对象中的属性,则要用#号指定对象名。request,session,application同理。
-->
--------------------------------------------<br>
底层实现:<br>
username: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getUsername() %><br>
password: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getPassword() %><br>
<!-- peek()函数是返回栈的最顶部的对象,但是并不从栈中删除这个对象,最顶部的对象为Action对象 -->
--------------------------------------------<br>
用命名对象实现:<br>
request: <s:property value="#request.hello"/><br>
session: <s:property value="#session.hello"/><br>
application: <s:property value="#application.hello"/><br>
attr: <s:property value="#attr.hello"/><br>
--------------------------------------------<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>
<!-- ActionContext是一个提供Action上下文环境的类,提供了getSession(),getApplication,get()等方法 -->
--------------------------------------------<br>
用标签库实现:<br>
person1.name:<s:property value="list[0].name"/><br>
person2.address:<s:property value="list[1].address"/><br>
list.size: <s:property value="list.size"/><br>
list.isEmpty: <s:property value="list.isEmpty()"/><br>
person1.cat: <s:property value="list[0].cat.name"/><br>
person2.friend1: <s:property value="list[1].friends[0]"/><br>
person1.map1: <s:property value="list[0].map"/><br>
person2.map2.key21: <s:property value="list[1].map['key21']"/><br>
<!-- 值栈是根对象,且在值栈的最顶层的对象为Action对象,所以这里可以直接指定Action中的属性来访问 -->
--------------------------------------------<br>
底层实现:<br>
person1.name: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getName() %><br>
person2.address: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getAddress() %><br>
list.size: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().size() %><br>
list.isEmpty: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().isEmpty() %><br>
person1.cat: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getCat().getName()%><br>
person2.friend1: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getFriends()[0] %><br>
person1.map1: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(0).getMap() %><br>
person2.map2.key21: <%=((OgnlAction)ActionContext.getContext().getValueStack().peek()).getList().get(1).getMap().get("key21") %><br>
--------------------------------------------<br>
<!-- 过滤 -->
person.name.lenth>2: <s:property value="list.{? #this.name.length()>2}"/><br>
person.iterator:<br>
<s:iterator value="list.{? #this.name.length()>2}">
<s:property value="name"/><br>
<s:property value="cat.name"/><br>
<s:property value="friends[0]"/><br><br>
</s:iterator>
<!-- 投影 -->
persons.name: <s:property value="list.{name}"/><br>
<s:iterator value="list.{name}">
<s:property/><br><!-- 这里已经是简单的属性了,不用写value,就可以取出来值了 -->
</s:iterator>
</body>
</html>