学习内容

 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_java


图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会依次在StackContextPage、 RequestSessionApplication作用域内查找对应的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”。


public class OgnlInfo {//定义静态方法public static String sayBye(String name){return name + "再见!";}//定义非静态方法public String sayHello(String name){return name + "你好!";}}


(2)创建index.jsp

 

<body><%    	//实例化ognl对象    	OgnlInfo ognlInfo = new OgnlInfo();    	//将ognlinfo对象存入request作用域内    	request.setAttribute("ognlInfo",ognlInfo);              %><!-- 执行ognl对象非静态方法 --><s:property value="#request.ognlInfo.sayHello('jack')"/><!-- 执行ognl对象静态方法 --><s:property value="@com.zzab.entity.OgnlInfo@sayBye('tom')"/></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_java_02 

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_java_03


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文件中的配置:


<struts><package name="struts2_Tags" extends="struts-default"namespace="/tags"><action name="tag1" class="com.zy.TagAction" method="exec"><result name="ok">succ.jsp</result></action></package></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_java_04 

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_java_05 

6.1.5 property标签

3. include标签

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

示例6.4

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


<%@ page contentType="text/html; charset=GBK" language="java"%><%@taglib prefix="s" uri="/struts-tags"%><html><head></head><body>---------------------------<h3>这是被包含的页面</h3></body></html>下面是包含include-file.jsp这个页面的s-include_Tag.jsp文件,代码如下所示:<%@ page contentType="text/html; charset=utf-8" language="java"%><%@taglib prefix="s" uri="/struts-tags"%><html><head><title>使用include标签来包含目标页面</title></head><body><h2>使用include标签来包含目标页面</h2><s:include value="include-file.jsp"/></body></html>




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

Struts2标签库和OGNL_java_06 

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_java_07 

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


<body><h3>使用url标签</h3><hr>指定action属性,且使用param标签传入参数。<br><s:url action="showPerson"><s:param name="name" value="'Jack'" /></s:url><hr>指定value属性,且使用param标签传入参数。<br><s:url value="http://localhost:8080/firstStruts2/news.jsp"><s:param name="name" value="'Jack'" /></s:url></body>




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

 Struts2标签库和OGNL_java_08

6.1.8 URL标签的应用

6. date标签

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

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

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

示例6.7

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


<body><h3>date标签的使用</h3><%java.util.Date now = new java.util.Date();pageContext.setAttribute("now" , now);%><s:date name="#attr.now" format="yyyy/MM/dd" nice="false"/><hr><br></body>




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

Struts2标签库和OGNL_java_09 

6.1.9 date标签的使用

7. <s:bean>标签

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

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

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

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

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


public class Book {private String isbn;private String name;private double price;public Book() {super();}public Book(String isbn, String name, double price) {super();this.isbn = isbn;this.name = name;this.price = price;}public String[] getAllBooks(){String[] books = {"JAVA","JSP","ASP.NET","C#"};return books;}}


(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>

<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>


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


<s:set name="dengji" value="85"/><s:if test="#dengji>=90">成绩优秀</s:if><s:elseif test="#dengji>=80">成绩良好</s:elseif><s:elseif test="#dengji>=60">成绩合格</s:elseif><s:else>成绩不合格</s:else>




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

Struts2标签库和OGNL_java_10 

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_java_11 

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_java_12 

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_java_13 

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_java_14 

6.2.1 运行jd1.jsp

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

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

 Struts2标签库和OGNL_java_15

6.2.2 用户不存在

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

 Struts2标签库和OGNL_java_16

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

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

 Struts2标签库和OGNL_java_17

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