Struts2标签库和OGNL

学习内容

 Struts 2标签库

 OGNL

能力目标

 熟练使用Struts 2常用标签

 熟练使用OGNL

 


本章简介

前面我们编写的案例使用的都是HTML标签,这些标签并不能很好的与Struts 2框架结合,Struts 2Struts 1一样都自带了功能强大、成熟完善的标签库供我们使用,通过使用这些标签库可以大大提高开发效率和代码的可维护性。

其实Struts 2的标签库是建立在OGNL基础上的,OGNL是一种功能强大的表达式语言,通过简单的语法即可存取对象的属性、调用对象的方法、遍历等功能。

本章将学习OGNLStruts 2标签库,包括数据访问标签、控制标签

核心技能部分

6.1 OGNL

6.1.1 ActionContext

Struts 2中的ActionContextValueStackStackContext对象与OGNL密切相关,理解这三个对象时学习OGNL的前提。

在前面的学习中,我们已经在使用ActionContextValueStackStackContext对象了,这三个对象的作用及其之间的关系如图6.1.1所示。

Struts2标签库和OGNL

图6.1.1 ActionContext

1. ActionContext对象

ActionContextcom.opensymphony.xwork.ActionContext)是Action执行时的上下文。我们可以把上下文看作是一个容器,用于存放Action执行时需要使用的对象信息,例如请求的参数(Parameter)、会话(Session)、Servlet上下文(ServletContext)等。在每次请求执行Action之前都会创建新的ActionContext。保存到ActionContext对象中的数据可以通过Struts2标签和OGNL表达式语言进行访问。

2. StackContext对象

StackContext对象是ActionContext上下文中的一个类型为java.utiI.Stack的实例。上面提到的请求参数(Parameter)、会话(Session)、Servlet上下文(ServletContext)等对象,实际上都存储在ActionContext上下文中的StackContext对象中。

3. ValueStack对象

Struts2会为每一次Action的请求创建与之对应的ValueStack,并将所有Action属性数据存储到ValueStack中,再将ValueStack 暴露给视图页面,这样页面就可以直接访问Action中的属性值。

 

6.1.2 使用OGNL

OGNL即(Object-Graph Navigation Language),是对象图导航语言的缩写,它是一个开源项目,工作在视图层,用来取代页面中的Java脚本,简化数据访问操作。

OGNL一种EL功能强大的表达式语言。通过其简单一致的表达式语法,可以存取对象的属性、调用对象的方法、遍历以及进行类型转换等功能。Struts 2框架默认使用OGNL作为表达式语言。

1. 访问上下文中的数据

ActionContextStruts 2OGNL的上下文环境,即ActionContext中的数据(实际存储在StackContext中)都可以通过OGNL来访问。而ActionContext又包括RequestSessionValueStack等对象,所以通过OGNL也可以访问存储在这些对象中的数据。

ValueStackOGNL的根,同时由于OGNL上下文中的根对象可以直接访问,所以通过OGNL访问ValueStack中的数据时,不需要使用任何特殊的标记,而访问ActionConext中的其他对象时则需要使用#标记。Struts 2中提供了<s:property>标签来显示OGNL上下文中的数据,在实际应用中通常分为以下四种情况:

1<s:property  value=”uid”>: Struts2会在ValueStack中查找名为uid的项,并输出其值。

2<s:property  value=”#uid”>: Struts2会在StackContext中查找名为uid的项,并输出其值。

3<s:property  value=”#session.uid”>: Struts2会在StackContcxt中的Session作用域中查找名为uid的项,并输出其值。这里的session也可以更换为requestapplication,以便在RequestApplication作用域中查找指定的项。

4) <s:property  value =”#attr.uid”/>: Struts2会依次在StackContextPageRequestSessionApplication作用域内查找对应的uid中的值。

2. 访问JavaBean属性

通过OGNL可以非常方便的访问JavaBean,假设现在ValueStack中存在StudentAction,该Action的属性有nameage等。

(1) <s:property value=”name”>Struts2会执行StudentAction对象的getName()方法来获得并输出name属性的值

(2) <s:property value=”age”>Struts2会执行StudentAction对象的getAge()方法来获得并输出age属性的值

由于ValueStackOGNL的根,所以此时在使用<s:property>标签时无需“#”标记。

3.  执行JavaBean方法

OGNL不仅可以自动执行getter方法,而且能够执行JavaBean的其他方法。更重要的是,还能够在执行方法的时候传入参数,OGNL执行的方法可以是静态方法和非静态方法。执行静态方法的格式为:@类的全类名@方法名(参数)。为了能够让OGNL执行静态方法,还必须在struts.xml配置文件中配置常量参数,才可以开启OGNL调用静态方法的功能,配置代码如下:

