Struts2学习(四)OGNL标签介绍

OGNLObject-Graph Navigation Language的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者调用对象的方法,能够遍历整个对象的结构图,实现对象属性类型的转换等功能。从语言角度来说:它是一个功能强大的表达式语言,用来获取和设置java 对象的属性 , 它旨在提供一个更高抽象度语法来对 java 对象图进行导航,OGNL 在许多的地方都有应用,例如:

  1. 作为 GUI元素(textfield,combobox,等)到模型对象的绑定语言。
  2. 数据库表到 Swing TableModel的数据源语言。
  3. web组件和后台 Model对象的绑定语言 (WebOGNL,Tapestry,WebWork,WebObjects)
  4. 作为 Jakarata Commons BeanUtils或者 JSTL的表达式语言的一个更具表达力的替代语言。

另外,java中很多可以做的事情,也可以使用 OGNL 来完成,例如:列表映射和选择。对于开发者来说,使用 OGNL,可以用简洁的语法来完成对 java对象的导航。通常来说: 通过一个“路径”来完成对象信息的导航,这个“路径”可以是到 java bean的某个属性,或者集合中的某个索引的对象,等等,而不是直接使用 get或者 set 方法来完成。

 

为什么需要表达式语言 (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表达式的计算是围绕OGNL上下文进行的。

OGNL上下文实际上就是一个Map对象,由ognl.OgnlContext类表示。它里面可以存放很多个JavaBean对象。它有一个上下文根对象。

上下文中的根对象可以直接使用名来访问或直接使用它的属性名访问它的属性值。否则要加前缀“#key”。

 

2.Struts2的标签库都是使用OGNL表达式来访问ActionContext中的对象数据的。如:<s:propertyvalue="xxx"/>。

 

3.Struts2ActionContext设置为OGNL上下文,并将值栈作为OGNL的根对象放置到ActionContext中。

 

4.值栈(ValueStack)

可以在值栈中放入、删除、查询对象。访问值栈中的对象不用“#”。

Struts2总是把当前Action实例放置在栈顶。所以在OGNL中引用Action中的属性也可以省略“#”。

 

5.调用ActionContextput(key,value)放入的数据,需要使用#访问。

 

OGNL中重要的3个符号#%$:

#%$符号在OGNL表达式中经常出现,而这三种符号也是开发者不容易掌握和理解的部分,需要时间的积累才渐渐弄清楚……

1#符号

#符号的用途一般有三种。

  1. 访问非根对象属性,例如#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上#相当于ActionContext. getContext()#session.msg表达式相当于ActionContext.getContext().getSession(). getAttribute("msg")
  2. 用于过滤和投影(projecting)集合,如persons.{?#this.age>25}persons.{?#this.name=='pla1'}.{age}[0]
  3. 用来构造Map,例如示例中的#{'foo1':'bar1', 'foo2':'bar2'}

2%符号

%符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值,这个类似js中的eval,很暴力。

3$符号

$符号主要有两个方面的用途。

  1. 在国际化资源文件中,引用OGNL表达式,例如国际化资源文件中的代码:reg.agerange=国际化资源信息:年龄必须在${min}${max}之间。
  1. Struts 2框架的配置文件中引用OGNL表达式

 

我们来使用接下来的代码对OGNL标签做进一步了解:

 

首先先在这里介绍一下Struts2中的一些常用表单标签,包括基本的输入框、按钮、单选框、多选框等。

<%--
   Created by IntelliJ IDEA.
   User: icarus
   Date: 2016/7/9
   Time: 15:06
   To change this template use File | Settings | File Templates.
 --%>
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <%--添加Struts2标签支持--%>
 <%@taglib prefix="s" uri="/struts-tags" %>
 <html>
 <head>
     <title>Struts2标签演示</title>
 </head>
 <body>
 <h1>Struts2标签---表单</h1>
 <s:form action="userLoginAction" method="POST">
     <%--登录框--%>
     <s:textfield label="用户名" name="user.username"/>
     <s:password label="密码" name="user.passsword"/>
     <s:submit value="提交"/>
     <%--多选框--%>
     <s:checkboxlist list="{'sb','hb','cb'}" name="cb1" label="请选择你的属性"/>
     <s:checkboxlist list="#{'1':'sb','2':'hb','3':'cb'}" name="cb2" label="请选择你的属性"/>
     <%--单选框--%>
     <s:radio list="#{'1':'男','2':'女','3':'外星人'}" name="r1" label="请选择您的性别"/>
     <%--下拉列表--%>
     <s:select list="#{'1':'火星情报局','2':'极限挑战','3':'天天向上'}" label="请选择你喜欢看的综艺界面" name="check"/>
     <%--输入框--%>
     <s:textarea name="tt" label="请输入您的留言" cols="20" rows="20"/>
     <%--级联菜单--%>
     <s:doubleselect doubleList="top=='陕西'?{'西安','渭南','澄城'}:{'不知道1','不知道2','不知道3'}" doubleName="db" name="ds" list="{'陕西','山西'}"/>
     <%--双列表内容转移--%>
     <s:optiontransferselect
             label="喜欢的书"
             name="cnbook"
             list="#{'1':'活着','2':'日子','3':'悲惨世界'}"
             listKey="key"
             listValue="value"
             multiple="true"
             headerValue="请选择中文书籍"
             emptyOption="true"
             headerKey="cnkey"
             leftTitle="中文书籍"
             rightTitle="英文书籍"
             doubleName="enbook"
             doubleList="#{'1':'one','2':'two','3':'three'}"
             doubleListKey="key"
             doubleListValue="value"
             doubleMultiple="true"
             doubleHeaderValue="请选择英文书籍"
             doubleHeaderKey="enkey"
             doubleEmptyOption="true"
     />
 </s:form>
 </body>
</html>


界面效果



接下来演示OGNL的主要作用:

 <%@ page import="java.util.List" %>
 <%@ page import="cn.lovepi.chapter04.bean.User" %>
 <%@ page import="java.util.ArrayList" %><%--
   Created by IntelliJ IDEA.
   User: icarus
   Date: 2016/7/9
   Time: 16:28
   To change this template use File | Settings | File Templates.
 --%>
 <%@ page contentType="text/html;charset=UTF-8" language="java" %>
 <%@ taglib prefix="s" uri="/struts-tags" %>
 <html>
 <head>
     <title>测试页面</title>
 </head>
 <body>
     <%--set标签:向各种域存放值。
     默认情况下的作用域是:request和pageContext
     可以使用scope来指定作用域
     相当于java代码:
     <%request.setAttribute("age",60);%>
     --%>
     <%------------------存放基本数据类型----------------%>
     <s:set name="age" value="90"/>
     <s:set name="age1" value="80" scope="session"/>
     <%--存放list集合--%>
     <s:set name="bookList" value="{'活着','人生','晏婴'}"/>
     <%--存放map集合--%>
     <s:set name="bookMap" value="#{'1':'活着','2':'人生','3':'晏婴'}"/>
     <%------------------获取set存放的数据---------------%>
     <%--获取基本数据类型--%>
     <s:property value="#age"/>
     <%--获取list集合中的数据--%>
     <s:property value="#bookList"/>
     <%--获取list集合中指定的数据,按照角标来判断--%>
     <s:property value="#bookList[1]"/>
     <%--获取map中的所有key值--%>
     <s:property value="#bookMap.keys"/>
     <%--获取map中的所有value值--%>
     <s:property value="#bookMap.values"/>
     <%---------------可以进行数据的if判断-------------------%>
     <s:if test="#>85age>=60">
         及格
     </s:if>
     <s:elseif test="#age>=85">
         学霸
     </s:elseif>
     <s:else>
         学沫沫
     </s:else>
     <%-------------可以使用迭代器来获取集合中的元素-----------------%>
     <%--获取list集合中的元素--%>
     <s:iterator value="#bookList" id="bookName">
         <s:property value="bookName"/>
     </s:iterator>
     <%--获取map集合中的元素--%>
	     <s:iterator value="#bookMap">
         <s:property value="key"/>
         <s:property value="value"/>
         <br>
     </s:iterator>
     <%--当集合中的元素是一个对象时,使用iterator来获取值
     其中status用来表示该行的一些状态信息--%>
     <%
         List<User> userList=new ArrayList<User>();
         User user1=new User(1,"张三","123");
         User user2=new User(2,"李四","123");
         User user3=new User(3,"王五","123");
         User user4=new User(4,"赵六","123");
         userList.add(user1);
         userList.add(user2);
         userList.add(user3);
         userList.add(user4);
         request.setAttribute("testList",userList);
     %>
     <%--还可以在这里对集合中的元素进行过滤
     使用:#request.testList.{?#this.uid>2},这里?^$三种符号都是可以的
     --%>
     <s:iterator value="#request.testList" var="us" status="vr">
         <%--0,2,4,6..行后换行--%>
         <s:if test="#vr.index%2==0"><br></s:if>
         <%--当前元素是否是第一个元素--%>
         <s:property value="#vr.first"/>
         <%--当前元素是否是最后一个元素--%>
         <s:property value="#vr.last"/>
         <%--当前元素的位置数--%>
         <s:property value="#vr.count"/>
         <%--当前元素的位置数是否为奇数--%>
         <s:property value="#vr.odd"/>
         <%--当前元素的位置数是否是偶数--%>
         <s:property value="#vr.even"/>
         <s:property value="#us.uid"/>
         <s:property value="#us.username"/>
         <s:property value="#us.passsword"/>
     </s:iterator>
 </body>
</html>


界面效果



总结OGNL的使用方法:

 

访问属性

名字属性获取:<s:property value="user.username"/><br>

地址属性获取:<s:property value="user.address.addr"/><br>

 

访问方法

调用值栈中对象的普通方法:<s:property value="user.get()"/><br>

 

访问静态属性和方法

调用Action中的静态方法:<s:property value="@struts.action.LoginAction@get()"/>

调用JDK中的类的静态方法:<s:property value="@java.lang.Math@floor(44.56)"/><br>

调用JDK中的类的静态方法(同上)<s:property value="@@floor(44.56)"/><br>

调用JDK中的类的静态方法:<s:property value="@java.util.Calendar@getInstance()"/><br>

调用普通类中的静态属性:<s:property value="@struts.vo.Address@TIPS"/><br>

 

访问构造方法

调用普通类的构造方法:<s:property value="new struts.vo.Student('李晓红' , '美女' , 3 , 25).username"/>

 

访问数组

获取List:<s:property value="testList"/><br>

获取List中的某一个元素(可以使用类似于数组中的下标获取List中的内容):

<s:property value="testList[0]"/><br>

获取Set:<s:property value="testSet"/><br>

获取Set中的某一个元素(Set由于没有顺序,所以不能使用下标获取数据):

<s:property value="testSet[0]"/><br> ×

获取Map:<s:property value="testMap"/><br>

获取Map中所有的键:<s:property value="testMap.keys"/><br>

获取Map中所有的值:<s:property value="testMap.values"/><br>

获取Map中的某一个元素(可以使用类似于数组中的下标获取List中的内容):

<s:property value="testMap['m1']"/><br>

获取List的大小:<s:property value="testSet.size"/><br>

 

访问集合 – 投影、选择(? ^ $)

利用选择获取List中成绩及格的对象:<s:property value="stus.{?#this.grade>=60}"/><br>

利用选择获取List中成绩及格的对象的username:

<s:property value="stus.{?#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的第一个对象的username:

<s:property value="stus.{?#this.grade>=60}.{username}[0]"/><br>

利用选择获取List中成绩及格的第一个对象的username:

<s:property value="stus.{^#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的最后一个对象的username:

<s:property value="stus.{$#this.grade>=60}.{username}"/><br>

利用选择获取List中成绩及格的第一个对象然后求大小:

<s:property value="stus.{^#this.grade>=600}.{username}.size"/><br>

 

集合的伪属性

OGNL能够引用集合的一些特殊的属性,这些属性并不是JavaBeans模式,例如size(),length()等等. 当表达式引用这些属性时,OGNL会调用相应的方法,这就是伪属性.

集合

伪属性

Collection(inherited by Map, List & Set)

size ,isEmpty

List

iterator

Map

keys , values

Set

iterator

Iterator

next , hasNext

Enumeration

next , hasNext , nextElement , hasMoreElements

 

 Lambda   :[]

格式::[]

使用Lambda表达式计算阶乘:

<s:property value="#f = :[#this==1?1:#this*#f(#this-1)] , #f(4)"/><br>

 

OGNL#的使用

#可以取出堆栈上下文中的存放的对象.

名称

作用

例子

parameters

包含当前HTTP请求参数的Map

#parameters.id[0]作用相当于

request.getParameter("id")

request

包含当前HttpServletRequest的属性(attribute)Map

#request.userName相当于

request.getAttribute("userName")

session

包含当前HttpSession的属性(attribute)的Map

#session.userName相当于

session.getAttribute("userName")

application

包含当前应用的ServletContext的属性(attribute)的Map

#application.userName相当于

application.getAttribute("userName")

attr

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

 

获取Paraments对象的属性:<s:propertyvalue="#parameters.username"/>

 

OGNL%的使用

用%{}可以取出存在值堆栈中的Action对象,直接调用它的方法.

例如你的Action如果继承了ActionSupport.那么在页面标签中,用%{getText('key')}的方式可以拿出国际化信息.

 OGNL中$的使用

$”有两个主要的用途

  • 用于在国际化资源文件中,引用OGNL表达式
  • 在Struts 2配置文件中,引用OGNL表达式

 

值栈

ValueStack对象。这个对象贯穿整个Action的生命周期(每个Action类的对象实例会拥有一个ValueStack对象)。当Struts 2接收到一个.action的请求后,会先建立Action类的对象实例,但并不会调用Action方法,而是先将Action类的相应属性放到ValueStack对象的顶层节点(ValueStack对象相当于一个栈)。

Action中获得ValueStack对象:ActionContext.getContext().getValueStack()

l         Top语法

使用Top获取值栈中的第二个对象:<s:property value="[1].top.对象"/>

l         N语法

使用N获取值栈中的第二个对象:<s:property value="[1].对象"/>

l         @语法

调用action中的静态方法:<s:property value="@vs1@静态方法"/>vs:值栈 1:表示第一个。




猜你喜欢

转载自blog.csdn.net/icarus_wang/article/details/52047751
今日推荐