概述
OGNL表达式基础
- OGNL是ObjectGraphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。Struts2框架使用OGNL作为默认的表达式语言,只能用于struts框架。相对 EL表达式,它提供了平时我们需要的一些功能,如:
支持对象方法调用,如xxx.sayHello();
支持类静态方法调用和值访问,表达式的格式为@[类全名(包括包路径)]@[方法名|值名],例如:@java.lang.String@format(‘foo%s’,’bar’) 或@cn.hw.Constant@APP_NAME;
操作集合对象
2. Ognl有一个上下文(Context)概念,即上下文就是一个MAP结构,它实现了java.utils.Map接口,在Struts2中上下文(Context)的实现为ActionContext,下面是上下文(Context)的结构示意图
context map{
application
session
valuestack(root)
request
parameters
attr(searchespage, request, session, then application scopes)
}
application对象:用于访问ServletContext的Map,例如#application.userName或者#application[‘userName’],相当于调用ServletContext的getAttribute(“username”)。
session对象:用来访问HttpSession的Map,例如#session.userName或者#session[‘userName’],相当于调用session.getAttribute(“userName”)。
request对象:用来访问HttpServletRequest属性(attribute)的Map,例如#request.userName或者#request[‘userName’],相当于调用request.getAttribute(“userName”)。
parameters对象:用与访问HTTP的请求参数,例如#parameters.userName或者#parameters[‘userName’],相当于调用request.getParameters(“username”)。相当于EL表达式的paramValues内置对象。
attr对象:用于按pageàrequestàsessionàapplication顺序访问其属性。相当于PageContext的findAttribute()方法,也相当于EL表达式${}
3. ★★当struts接受一个请求时,会迅速创建ActionContext,ValueStack,action。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。访问上下文(Context)中的对象需要使用#符号标注命名空间,如#application、#session。
1.1.1.2 ★★重点:OGNL中的值栈
1. 值栈(valueStack):值栈是依据静态注入生成的(OgnlValueStack)
(a) 值栈的获取:ActionContext.getContext().getValueStack()
struts2把ValueStack对象保存在名为struts.valueStack的request域中,
(b) 值栈的生命周期:值栈的生命周期就是一次请求
(c) struts2在后台将数据放到valueStack中,在前台把数据取出来,所以valueStack在struts2中充当传递数据的一种方式(相比在servlet中:request/session/application.getParameter())
(d) 值栈的内存结构:对象栈(是一个list用username取)、 map栈(是一个map用#username取)
对照上面的图:
ActionContext.getContext().getValueStack().getContext();//包含:【context:OgnlContext】
ActionContext.getContext().getValueStack().getRoot();//获取对象栈【root:CompoundRoot】
2. 对象栈的说明
(1) 如果将一个对象放到对象栈中,则这个对象的属性就暴露出来了,所以处于对象栈的对象的属性是可以直接访问的,如果在对象栈中有和访问字段名称相同的属性,struts2内部就会从栈顶开始查找,直到找到为止。利用这个特点能很好的解决jsp页面数据回显的问题,所以要进行回显的数据应该放在对象栈中,这样做的效率会比较高。
(a) 场景分析1
如果在对象栈中放了两个Person对象(person1和person2),这两个Person对象的属性相同,但是值不一样。当jsp页面需要访问该属性时,struts2会到对象栈从栈顶开始查找,只要找到了(不管值是哪一个的)它就不会再找了
(2) 对象栈获取数据和在对象栈中存入元素的方式有以下几种:
//对象栈其实就是一个List,用add(Object)方法把对象放到【对象栈栈底】
ActionContext.getContext().getValueStack().getRoot().add(useList);
//add(0,Object)方法是将元素放到【对象栈栈顶】
ActionContext.getContext().getValueStack().getRoot().add(0,userLiset);
//push()方法是对add(0,Object)方法进行的简单的封装,所以是放入【对象栈栈顶】
ActionContext.getContext().getValueStack().push(userList);
ActionContext.getContext().getValueStack().getRoot().get(0); ///get(0)取出栈顶元素
//peek()是对get(0)进行简单封装,也是取出【对象栈栈顶】元素
ActionContext.getContext().getValueStack().peek();//获取【对象栈栈顶】元素
ActionContext.getContext().getValueStack().pop();//移除【对象栈栈顶】元素
ActionContext.getContext().getValueStack().getRoot().romove(0);
//把一个map放入到【对象栈的栈顶】
ActionContext.getContext().getValueStack().set(key,obj);
(3) 页面访问方式:用ognl表达式访问对象栈,直接用属性名称就可以了,不用加#
3. map栈说明
(1) map栈中的内容
reuqest,session,application都在map栈中;
可以把一个对象放入到map中;
当前请求Action在map栈中也存放了一份。
(2) ognl表达式访问map栈中的内容的方式
如果一个对象放在request中:#request.对象的key值.属性
如果一个对象直接放入到map中:#对象的key值.属性
(说明:把一个对象放入到map栈中,是不能直接访问该对象的属性)
(3) 把对象放入map栈中的方式
//把一个对象放到map栈中
ActionContext.getContext.put("departmentList", departmentList);
ServletActionContext.getRequest().setAttribute("departmentList", departmentList);
(4) ★★▲关于jsp页面的遍历:<iterator>[value属性:迭代对象的key值]
(a) 当前正在迭代的元素的在栈顶:如果没有放任何一个对象在对象栈中,则当前请求的action在栈顶,但用<iterator>标签遍历对象时,当前迭代的元素优先级比当前action更高,居于栈顶,其属性可以直接访问。
(b) 如果value属性不写,则默认迭代栈顶的元素。这一点可以解释,在action层将一个对象放入到对象栈中,当在页面要进行迭代的时候,虽然没有value属性对迭代对象key值的指定,仍可以迭代指定对象属性。
(c) 如果value值为top,则也是迭代栈顶元素。
【UserAction.java】
public class UserAction implements ModelDriven<User> {
public String setValue() {
List<User>userList = new ArrayList<User>();
List<List<User>> users = new ArrayList<List<User>>();
User user = new User();
user.setId(1L);
user.setName("hyc");
User user1 = new User();
user1.setId(2L);
user1.setName("xjk");
userList.add(user);
userList.add(user1);
users.add(userList);
ActionContext.getContext().put("userList", userList);
Map<String,List<User>> map = new HashMap<String,List<User>>();
map.put("userList", userList);
ActionContext.getContext().put("users",users);
return "index";
}
}
【index.jsp】
<!-- ★★利用当前正在迭代的元素在对象栈的栈顶,所以id和name前面不要用#-->
<!—userList放在map栈中,迭代:List<User> -->
<s:iterator value="#userList">
<s:property value="id" />
<s:property value="name" /><br/>
</s:iterator>
<hr/>
<!-- users放在map栈中,迭代:List<List<User>> -->
<s:iterator value="#users">
<s:iterator>
<s:property value="id" />
<s:property value="name" /><br/>
</s:iterator>
</s:iterator >
<hr/>
<!-- users放在map栈中,迭代:Map<String,List<User>> -->
<s:iterator value="#map">
<s:property value="key"/>
<s:iterator value="value">
<s:property value="id"/>
<s:property value="name" /><br/>
</s:iterator>
</s:iterator>
<!-- users放在map栈中,迭代:List<Map<String,User> -->
<s:iterator value="#users">
<s:iterator>
<s:property value="key" />
<s:property value="value.name" /><br/>
</s:iterator>
</s:iterator >
<hr/>
4. 补充
注意:★★Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value=“name”/>
相当于jstl核心标签中的:<c:outvalue=”${sessionScope.user}”/>
小技巧:★★在页面中使用<s:debug/>,然后再浏览器中点击debug,出来的就是ActionContext,可以查看上下文中的对象。
5. 对于集合类型,OGNL表达式可以使用in和not in两个元素符号。其中,in表达式用来判断某个元素是否在指定的集合对象中;not in判断某个元素是否不在指定的集合对象中
6. 解答:为何使用EL表达式能够访问valueStack中对象的属性?
原因:是Struts2对HttpServletRequest作了进一步的封装。简略源代码如下:
public class StrutsRequestWrapper extendsHttpServletRequestWrapper{
public StrutsRequestWrapper(HttpServletRequestreq){
super(req);
}
public Object getAttribute(Strings){
……
ActionContext ctx = ActionContext.getContext();
Objectattribute = super.getAttribute(s);//先从request范围获取属性值
if(ctx!=null){
if(attribute==null){
/*★★★如果从request范围没有找到属性值,即从ValueStack中查找对象的属性值*/
……
ValueStack stack = ctx.getValueStack();
attribute = stack.findValues(s);
……
}
}
return attribute;
}
}
1.1.1.3 ★★OGNL创建List/Map集合对象
如果需要一个集合元素的时候(例如List对象或者Map对象),可以使用OGNL中同集合相关的表达式。使用如下代码直接
1. 生成一个List对象:
Set标签用于将某个值放入指定范围。
scope:指定变量被放置的范围,该属性可以接受application、session、request、page或action。value:赋给变量的值。如果没有设置该属性,则将ValueStack栈顶的值赋给变量。
<s:set var="list1"value='{"a","b","c"}'></s:set><br/>
<!-- 创建集合,如果不指定范围默认放到了ActionContext上下文件中,scope="action"-->
<s:set var="list2"value="{'aa','bb','cc'}"scope="session"/><!--指定范围-->
<s:iterator value="#session.list2"var="l">
<s:property value="#l"/><br/>
</s:iterator>
2. 生成一个Map对象
<s:set var="map1" value="#{'a':'valuea','b':'valueb'}" scope="session"/>
<!-- 打印valueb:用#map1.b取不到 -->
<s:iterator value="#session.map1" var="me">
<s:property value="#me.key"/>=<s:property value="#me.value"/><br/>
</s:iterator>
<!-- 作用如同forEach -->
<c:forEach items="${sessionScope.map1}" var="me">
${me.key }=${me.value }<br/>
</c:forEach>
1.1.1.4 OGNL表达式的投影功能(不是很重要)<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1. 除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">1. 除了in和not in之外,OGNL还允许使用某个规则获得集合对象的子集,常用的有以下3个相关操作符。</span>
?:获得所有符合逻辑的元素
^:获得符合逻辑的第一个元素
$:获得符合逻辑的最后一个元素
2. 例如代码:
<s:iteratorvalue=“books.{?#this.price>35}”>
<s:propertyvalue=“title”/>-$<s:property value=“price”/><br/>
</s:iterator>
在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合,需要对大集合books进行迭代,this代表当前迭代的元素。本例的表达式用于获取集合中价格大于35的书集合。
public classBookAction extends ActionSupport{
private List<Book> books;
public String execute(){
books = newArrayList<Book>();
books.add(new Book(“a”,”spring”,67));
books.add(new Book(“b”,”ejb”,15));
}
}
最后
以上就是健忘鸡为你收集整理的struts2中OGNL表达式 OGNL表达式基础的全部内容,希望文章能够帮你解决struts2中OGNL表达式 OGNL表达式基础所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复