<constantname="struts.ognl.allowStaticMethodAccess" value="true" />

示例6.1演示了使用OGNL执行JavaBean方法。

示例6.1

(1)创建JavaBean ,命名为“OgnlInfo.java”。

[java] view plain copy
  1. public class OgnlInfo {   
  2. //定义静态方法  
  3. public static String sayBye(String name)  
  4. {  
  5. return name + "再见!";  
  6. }  
  7. //定义非静态方法  
  8. public String sayHello(String name)  
  9. {  
  10. return name + "你好!";  
  11. }  
  12. }  

(2)创建index.jsp

 

[html] view plain copy
  1. <body>  
  2.     <%  
  3.         //实例化ognl对象  
  4.         OgnlInfo ognlInfo = new OgnlInfo();  
  5.         //将ognlinfo对象存入request作用域内  
  6.         request.setAttribute("ognlInfo",ognlInfo);    
  7.       
  8.       
  9.     %>  
  10.     <!-- 执行ognl对象非静态方法 -->  
  11.     <s:property value="#request.ognlInfo.sayHello('jack')"/>  
  12.     <!-- 执行ognl对象静态方法 -->  
  13.     <s:property value="@[email protected]('tom')"/>  
  14.    
  15.   </body>  

4.   OGNL操作符

OGNL表达式中能使用的操作符基本与Java中的操作符相同,除了能使用+、—、*/==!==等操作符之外,还能使用mod(取余)、innot in等操作符。

5. “%”号

%”号用于对属性为字符串类型的OGNL表达式的值进行计算,“%”符号在OGNL中的使用方法如下:

<body>

<%

String value="确定";

pageContext.setAttribute("val", value);

%>

不使用%符号,会按原样显示<br>

<s:submit value="#attr.val"/>

<br>

使用%符号,会计算OGNL表达式的值<br>

<s:submit value="%{#attr.val}"/>

</body>

运行结果如图6.1.2所示。

Struts2标签库和OGNL 

6.1.2 %的使用

6. OGNL的集合操作

1)生成List类型的集合。具体语法为{e1,e2,e3,...}。此语法将直接生成一个list类型集合,该集合包含3个元素:e1,e2,e3。如果需要更多的元素,则多个元素之间以英文逗号隔开。

2)生成Map类型的集合。具体语法为#{key1,key2,key3...}。此语法将直接生成一个Map类型集合,该Map中每个key-value对象之间以英文冒号隔开,如果需要更多的元素,则多个元素之间以英文逗号隔开。

3)使用innot in 运算符。对于集合,OGNL提供元素符innot in。其中,in用于判断某个元素是否在指定集合内;not in 则用于判断某个元素是否不在指定的集合中。In和 not in 的用法如下:

<!-- 判断java是否在指定集合中-->

<s:if test="'java' in {'java','jsp','html'}">

存在

<s:else>

不存在

</s:else>

</s:if>

(4)   获取集合的子集。OGNL允许通过某个规则取得集合的子集,取得子集时有以下三种操作符:

1)“?”操作符:取出所有符合选择逻辑的元素。

2)“^”操作符:取出符合选择逻辑的第一个元素。

3)“$”操作符:取出符合选择逻辑的最后一个元素。

假设现在Session中存在名为StudentList的集合,该集合存储了多个Student对象。Student类中存在一个age属性,这三种操作的语法如下:

#session.StudentList.{?#this.age>20}用于取出年龄大于20的子集合。

#session.StudentList.{^#this.age>20}用于取出第一个年龄大于20Student对象。

#session.StudentList.{$#this.age>20}用于取出最后一个年龄大于20Student对象。

6.2 Struts 2的标签库

Struts 2作为一个优秀的MVC框架,它为开发人员提供了一个功能强大、支持广泛、高扩展性的标签库,完全能满足Web页面复杂、多变的需求。

Struts 2的标签库大大简化了视图页面的代码编辑工作,提高了视图页面的维护效率。与Struts 1的标签库相比,Struts 2的标签库不但功能强大,而且更加简单易用。

Struts 1的标签库中,它分别提供了htmlbeanlogic等几个标签库。Struts 2标签库并没有严格的对标签进行分类,而是把所有标签整合到了一个标签库中。为了使初学者对Struts 2标签库能有更加清晰的认识,我们可以将Struts 2的标签库分成三大类(如图6.1.3所示):

 UI标签:主要用于生成HTML页面元素。

 UI标签:主要用于逻辑控制、数据访问等操作。

 Ajax标签:主要用于支持Ajax访问。

其中又可以把UI标签分为如下两类:

