《研磨struts2》第八章 Struts2的Taglib 之 8.3 控制标签
8.3 控制标签
控制标签关注程序的运行流程,比如用if/else来进行分支控制,用iterator来进行循环控制。接下来就来学习Struts2的控制标签。
8.3.1 if、elseif与else标签
1:if标签的功能:
类似于Java程序中的if,用来表达分支判断。
else标签的功能:
类似于Java程序中的else。
elseif标签的功能:
类似于Java程序中的else if。
2:属性:
if标签和elseif标签都只有一个test属性,它本身是一个OGNL表达式,运算结果为一个boolean值,表示是否符合条件,必须设置。
else标签没有属性。
3:示例:
由于大家对于Java中的if-else是非常熟悉的,因此这里只需要看看,用标签如何来表达即可,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- int length=15;
- request.setAttribute("len",length);
- %>
- <s:if test="#request['len']>=20">
- 您输入的值大于等于20
- </s:if>
- <s:elseif test="#request['len']<=10">
- 您输入的值小于等于10
- </s:elseif>
- <s:else>
- 您输入的值在10与20之间
- </s:else>
8.3.2 iterator标签
1:功能:
iterator标签用来处理循环,可以用它遍历数组、Set和List等集合对象。这个标签还支持在ActionContext中保持一个保存遍历状态的对象,通过这个变量可以得到当前循环的各种信息。
iterator标签在遍历一组对象的时候,它把正在循环的对象放在值栈的栈顶,所以可以直接引用这个对象的方法或属性,后面给出示例。
2:属性:
iterator标签的主要属性:
- value:用来指明到底循环的是谁,这个属性的值是OGNL表达式,用来访问ActionContext和值栈中需要被循环的对象。
- status:这个属性在ActionContext中保存一个对象,用来返回当前循环的各种信息,可以返回的信息有:
l count:集合含有多少个对象。
l index:正在循环的这一项的索引。
l even:当前遍历到的对象是不是处于列表的偶数索引位置。
l odd:当前遍历到的对象是不是处于列表的奇数索引位置。
l first:正在循环的是不是第一个。
l last:正在循环的是不是最后一个。
- begin、end、step:指明了如果使用索引来进行循环时的开始、结束和步长。
- var:变量名称,用来引用存放到值栈的被循环的对象。
3:示例:
其实在Java中处理循环的时候,主要用的是for循环和while循环,do-while循环的应用相对少一些。接下来用iterator标签来实现类似于Java中循环的功能。
(1)实现类似于for循环的功能
假如现在要求完全使用标签,来实现循环输出1到10的值,该如何实现呢?
很明显,使用iterator标签的begin、end、step和var属性就可以了,示例代码如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:iterator var="i" begin="1" end="10" step="1">
- <s:property value="#i"/>
- </s:iterator>
上面的实现很类似于如下的Java代码:
- <%
- for(int i=1;i<=10;i++){
- out.println(i);
- }
- %>
有朋友可能会说
(2)实现类似于while循环的功能
假如要循环输出一个List的值,那么就需要使用到var和value属性了,示例如下:
- <%@ page import="java.util.*"%>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- //准备点循环用的数据
- List<String> list = new ArrayList<String>();
- for(int i=1;i<=10;i++){
- list.add("str="+i);
- }
- request.setAttribute("list",list);
- %>
- <s:iterator var="v" value="#request['list']">
- <s:property value="#v"/>
- </s:iterator>
上面的实现很类似于如下的Java代码:
- <%
- //如果用Iterator来循环
- Iterator it = list.iterator();
- while(it.hasNext()){
- out.println(it.next());
- }
- //如果用加强的for循环
- for(String s : list){
- out.println(s);
- }
- %>
(3)访问复杂的对象
如果List里面放的是复杂对象呢,比如前面用过的UserModel,里面有两个属性:userId、name。页面上该如何循环显示呢?
示例代码如下:
- <%@ page import="java.util.*"%>
- <%@page import="cn.javass.ognl.vo.UserModel" %>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- //准备需要循环的数据
- List<UserModel> list = new ArrayList<UserModel>();
- UserModel um1 = new UserModel();
- um1.setUserId("userId1");
- um1.setName("张三");
- list.add(um1);
- UserModel um2 = new UserModel();
- um2.setUserId("userId2");
- um2.setName("李四");
- list.add(um2);
- request.setAttribute("users",list);
- %>
- <s:iterator value="#request.users">
- userId=<s:property value="userId"/>,
- name=<s:property value="name"/><br>
- </s:iterator>
分析一下上面的代码,iterator标签的value属性指明了要循环谁,里面的OGNL表达式"#request.users"表明了要访问request的属性中名称为users的属性的值。
接下来iterator标签在循环的时候,把当前正在循环的对象放到值栈的栈顶,比如循环第一次的时候,它就会把List中的第一个对象放到值栈的栈顶,这时候,访问这个对象的getName方法,就可以直接用简单的“name”就可以了。
(4)使用status属性
如果还想输出当前循环的索引,或者是想要把循环输出的数据用表格来展示,并按照奇数行和偶数行来设置不同的背景色,也就是我们熟悉的波浪纹或者是斑马纹背景,该如何实现呢?
这当然需要使用iterator标签的status属性,把一个保存循环状态的对象放到ActionContext中,然后在iterator标签内的property标签中,就可以引用这个保存循环状态的对象了。先来示例输出当前循环的索引,示例如下:
- <s:iterator value="#request.users" status="state">
- 索引=<s:property value="#state.index"/>,
- userId=<s:property value="userId"/>,
- name=<s:property value="name"/><br>
- </s:iterator>
注意,<s:property>引用status属性名称的时候前面要加#号,status这个对象可以使用的属性在前面的属性列表中写明了,#state.index就表示在循环内引用循环状态信息中的索引,每次循环完一个对象,state的内部状态都会相应变化。
如果要实现波浪纹或斑马纹背景的表格,该如何实现呢?
首先需要多添加点数据,才好看出效果,其次把循环的数据放置到表格中去,然后通过循环的状态对象来判断是奇数行还是偶数行,为这些行设置不同的背景颜色就可以了。示例代码如下:
- <%@ page import="java.util.*"%>
- <%@page import="cn.javass.ognl.vo.UserModel" %>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- //准备需要循环的数据
- List<UserModel> list = new ArrayList<UserModel>();
- UserModel um1 = new UserModel();
- um1.setUserId("userId1");
- um1.setName("张三");
- list.add(um1);
- UserModel um2 = new UserModel();
- um2.setUserId("userId2");
- um2.setName("李四");
- list.add(um2);
- UserModel um3 = new UserModel();
- um3.setUserId("userId3");
- um3.setName("王五");
- list.add(um3);
- UserModel um4 = new UserModel();
- um4.setUserId("userId4");
- um4.setName("马六");
- list.add(um4);
- request.setAttribute("users",list);
- %>
- <table border=1>
- <tr>
- <td colspan="4" align="center">用户列表</td>
- </tr>
- <tr>
- <td>索引</td>
- <td>用户编号</td>
- <td>用户姓名</td>
- <td>操作</td>
- </tr>
- <s:iterator value="#request.users" status="state">
- <tr
- <s:if test="#state.even">
- bgcolor="#EFF8FF"
- </s:if>
- <s:else>
- bgcolor="#B4CFF1"
- </s:else>
- >
- <td><s:property value="#state.index"/></td>
- <td><s:property value="userId"/></td>
- <td><s:property value="name"/></td>
- <td><a href="">修改</a> <a href="">删除</a></td>
- </tr>
- </s:iterator>
- </table>
运行效果如下图
图8.9 示例iterator标签
是不是看起来有点做列表页面的感觉,这就对了,以后用Struts2开发,一定少不了使用iterator标签的。
8.3.3 append与param标签
1:功能:
append标签用于把几个已经存在的集合组合成一个大集合,param标签跟它连用,用来指定组合哪些集合。
2:属性:
append标签的主要属性:
- var:用来指定把组合后的大集合放到值栈里的变量名称。
3:示例:
简单的示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:set value="{1,2,3}" var="list1"/>
- <s:set value="{4,5,6}" var="list2"/>
- <s:append var="list3">
- <s:param value="#list1"/>
- <s:param value="#list2"/>
- </s:append>
- <s:iterator value="#list3">
- <s:property/>
- </s:iterator>
首先用set标签来指定两个集合,对于<s:set value="{1,2,3}" var="list1"/>来说,var属性指定了这个集合被放进值栈的名字为list1,而value属性的值为{1,2,3},本身是OGNL表达式,表示直接创建一个集合,里面有1、2、3三个值。
然后,使用append标签来把list1和list2组合成一个大的集合,<s:append var="list3">中的var属性指定了组合后的大集合放进值栈的名字为list3,而param标签的value属性指定了被组合的集合。
最后,用iterator标签来遍历并输出合并后的集合。
8.3.4generator标签
1:功能:
generator标签用来切分字符串,并把切分的结果组成一个集合。
2:属性:
generator标签的主要属性:
- val:指定被切分的字符串,必须指定。
- separator:指定切分字符串用的分隔符,必须指定。比如要用“,”来切分字符串“a,b,c,d”,最终的结果为包含a、b、c、d四个字符串的集合。
- count:返回集合的最大长度。
- converter:用于设置自定义的Converter,必须是org.apache.struts2.util.IteratorGenerator.Converter接口的实现类。
- var:指定变量名称,用来访问放到值栈中的集合。
3:示例:
来个简单的示例,把一个字符串分解成集合,然后循环输出。示例代码如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:generator separator="," val="'a,b,c,d'" var="myList"/>
- <s:iterator value="#myList">
- <s:property/>
- </s:iterator>
上面的示例中,先使用generator标签将val的值,也就是字符串"'a,b,c,d'"用separator的值,也就是","来进行切分,把切分后的结果放入值栈,引用的名称为var属性的值arr。最后用iterator标签输出刚刚切分创建的集合。
如果把iterator标签嵌套在generator标签内,就可以不用指定iterator标签的value属性,而直接使用generator标签拆分字符串的结果了。
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:generator separator="," val="'a,b,c,d'" var="myList">
- <s:iterator>
- <s:property/>
- </s:iterator>
- </s:generator>
8.3.5merge标签
1:功能:
merge标签用来把几个已经存在的集合组合成一个大集合,与append标签的作用类似,只是原来集合中出现的各个元素出现在大集合中的顺序不同。
2:属性:
merge标签的主要属性:
- var:用来指定把组合后的大集合放到值栈里的变量名称。
3:示例:
沿用前面的例子,稍稍修改一下,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:set value="{1,2,3}" var="list1"/>
- <s:set value="{4,5,6}" var="list2"/>
- <s:merge var="list3">
- <s:param value="#list1"/>
- <s:param value="#list2"/>
- </s:merge>
- <s:iterator value="#list3">
- <s:property/>
- </s:iterator>
去运行测试一下,结果页面如下:
图8.10 示例merge标签
通过上面的示例可以看出,使用merge标签的时候,先出现原来各个集合中的第一个元素,然后是原来各个集合中的第二个元素,以此类推,所以结果为“1,4,2,5,3,6”。
而以前在使用append标签的时候,原来集合中的元素出现在大集合中的顺序为第一个集合的所有元素都出现之后,再出现第二个集合的所有元素,结果为“1,2,3,4,5,6”。
这就看出merge标签和append标签的区别来了。
8.3.6sort标签
1:功能:
利用设置的比较器,来对指定的集合进行排序。
2:属性:
sort标签的主要属性:
- comparator:用来指定对集合排序使用的比较器的实例
- source:需要排序的集合
- var:变量名称,把集合排序后的结果存放到page context中的key值
3:包含基本数据类型的集合排序示例:
还是通过示例来看sort的使用,先来示范对包含基本数据类型的集合的排序。
(1)先来准备比较器,就是实现java.util.Comparator接口的类,实现对整型数据进行升序排序,示例如下:
- package cn.javass.tag;
- public class MyComparator implements java.util.Comparator{
- public int compare(Object o1, Object o2) {
- int a = Integer.parseInt(o1.toString());
- int b = Integer.parseInt(o2.toString());
- if(a>b){
- return 1;
- }else if(a<b){
- return -1;
- }
- return 0;
- }
- }
(2)在页面上直接准备集合数据,然后排序并输出,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:set value="{4,5,3}" var="list1"/>
- <s:bean id="myComparator" name="cn.javass.tag.MyComparator" />
- <s:sort comparator="#myComparator" source="#list1">
- <s:iterator>
- <s:property/>
- </s:iterator>
- </s:sort>
注意,在sort标签的comparator属性里面,配置的是比较器的实例,这个实例怎么得到呢?因此在前面使用bean标签创建了一个比较器的实例,然后在comparator属性里面指定就可以了。
(3)运行测试一下,界面输出:“3,4,5”,是排好序了的。当然,你也可以修改比较器的实现,来实现其它的比较方式,比如降序排列等等。
有朋友会说,这是对基本类型的处理,要是复杂对象怎么排序呢?
4:包含复杂数据类型的集合排序示例:
(1)先来准备要排序的对象,简单点,就使用UserModel吧,给他添加toString方法,后面排序输出的时候会用,示例如下:
- public class UserModel {
- private String userId;
- private String name;
- public String getUserId() {
- return userId;
- }
- public void setUserId(String userId) {
- this.userId = userId;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String toString(){
- return "userId="+userId+",name="+name;
- }
- }
(2)来准备比较器实现,很简单,按照用户编号来进行降序排列吧,示例如下:
- public class MyComparator implements java.util.Comparator<UserModel>{
- public int compare(UserModel o1, UserModel o2) {
- if(o1.getUserId().compareTo(o2.getUserId()) > 0){
- //注意是降序排列
- return -1;
- }else if(o1.getUserId().compareTo(o2.getUserId()) < 0){
- return 1;
- }
- return 0;
- }
- }
(3)在页面上直接准备集合数据,然后排序并输出,示例如下:
- <%@page import="cn.javass.tag.vo.UserModel"%>
- <%@page import="java.util.*"%>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <%
- List<UserModel> list = new ArrayList<UserModel>();
- UserModel um1 = new UserModel();
- um1.setUserId("user1");
- um1.setName("张三");
- list.add(um1);
- UserModel um2 = new UserModel();
- um2.setUserId("user2");
- um2.setName("李四");
- list.add(um2);
- UserModel um3 = new UserModel();
- um3.setUserId("user3");
- um3.setName("王五");
- list.add(um3);
- request.setAttribute("list",list);
- %>
- <s:bean id="myComparator" name="cn.javass.tag.MyComparator" />
- <s:sort comparator="#myComparator" source="#request['list']">
- <s:iterator>
- <s:property/>
- </s:iterator>
- </s:sort>
(4)运行测试一下,界面输出:“userId=user3,name=王五 userId=user2,name=李四 userId=user1,name=张三”,是按照用户编号降序排好序了的。
8.3.7subset标签
1:功能:
用于获取指定集合的子集合。
2:属性:
subset标签的主要属性:
- count:用于指定子集中元素的个数。
- decider:用于指定实现过滤条件的对象,这个对象会按照过滤条件一一检测源集合中的元素是否应该被放到子集合中,指定过滤条件的类需要实现org.apache.struts2.util.SubsetIteratorFilter.Decider接口。
- var:变量名称,就是将子集合保存在当前页的上下文pageContext中所指定的key值,以后可以通过这个key值来访问。
- source:用于指定源集合。
- start:用于指定从源集合的第几个元素开始截取,注意:0代表第一个元素。
3:示例简单截取:
先来个简单的示例,准备一个集合,然后从第2个开始截取,一共截取2个元素,然后把子集合输出出来,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:set var="list" value="{1,2,3,4,5}"></s:set>
- <s:subset source="#list" count="2" start="2">
- <s:iterator>
- <s:property />
- </s:iterator>
- </s:subset>
运行测试一下,界面应该输出如下:“3 4”。因为从原集合索引为2的位置开始截取,索引是从0开始,2就是第3个位置了。
4:decider属性示例:
先写一个Decider,假如实现如下功能:用于检测源集合中的每一个元素转换为字符串后,长度是否为1,是1则通过,否则这个元素不会进入子集合。示例代码如下:
- public class StringLengthDecider implements Decider{
- public boolean decide(Object item) throws Exception {
- String value = item.toString();
- if (value.length()==1){
- return true;
- }
- return false;
- }
- }
在页面上先准备一个集合,然后使用这个Decider来实现截取判断,示例如下:
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <s:bean name="cn.javass.tag.StringLengthDecider" var="decider1"/>
- <s:set var="list" value="{'1','2','33','4','55','6'}"></s:set>
- <s:subset source="#list" start="1" count="2" decider="#decider1">
- <s:iterator>
- <s:property />
- </s:iterator>
- </s:subset>
在上面的代码中,首先使用bean标签创建了一个StringLengthDecider的实例,并把这个实例放到值栈上。然后用set标签创建了一个集合,也把这个集合放到值栈上。
然后使用subset标签,其source属性指定了源集合为值栈中名称为“list”的集合;其start属性为1说明了从索引1开始,即源集合的第一个元素’1’不会进入子集合;其count属性的值为2说明了子集合中最多有2个元素;其decider属性指定了字符串长度等于1的元素才能进入子集合。
综合以上各项条件,最终运行得到的结果应该是:“2 4”。
私塾在线网站原创《研磨struts2》系列
转自请注明出处:【http://sishuok.com/forum/blogPost/list/0/4079.html】
欢迎访问http://sishuok.com获取更多内容