Struts 2标签库
OGNL
能力目标
熟练使用Struts 2常用标签
熟练使用OGNL
本章简介
前面我们编写的案例使用的都是HTML标签,这些标签并不能很好的与Struts 2框架结合,Struts 2和Struts 1一样都自带了功能强大、成熟完善的标签库供我们使用,通过使用这些标签库可以大大提高开发效率和代码的可维护性。
其实Struts 2的标签库是建立在OGNL基础上的,OGNL是一种功能强大的表达式语言,通过简单的语法即可存取对象的属性、调用对象的方法、遍历等功能。
本章将学习OGNL和Struts 2标签库,包括数据访问标签、控制标签
核心技能部分
6.1 OGNL
6.1.1 ActionContext
Struts 2中的ActionContext、ValueStack和StackContext对象与OGNL密切相关,理解这三个对象时学习OGNL的前提。
在前面的学习中,我们已经在使用ActionContext、ValueStack和StackContext对象了,这三个对象的作用及其之间的关系如图6.1.1所示。
图6.1.1 ActionContext
1. ActionContext对象
ActionContext(com.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. 访问上下文中的数据
ActionContext是Struts 2中OGNL的上下文环境,即ActionContext中的数据(实际存储在StackContext中)都可以通过OGNL来访问。而ActionContext又包括Request、Session、ValueStack等对象,所以通过OGNL也可以访问存储在这些对象中的数据。
ValueStack是OGNL的根,同时由于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也可以更换为request和application,以便在Request和Application作用域中查找指定的项。
(4) <s:property value =”#attr.uid”/>: Struts2会依次在StackContext的Page、 Request、Session、Application作用域内查找对应的uid中的值。
2. 访问JavaBean属性
通过OGNL可以非常方便的访问JavaBean,假设现在ValueStack中存在StudentAction,该Action的属性有name、age等。
(1) <s:property value=”name”/>:Struts2会执行StudentAction对象的getName()方法来获得并输出name属性的值
(2) <s:property value=”age”/>:Struts2会执行StudentAction对象的getAge()方法来获得并输出age属性的值
由于ValueStack是OGNL的根,所以此时在使用<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(取余)、in、not 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所示。
图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)使用in和not in 运算符。对于集合,OGNL提供元素符in与not 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}用于取出第一个年龄大于20的Student对象。
#session.StudentList.{$#this.age>20}用于取出最后一个年龄大于20的Student对象。
6.2 Struts 2的标签库
Struts 2作为一个优秀的MVC框架,它为开发人员提供了一个功能强大、支持广泛、高扩展性的标签库,完全能满足Web页面复杂、多变的需求。
Struts 2的标签库大大简化了视图页面的代码编辑工作,提高了视图页面的维护效率。与Struts 1的标签库相比,Struts 2的标签库不但功能强大,而且更加简单易用。
在Struts 1的标签库中,它分别提供了html、bean、logic等几个标签库。Struts 2标签库并没有严格的对标签进行分类,而是把所有标签整合到了一个标签库中。为了使初学者对Struts 2标签库能有更加清晰的认识,我们可以将Struts 2的标签库分成三大类(如图6.1.3所示):
UI标签:主要用于生成HTML页面元素。
非UI标签:主要用于逻辑控制、数据访问等操作。
Ajax标签:主要用于支持Ajax访问。
其中又可以把UI标签分为如下两类:
表单标签:主要用于生成HTML中的表单元素。
非表单标签:主要包含一些常用的功能标签,例如显示日期或树形菜单。
对于非UI标签,也可以再细分为如下两类:
数据访问标签:主要用于获得或输出ValueStack中的值。
逻辑控制标签:主要用于数据访问中的条件分支、循环等流程控制。
图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标签:该标签用于设置一个参数,通常用作bean、url标签的子标签。
property标签:该标签用于输出某个值。
set标签:该标签用于设置一个新变量。
text标签:该标签用于输出国际化消息。
url标签:该标签用于生成一个URL地址。
date标签:该标签用于格式化输出一个日期。
1. action标签
该标签可以在JSP页面中直接调用Action,并可以把执行的结果包含在标签的位置,这时需要指定Action的name和namespace等属性。下面是该标签的几个主要属性:
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业务方法。下面是该Action在struts.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将结果包含到了本页面中。
图6.1.4 action标签的应用
2. property标签
该标签的作用就是输出ActionContext中对象的值或者Action、JavaBean的属性值,通常结合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所示。
图6.1.5 property标签
3. include标签
该标签用来将一个JSP或Servlet等资源包含到当前页面中,使用起来非常简单。该标签主要包含value属性,用来指定被包含的JSP或Servlet等资源文件。
示例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所示。
图6.1.6 include标签
4. set标签
该标签用来定义一个变量,并把这个变量放到指定的范围内,例如application范围、session范围等。该标签有以下一些常用属性:
Ø id属性:该属性用来定义变量的名字。
Ø scope属性:该属性用来定义变量被放置的范围,可选的值有application、session、request、response、page和StackContext。
Ø 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所示。
图6.1.7 set标签的应用
5. url标签
该标签用来生成一个URL地址,我们也可以通过嵌套param标签来为URL指定发送参数。该标签主要有以下一些常用属性:
Ø includeParams属性:该属性用来指定是否在生成的URL参数中追加本页面接收到的请求参数,有3个值可供选择,none, get和all,分别代表“不包含”、“包含get方法传递的参数”和“所有的参数”。
Ø value属性:该属性用来指定要生成的URL的地址值。
Ø action属性:该属性用来指定一个Action作为URL地址值。
Ø namespace属性:该属性用来指定命名空间。
Ø method属性:该属性用来指定调用Action的方法名。
Ø includeContext属性:该属性用来指定是否把当前上下文包含在URL地址值中。
在上述属性中,action和value属性只需指定其一即可,如果两个都未指定,就以当前页面作为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所示。
图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所示。
图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所示。
图6.1.10 if/elseif/else标签的应用
2. iterator标签
该标签主要用于对集合类型的变量进行迭代输出,这里的集合类型包括List、Set、数组和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所示。
图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所示。
图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所示。
本章总结
Ø ActionContext对象。ActionContext(com.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)访问上下文中的数据。ValueStack是OGNL的根,同时由于OGNL上下文中的根对象可以直接访问,所以通过OGNL访问ValueStack中的数据时,不需要使用任何特殊的标记,而访问ActionConext中的其他对象时则需要使用“#”标记。
(2)执行JavaBean方法。OGNL不仅可以自动执行getter方法,而且能够执行JavaBean的其他方法。更重要的是,还能够在执行方法的时候传入参数,OGNL执行的方法可以是静态方法和非静态方法。
Ø Struts 2的标签库
(1)Struts2标签库的分类。我们可以将Struts 2的标签库分成三大类:UI、非UI、ajax标签,其中UI标签又可分为表单 、非表单标签,非UI标签可分为数据访问、逻辑控制标签。
(2)数据访问标签。常见的数据标签主要包含action、include、param 、property、set、text、url、date等。
(3)逻辑控制标签。逻辑控制标签主要用于程序流程的逻辑控制,例如选择、分支、循环等操作,常见的逻辑控制标签主要有五个标签:if 、elseif、 else 、generator 、iterator。
任务实训部分
1:查询管理员
训练技能点
Ø OGNL
Ø property标签
Ø iterator标签
需求说明
在前面章节的任务实训部分,我们实现了管理员的增、删、改、查等功能,现在要求在查询管理员时,使用OGNL和iterator、property等标签显示查询到的管理员列表,并且只显示密码长度小于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标签
需求说明
在前面章节的任务实训部分,我们实现了查询图书的案例,现在要求使用OGNL和iterator、property等标签显示查询到的图书列表,并且设置偶数行的背景色为灰色。
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="yyyy年MM月dd日"/></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所示。
图6.2.1 运行jd1.jsp
在图6.2.1中输入需要查找的客户编号。
若编号不存在,系统将会显示提示消息。 如图6.2.2所示。
图6.2.2 用户不存在
若编号存在,系统将显示该客户对应的详细信息,如图图6.2.3所示。
图6.2.3 查找客户并显示详细信息
在图6.2.3中单击“查看订单”按钮,系统将显示客户对应的订单信息,如图6.2.4所示。
图6.2.4显示客户的订单信息
巩固练习
一、选择题
1. 以下关于OGNL的说法正确的是()。
A. ActionContext是OGNL的上下文环境
B. ValueStack是OGNL的根
C. StackContext是OGNL的上下文环境
D. ActionContext是OGNL的根
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