表单标签:主要用于生成HTML中的表单元素。

 非表单标签:主要包含一些常用的功能标签,例如显示日期或树形菜单。

对于非UI标签,也可以再细分为如下两类:

 数据访问标签:主要用于获得或输出ValueStack中的值。

 逻辑控制标签:主要用于数据访问中的条件分支、循环等流程控制。Struts2标签库和OGNL

6.1.3 标签库分类

使用Struts2标签库之前,也需要在JSP页面中导入。现在的Web应用一般都使用Servlet 2.4以上的规范,因此我们就无须在web.xml文件中对标签库进行配置,因为Servlet 2.4以上的规范可以直接读取标签库定义文件(TLD文件),在JSP页面中直接通过下面一行代码就可以导入Struts 2标签库。

<%@ taglib prefix="s" uri="/struts-tags" %>

 

6.2.1 数据访问标签

数据访问标签主要用来获得或输出各种数据的功能,常应用于显示Action中的属性以及国际化输出等场合。常见的数据标签主要包含以下几个:

 action标签:该标签用于在JSP页面中直接调用一个Action 

include标签:该标签用于在JSP页面中包含其他页面资源。

 param标签:该标签用于设置一个参数,通常用作beanurl标签的子标签。

 property标签:该标签用于输出某个值。

 set标签:该标签用于设置一个新变量。

 text标签:该标签用于输出国际化消息。

 url标签:该标签用于生成一个URL地址。

 date标签:该标签用于格式化输出一个日期。

1. action标签

该标签可以在JSP页面中直接调用Action,并可以把执行的结果包含在标签的位置,这时需要指定Actionnamenamespace等属性。下面是该标签的几个主要属性:

 id属性:该属性用来指定被调用的Action的引用ID

 name属性:该属性用来指定被调用的Action的名字。

 namespace属性:该属性用来指定被调用的Action所在的namespace

 executeResult属性:该属性用来指定是否将Action的处理结果包含到当前页面中,该

属性的默认值是false,即不包含。

示例6.2

下面我们通过一个实例来介绍action标签的具体应用,首先编写一个简单的Action类,代码如下所示。

public class TagAction

{

private String name;

//省略getter和setter方法

public String exec()

{

return "ok";

}

}

通过上述代码可以看到该Action只包含了一个exec业务方法。下面是该Actionstruts.xml文件中的配置:

[html] view plain copy
  1. <struts>  
  2.     <package name="struts2_Tags" extends="struts-default"  
  3.      namespace="/tags">        
  4. <action name="tag1" class="com.zy.TagAction" method="exec">  
  5. <result name="ok">succ.jsp</result>  
  6. </action>  
  7.     </package>  
  8. </struts>  

下面是succ.jsp视图文件的代码:

<body>

<br>

调用Action!!

</body>

下面是使用action标签的s-action_Tag.jsp文件,代码如下所示:

<body>

下面调用Action,并将结果包含到本页面中。<br>

<s:action name="tag1" executeResult="true" namespace="/tags"/>

</body>

上述代码使用<s:action />标签调用了名字为tag1的逻辑action,并通过设置executeResult属性为true将结果包含到了本页面中。

Struts2标签库和OGNL 

6.1.4  action标签的应用

2. property标签

该标签的作用就是输出ActionContext中对象的值或者ActionJavaBean的属性值,通常结合OGNL使用。该标签有如下几个属性:

Ø value,该属性用来指定要输出的属性或OGNL表达式。

Ø default,该属性用来指定当value指定的属性值为null时输出的值。

Ø escape,该属性用来指定是否生成HTML代码,默认为true,表示在浏览器上输出表达式的值;如果为false,则把表达式的值作为HTML代码嵌入。

示例6.3

下面是应用property标签的简单示例。

<body>

    <%

     String url="<a href='index.jsp'>超链接</a>";

     pageContext.setAttribute("su",url);

     %>

     <s:property value="#attr.su"/><hr>

     <s:property value="#attr.su" escape="false"/><hr>

     <s:property value="#attr.uid" default="找不到uid"/>

</body>

运行效果如图6.1.5所示。

Struts2标签库和OGNL 

6.1.5 property标签

3. include标签

该标签用来将一个JSPServlet等资源包含到当前页面中,使用起来非常简单。该标签主要包含value属性,用来指定被包含的JSPServlet等资源文件。

示例6.4

接下来通过一个简单的例子来介绍include标签的具体应用,首先是被包含的include-file.jsp页面的代码:

