ld文件如下:
<tag> <name>forEach</name> <tag-class>tag.Demo1</tag-class> <body-content>scriptless</body-content> <attribute> <name>var</name> <rtexprvalue>true</rtexprvalue> <!--字符串即可,不需要EL表达式的支持--> <required>false</required> </attribute> <attribute> <name>items</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
测试的jsp代码如下:
<% List list = new ArrayList(); list.add("zhongfucneng"); list.add("1"); list.add("2"); list.add("3"); request.setAttribute("list",list); %> <zhongfucheng:forEach items="${list}" var="str"> ${str} </zhongfucheng:forEach>
效果:
上面写的仅仅能够遍历List集合,做一个通用的forEach标签麻烦的是在:不知道传进来的是什么类型的数组、什么类型集合!,需要逐一去判断
- 我们的实现思路就是将所有的集合或数组都转成是Collection类型的!
- 我们来尝试着写一下:
//如果items是Collection类型的,就强转为Colletion if (items instanceof Collection) { collection = (Collection) items; } //如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的! if (items instanceof Map) { Map map = (Map) items; collection = (Collection) map.entrySet(); } //对象数组 if (items instanceof Object[]) { Object[] objects = (Object[]) items; collection = Arrays.asList(objects); } //int[],Byte[],char[]等八大基本数据类型.....
还有int[],byte[],char[]等八大基本数据类型,这八大基本数据类型就不能用Arrays.asList()把引用传进去了。因为JDK5以后会把引用自动装箱成Interger[]、Byte[]等等,而不是获取到数组的元素数据。
- 测试代码如下:
public static void main(String[] args) { int[] ints = new int[]{1, 2, 3}; Object[] objects = new Object[]{"1", "2", "3"}; if (objects instanceof Object[]) { Collection collection = Arrays.asList(objects); System.out.println(collection); } if (ints instanceof int[]) { Collection collection1 = Arrays.asList(ints); System.out.println(collection1); } }
效果:
对于八大基本类型数据我们就可以这样干:
if (items instanceof int[]) { int[] ints = (int[]) items; collection = new ArrayList(); for (int anInt : ints) { collection.add(anInt); } } //......这里还要写7个
JSTL的forEach标签类似就是这样干的:
由于JDK5的新特性,我们又有另外的解决方案,Class对象能够判断是否为数组类,reflect反射包下Array类:
- 其实,无论Map集合、还是任何类型的数组、都可以使用Colletion进行遍历!。
- 如果是八大基本数据类型的数组,我们就使用反射来进行构建出Collection集合。
- 标签处理器的代码:
public class Demo1 extends SimpleTagSupport { //遍历的是未知的集合或数组,定义成Object private Object items; //每次被遍历的对象存储关键字 private String var; //Colletion private Collection collection; //在WEB容器设置标签的属性的时候,判断是什么类型的数组和集合 public void setItems(Object items) { this.items = items; //如果items是Collection类型的,就强转为Colletion if (items instanceof Collection) { collection = (Collection) items; } //如果itmes是Map类型的,那么就强转为Map,再获取到<Map.Entry<K, V>,这个是Set集合的! if (items instanceof Map) { Map map = (Map) items; collection = (Collection) map.entrySet(); } //可以这样解决,Class对象判断是否是一个数组类 if (items.getClass().isArray()) { //创建Collection集合添加数组的元素! collection = new ArrayList(); //再利用reflect包下的Array类获取到该数组类的长度 int len = Array.getLength(items); //遍历并添加到集合中 for (int i = 0; i < len; i++) { collection.add(Array.get(items, i)); } } } public void setVar(String var) { this.var = var; } @Override public void doTag() throws JspException, IOException { //获取到代表标签体内容的对象 JspFragment jspFragment = this.getJspBody(); Iterator iterator = collection.iterator(); //遍历集合 while (iterator.hasNext()) { Object o = iterator.next(); //把遍历出来的对象存储到page范围中(在标签体中使用EL表达式${var},就能够获取到集合的对象了!) this.getJspContext().setAttribute(var, o); jspFragment.invoke(null); } } }