[html] view plain copy
  1. <%@ page contentType="text/html; charset=GBK" language="java"%>  
  2. <%@taglib prefix="s" uri="/struts-tags"%>  
  3. <html>  
  4. <head>  
  5. </head>  
  6. <body>  
  7. ---------------------------  
  8. <h3>这是被包含的页面</h3>  
  9. </body>  
  10. </html>  
  11. 下面是包含include-file.jsp这个页面的s-include_Tag.jsp文件,代码如下所示:  
  12. <%@ page contentType="text/html; charset=utf-8" language="java"%>  
  13. <%@taglib prefix="s" uri="/struts-tags"%>  
  14. <html>  
  15. <head>  
  16. <title>使用include标签来包含目标页面</title>  
  17. </head>  
  18. <body>  
  19. <h2>使用include标签来包含目标页面</h2>  
  20. <s:include value="include-file.jsp"/>  
  21. </body>  
  22. </html>  


上述代码通过使用include标签包含了include-file.jsp页面,运行效果如图6.1.6所示。

Struts2标签库和OGNL 

6.1.6 include标签

4. set标签

该标签用来定义一个变量,并把这个变量放到指定的范围内,例如application范围、session范围等。该标签有以下一些常用属性:

Ø id属性:该属性用来定义变量的名字。

Ø scope属性:该属性用来定义变量被放置的范围,可选的值有applicationsessionrequestresponsepageStackContext

Ø value属性:该属性用来定义将要赋给变量的固定值或者另一个已经定义的变量。

示例6.5

下面我们通过一个示例来介绍set标签的具体应用,首先我们定义一个变量p,并把“小样儿”这个字符串赋值给它,然后定义另一个变量user,并把p赋值给user。代码如下所示:

<body>

<h2>使用set标签设置一个新变量</h2>

<s:set id="p" value="'小样儿'"/>

<s:property value="#attr.p"/><br>

将p变量赋值给user变量并放入session范围内<br>

<s:set value="#p" id="user" scope="session"/>

<s:property value="#session.user"/><br>

</body>

运行效果如图6.1.7所示。

Struts2标签库和OGNL 

6.1.7 set标签的应用

5. url标签

该标签用来生成一个URL地址,我们也可以通过嵌套param标签来为URL指定发送参数。该标签主要有以下一些常用属性:

Ø includeParams属性:该属性用来指定是否在生成的URL参数中追加本页面接收到的请求参数,有3个值可供选择,none getall,分别代表“不包含”、“包含get方法传递的参数”和“所有的参数”。

Ø value属性:该属性用来指定要生成的URL的地址值。

Ø action属性:该属性用来指定一个Action作为URL地址值。

Ø namespace属性:该属性用来指定命名空间。

Ø method属性:该属性用来指定调用Action的方法名。

Ø includeContext属性:该属性用来指定是否把当前上下文包含在URL地址值中。

在上述属性中,actionvalue属性只需指定其一即可,如果两个都未指定,就以当前页面作为URL地址值。下面是一个应用URL标签的示例。

示例6.6

[html] view plain copy
  1. <body>  
  2. <h3>使用url标签</h3>  
  3. <hr>  
  4. 指定action属性,且使用param标签传入参数。<br>  
  5. <s:url action="showPerson">  
  6.     <s:param name="name" value="'Jack'" />  
  7. </s:url>  
  8. <hr>  
  9. 指定value属性,且使用param标签传入参数。<br>  
  10. <s:url value="http://localhost:8080/firstStruts2/news.jsp">  
  11.     <s:param name="name" value="'Jack'" />  
  12. </s:url>  
  13. </body>  


该页面的运行效果如图6.1.8所示。

 Struts2标签库和OGNL

6.1.8 URL标签的应用

6. date标签

date标签用来按指定的格式输出一个日期,还可以计算指定日期到当前时间的时差。该标签主要有如下一些属性:

Ø format属性:该属性用来指定日期输出的格式,例如“yyyy-MM-dd”。

Ø name属性:该属性用来指定要被格式化输出的日期值。

示例6.7

我们看下面的实例代码,用“年//日”的完整格式显示当前日期:

[html] view plain copy
  1. <body>  
  2. <h3>date标签的使用</h3>  
  3. <%  
  4. java.util.Date now = new java.util.Date();  
  5. pageContext.setAttribute("now" , now);  
  6. %>  
  7. <s:date name="#attr.now" format="yyyy/MM/dd" nice="false"/><hr><br>  
  8. </body>  


该页面的运行效果如图6.1.9所示。

Struts2标签库和OGNL 

6.1.9 date标签的使用

7. <s:bean>标签

<s:bean>用来创建JavaBean实例,创建JavaBean实例的时候,可以在该标签内部使用<param/>标签为该JavaBean实例传入属性。其常见属性如下:

Ø Id:指定创建JavaBean的引用id.

Ø name:指定需要实例化的JavaBean的实现类

<s:bean>标签用法的如下:

(1) 创建JavaBean,命名为Book.java

[java] view plain copy
  1. public class Book {   
  2. private String isbn;  
  3. private String name;  
  4. private double price;  
  5. public Book() {  
  6. super();  
  7. }  
  8. public Book(String isbn, String name, double price) {  
  9. super();  
  10. this.isbn = isbn;  
  11. this.name = name;  
  12. this.price = price;  
  13. }  
  14. public String[] getAllBooks()  
  15. {  
  16. String[] books = {"JAVA","JSP","ASP.NET","C#"};  
  17. return books;  
  18. }  
  19. }  

(2) 创建Jsp页面.

<!-- 实例化book JavaBean对象,并存储到StackContext中 -->

<s:bean id="book" name="com.zzab.entity.Book">

<s:param name="isbn" value="'621345'"/>

<s:param name="name" value="'HTML'"/>

</s:bean>

<!-- 输出bean对象的值 -->

book对象属性值:<br>

isbn:<s:property value="#book.isbn"/><br/>

name:<s:property value="#book.name"/><br/>

调用book对象的getAllBooks方法获取全部书籍列表:<br/>

<c:forEach var="book" items="${book.allBooks}">

<div>${book }</div>

</c:forEach>

[html] view plain copy
  1. <s:bean id="book" name="com.zzab.entity.Book">  
  2. <s:param name="isbn" value="'621345'"/>  
  3. <s:param name="name" value="'HTML'"/>  
  4. </s:bean>  
  5. <!-- 输出bean对象的值 -->  
  6. book对象属性值:<br>  
  7. isbn:<s:property value="#book.isbn"/><br/>  
  8. name:<s:property value="#book.name"/><br/>  
  9. 调用book对象的getAllBooks方法获取全部书籍列表:<br/>  
  10. <c:forEach var="book" items="${book.allBooks}">  
  11. <div>${book }</div>  
  12. </c:forEach>  


6.2.2 逻辑控制标签

Struts 2的逻辑控制标签主要用于程序流程的逻辑控制,例如选择、分支、循环等操作,常见的逻辑控制标签主要有以下五个标签:

Ø if标签:用于控制选择流程的标签。

Ø elseif标签:与if标签结合使用。

Ø else标签:与if标签结合使用。

Ø generator标签,用于将一个字符串解析成一个集合。

Ø iterator标签:这是一个迭代器,用于将集合进行循环输出。

 

1. if/elseif/else标签

if/elseif/else这三个标签通常结合使用,都是用于进行程序分支逻辑控制,跟多数编程语言中的if/elseif/else语句的功能相似,test属性用来设置比较表达式,具体语法如下所示:

<s:if test="表达式">

标签体

<s:elseif test="表达式">

标签体

<s:else>

标签体

</s:else>

下面是一个实例的代码片段:

示例6.8

[html] view plain copy
  1. <s:set name="dengji" value="85"/>  
  2. <s:if test="#dengji>=90">  
  3.     成绩优秀  
  4. </s:if>  
  5. <s:elseif test="#dengji>=80">  
  6.     成绩良好  
  7. </s:elseif>  
  8. <s:elseif test="#dengji>=60">  
  9. 成绩合格  
  10. </s:elseif>  
  11. <s:else>  
  12.     成绩不合格  
  13. </s:else>  


上述代码先通过set标签定义了一个名为dengji的属性并赋值为85,然后通过if/elseif/else标签根据dengji属性的值的范围来控制输出成绩的评价是“优秀”、“良好”、“合格”或“不合格”。运行效果如图6.1.10所示。

Struts2标签库和OGNL 

6.1.10 if/elseif/else标签的应用

 

2. iterator标签

该标签主要用于对集合类型的变量进行迭代输出,这里的集合类型包括ListSet、数组和Map等。该标签主要有三个属性:

Ø value属性:该属性用来指定被迭代输出的集合,被迭代的集合可以由OGNL表达式指

定也可以通过Action返回一个集合类型的变量。

Ø id属性:该属性用来指定集合中元素的ID属性。

Ø status属性:该属性可以实现一些附加功能,详见后面讲解。

下面是一个实例的代码片段:

示例6.9

<h3>iterator的用法</h3>

 <%

  List bookList=new ArrayList();

  bookList.add("Spring3.0技术宝典");

  bookList.add("Struts2权威指南");

  bookList.add("JavaScript技术大全");

  bookList.add("JSP技术详解");

  bookList.add("Ajax实战");

  pageContext.setAttribute("bookList",bookList);

  %>

 <s:iterator value="#attr.bookList" id="bookname">

 <li><s:property value="bookname" /></li>

 </s:iterator>

上述代码通过iterator标签的value属性指定了一个集合,并指定它的id属性为bookname,然后就可以通过<s:property value="bookname" />输出集合中每个元素的值。该页面的运行效果如图6.1.11所示。

Struts2标签库和OGNL 

6.1.11 iterator标签的应用

iterator标签的status属性很有用,利用它可以实现一些很实用的功能。指定该属性后,每次迭代都会以此属性为名称创建一个IteratorStatus的实例对象,该实例对象包含了以下几个属性:

Ø count:返回当前迭代了几个元素。

Ø index:返回当前迭代元素在集合中的索引值。

Ø even:返回当前迭代元素的索引值是否为偶数。

Ø odd:返回当前迭代元素的索引值是否为奇数。

Ø first:返回当前迭代元素是否是第一个元素。

Ø last:返回当前迭代元素是否是最后一个元素。

我们看下面的代码片段:

<table border="1" width="200">

 <s:iterator value="#attr.bookList" id="name" status="st">

<tr <s:if test="#st.odd">style="background-color:#bbbbbb"</s:if>>

<td><s:property value="#st.index"/></td>

<td><s:property value="name"/></td>

</tr>

 </s:iterator>

</table>

上述代码以表格的形式输出了集合中的每个元素和元素的索引值,并通过iterator标签的status属性控制奇数行的背景色,运行效果如图6.1.12所示。

Struts2标签库和OGNL 

6.1.12 status属性的应用

 

 

3. generator标签

 

该标签可以将一个字符串按指定的分隔符分隔成多个子串,新生成的多个子串可以使用iterator标签进行迭代输出。generator标签常见的属性如下:

Ø count属性:该属性用来指定所生成集合中元素的总数。

Ø separator属性:该属性用来指定分隔符。

Ø converter属性:该属性指定了一个转换器,该转换器负责将集合中的每个字符串转换成

对象。

Ø id属性:如果指定了该属性,则新生成的集合会以此为名称,被放在pageContext中。

我们来看下面的代码片段:

示例6.10

<s:generator val="'Spring技术宝典,Ajax实战,Struts2权威指南,JSP技术详解,

JavaScript技术大全'" separator="," id="generList"/>

<table border="1" width="320">

<caption>迭代输出由generator标签产生的集合</caption>

 <s:iterator value="#attr.generList" id="name" status="st">

<tr>

<td><s:property value="#st.index"/></td>

<td><s:property value="name"/></td>

</tr>

 </s:iterator>

</table>

上述代码使用generator标签把一个字符串按逗号进行了分割,并把产生的集合按照指定的“generList”为id保存在pageContext中,接下来使用iterator标签迭代输出generList集合中的元素,运行效果如图6.1.13所示。

Struts2标签库和OGNL 

6.1.13 generator标签的应用

 

 


本章总结

Ø ActionContext对象。ActionContextcom.opensymphony.xwork.ActionContext)是Action执行时的上下文。我们可以把上下文看作是一个容器,用于存放Action执行时需要使用的对象信息。

Ø StackContext对象。请求参数(Parameter)、会话(Session)、Servlet上下文(ServletContext)等对象,实际上都存储在ActionContext上下文中的StackContext对象中。

Ø ValueStack对象。Struts2会为每一次Action的请求创建与之对应的ValueStack,并将所有Action属性数据存储到ValueStack中,再将ValueStack 暴露给视图页面,这样页面就可以直接访问Action中的属性值。

Ø OGNL即(Object-Graph Navigation Language),是对象图导航语言的缩写,它是一个开源项目,工作在视图层,用来取代页面中的Java脚本,简化数据访问操作。

1访问上下文中的数据。ValueStackOGNL的根,同时由于OGNL上下文中的根对象可以直接访问,所以通过OGNL访问ValueStack中的数据时,不需要使用任何特殊的标记,而访问ActionConext中的其他对象时则需要使用#标记

2)执行JavaBean方法。OGNL不仅可以自动执行getter方法,而且能够执行JavaBean的其他方法。更重要的是,还能够在执行方法的时候传入参数,OGNL执行的方法可以是静态方法和非静态方法。

Ø Struts 2的标签库

1Struts2标签库的分类。我们可以将Struts 2的标签库分成三大类:UI、非UIajax标签,其中UI标签又可分为表单 、非表单标签,非UI标签可分为数据访问、逻辑控制标签。

2)数据访问标签。常见的数据标签主要包含action、includeparam propertysettexturldate等。

3)逻辑控制标签。逻辑控制标签主要用于程序流程的逻辑控制,例如选择、分支、循环等操作,常见的逻辑控制标签主要有五个标签:if elseif、 else generator iterator


任务实训部分

1:查询管理员

训练技能点

Ø OGNL

Ø property标签

Ø iterator标签

  需求说明

在前面章节的任务实训部分,我们实现了管理员的增、删、改、查等功能,现在要求在查询管理员时,使用OGNLiteratorproperty等标签显示查询到的管理员列表,并且只显示密码长度小于3的管理员信息。

  关键代码

<s:iterator value="#attr.adminList.{?#this.pwd.length()>3}" id="admin">

   <tr>

     <td align="center"><s:property value="id"/></td>

     <td align="center"><s:property value="name"/></td>

     <td align="center"><s:property value="pwd"/></td>

   </tr>

</s:iterator>

2:查询图书

训练技能点

Ø OGNL

Ø property标签

Ø iterator标签

  需求说明

在前面章节的任务实训部分,我们实现了查询图书的案例,现在要求使用OGNLiteratorproperty等标签显示查询到的图书列表,并且设置偶数行的背景色为灰色。

3:查找客户信息

训练技能点

Ø OGNL

Ø 数据访问标签

Ø 控制标签

  需求说明

实现输入客户编号时,查找对应的客户是否存在,若不存在,则输出无法查找到此客户的提示;若存在,则进一步显示客户的订单信息。

 

 

  实现思路

(1) 创建用于描述订单的实体类,命名为Order.java

 

public class Order implements Serializable{

//订单Id

private String orderId;

//订单日期

private Date orderDtm;

//订单状态 0:禁用 1:启用

private int state;

//无参构造函数

public Order() {

super();

// TODO Auto-generated constructor stub

}

//有参构造函数

public Order(String orderId, Date orderDtm, int state) {

super();

this.orderId = orderId;

this.orderDtm = orderDtm;

this.state = state;

}

//getter setter省略......

}

(2) 创建用于描述客户的实体类,命名为Cust.java

public class Cust implements Serializable{

//客户编号

private String custId;

//客户名称

private String custName;

//电话

private String tel;

//订单集合

private List<Order> orders = new ArrayList<Order>();

//无参构造函数

public Cust() {

super();

// TODO Auto-generated constructor stub

}

//有参构造函数

public Cust(String custId, String custName, String tel) {

super();

this.custId = custId;

this.custName = custName;

this.tel = tel;

}

//getter setter省略......

}

(3) 创建用于处理业务逻辑的JavaBean,命名为CustService.java

public class CustService {

//定义客户列表

private static List<Cust> custList = new ArrayList<Cust>();

//静态构造器,初始化客户和订单信息

static{

try {

//用于格式化日期

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

//创建客户c1

Cust c1 = new Cust("c001", "张三", "110");

Order c1Order1  = new Order("OR001", sdf.parse("2012-01-01"), 0);

Order c1Order2  = new Order("OR002", sdf.parse("2012-01-02"), 0);

Order c1Order3  = new Order("OR003", sdf.parse("2012-01-03"), 1);

//添加订单到c1客户

c1.getOrders().add(c1Order1);

c1.getOrders().add(c1Order2);

c1.getOrders().add(c1Order3);

//创建客户c2

Cust c2 = new Cust("c002", "李四", "114");

Order c2Order1  = new Order("OR004", sdf.parse("2012-01-04"), 0);

Order c2Order2  = new Order("OR005", sdf.parse("2012-01-05"), 0);

Order c2Order3  = new Order("OR006", sdf.parse("2012-01-06"), 1);

//添加订单到c2客户

c2.getOrders().add(c2Order1);

c2.getOrders().add(c2Order2);

c2.getOrders().add(c2Order3);

//创建客户c3

Cust c3 = new Cust("c003", "王五", "119");

Order c3Order1  = new Order("OR007", sdf.parse("2012-01-07"), 0);

Order c3Order2  = new Order("OR008", sdf.parse("2012-01-08"), 0);

Order c3Order3  = new Order("OR009", sdf.parse("2012-01-09"), 1);

//添加订单到c3客户

c3.getOrders().add(c3Order1);

c3.getOrders().add(c3Order2);

c3.getOrders().add(c3Order3);

//把客户添加到List列表中

custList.add(c1);

custList.add(c2);

custList.add(c3);

} catch (ParseException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

}

//

public static Cust findCustById(String custId){

//循环每个客户

for (Cust cust : custList) {

//循环每个客户

if(cust.getCustId().equals(custId)){

return cust;

}

}

//如果找不到则返回空

return null;

}

//

public static List<Order> getCustOrders(String custId){

//循环每个客户

for (Cust cust : custList) {

//循环每个客户

if(cust.getCustId().equals(custId)){

//返回对应客户的订单

return cust.getOrders();

}

}

//如果找不到则返回空

return null;

}

}

(4) 创建用于处理业务逻辑的控制器Action,命名为CustAction.java

public class CustAction extends ActionSupport {

//封装用户的id

private String custId;

//查找订单

public String findOrder()throws Exception{

//调用业务层

List<Order> orderList = CustService.getCustOrders(custId);

//将订单放到request

ServletActionContext.getRequest().setAttribute("orderList", orderList);

//返回input逻辑视图

return SUCCESS;

}

/**

 * @return

 */

public String findCust() {

// TODO Auto-generated method stub

//调用业务逻辑

Cust cust = CustService.findCustById(custId);

if(cust!=null){

//cust存储到session

ServletActionContext.getRequest().getSession().setAttribute("cust", cust);

}

else{

//否则给msg赋值,准备弹出对话框。

ServletActionContext.getRequest().setAttribute("msg","<script>alert('没有此用户');</script>");

}

//返回input逻辑视图

return SUCCESS;

}

//getter setter方法

public String getCustId() {

return custId;

}

public void setCustId(String custId) {

this.custId = custId;

}

}

(5) 创建Jsp页面,命名为jd1.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@ taglib uri="/struts-tags" prefix="s" %>

<%

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>

   

    <title>My JSP 'jd1.jsp' starting page</title>

    

  </head>

  

  <body>

    <h2>

    <form action="custaction!findCust.action" method="post">

    完成客户查找功能:<hr>

    客户编号:<input type="text" name="custId"> <br/>

    <input type="submit" value="查找">

    <!-- 如果找到该用户 -->

    <s:if test="#session.cust">

    <hr/>

    编号:${cust.custId}<br/>

    姓名:${cust.custName}<br/>

    联系方式:${cust.tel}<br/><a href="custaction!findOrder.action?custId=${cust.custId }">查看订单</a>

    <hr/>

    </s:if>

    <!-- 如果存在订单列表 -->

    <s:if test="#request.orderList">

    <hr/>

    <table border="1">

    <tr>

    <td>订单编号</td>

    <td>订单日期</td>

    <td>订单状态</td>

    </tr>

    <s:iterator id="row" value="#request.orderList">

    <tr>

    <td>${row.orderId }</td>

    <td><s:date name="#row.orderDtm" format="yyyyMMdd"/></td>

    <td>${row.state==0?"禁用""启用" }</td>

   

    </tr>

    </s:iterator>

    </table>

   

    </s:if>

    </form>

   

    </h2>

    <!-- 执行msg -->

    ${msg }

  </body>

</html>

(6) 配置Struts.xml文件。

<struts>

<!-- 配置字符集 -->

<constant name="struts.i18n.encoding" value="utf-8"></constant>

<!-- 配置主题 -->

<constant name="struts.ui.theme" value="simple"></constant>

<package name="test" extends="struts-default">

<action name="custaction" class="com.zzzy.web.CustAction">

<result >/jd1.jsp</result>

</action>

</package>

</struts>

(7) 运行jd1.jsp页面,效果如图6.2.1所示。

Struts2标签库和OGNL 

6.2.1 运行jd1.jsp

在图6.2.1中输入需要查找的客户编号。

若编号不存在,系统将会显示提示消息。 如图6.2.2所示。

 Struts2标签库和OGNL

6.2.2 用户不存在

若编号存在,系统将显示该客户对应的详细信息,如图图6.2.3所示。

 Struts2标签库和OGNL

6.2.3 查找客户并显示详细信息

在图6.2.3中单击“查看订单”按钮,系统将显示客户对应的订单信息,如图6.2.4所示。

 Struts2标签库和OGNL

6.2.4显示客户的订单信息


巩固练习

一、选择题

1. 以下关于OGNL的说法正确的是()。

A. ActionContextOGNL的上下文环境

B. ValueStackOGNL的根

C. StackContextOGNL的上下文环境

D. ActionContextOGNL的根

2. 假设session中存在名为uid的属性,通过OGNL访问该属性的代码是()。

A. #uid

E. uid

F. #session.uid

G. ${session.uid}

3. 关于“#session.users.{?#this.age>20}”的OGNL代码所表示的意思是()。

A. users集合中取出第一个年龄大于20的对象

H. users集合中取出所有年龄大于20的对象

I. users集合中取出最后一个年龄大于20的对象

J. 该代码有语法错误

4. 假设页面中存在这样一行代码“<s:property />”,则下面说法正确的是()。

A. 编译错误

K. 页面不显示任何内容

L. 输出ValueStack中最上面的对象

M. 以上说法都不正确

5. 以下()不属于Struts 2的数据访问标签。

A. set

B. date

C. text

D. textfield