• Struts源码阅读心得之logic:Iterator篇


    logic:Iterator标签(以下简称“该标签”)是Struts里非常常用的一个标签,其作用在于循环显示给定容器对象中的值
    如此常用的标签,其源代码当然需要拿出来研究一下,以下列举几条研究成果:
    1、该标签内部使用Collection来表示给定的容器,所有的给定容器对象(如ArrayList,Map等)都会被其转化成为Collection
    2、该标签自己维护循环索引
    3、该标签常见的几个属性如下:
    name、property、scope、id
    4、结合以上标签,给出一段源代码来解释其工作的机理

    这段源代码中,一开始就可以看到这样一句:
    collection = TagUtils.getInstance().lookup(pageContext, name, property, scope);
    这局代码在之前的几次Struts源码分析中已经分析到了,作用如下:
    1、如果property的值为null,那么
    在scope定义的范围内(即request、session、application、page)查找以name变量值命名的对象(返回值是一个Object,然后转化成Collection)

    2、如果property的值不为null,那么
    做完1步骤的事情后,她将调用org.apache.commons.beanutils.PropertyUtils类中的getProperty方法,得到目标对象,转化成Collection类型

    所以,我们在编码时,可以自己构建一个ArrayList,然后放到session或request范围内,然后在logic:Iterator标签中可以这样定义:
    name=对象在session或request中绑定的key值
    property可以不写(因为没有再将这个ArrayList包装进一个对象)
    scope也可以不写(不写将发生pageContext.findAttribute方法调用,在四种scope中依次寻找),或写session或request

    之后的代码也很好理解,Struts得到Collection之后,动态判断其进一步的类型,然后调用相关方法获得Iterator
    最后,Struts使用得到的Iterator对象,开始对Collection进行循环,将Collection中每个元素对象取出,以id变量值绑定到
    pageContext上。看到这里,心急的人可能会问,怎么就这么结束了么?她不将元素对象取出,然后显示么?

    =========================================================
    Code: Select all
    public int doStartTag() throws JspException {

            // Acquire the collection we are going to iterate over
            Object collection = this.collection;
            if (collection == null) {
                collection = TagUtils.getInstance().lookup(pageContext, name, property, scope);
            }

            if (collection == null) {
                JspException e = new JspException(messages.getMessage("iterate.collection"));
                TagUtils.getInstance().saveException(pageContext, e);
                throw e;
            }

            // Construct an iterator for this collection
            if (collection.getClass().isArray()) {
                try {
                    // If we're lucky, it is an array of objects
                    // that we can iterate over with no copying
                    iterator = Arrays.asList((Object[]) collection).iterator();
                } catch (ClassCastException e) {
                    // Rats -- it is an array of primitives
                    int length = Array.getLength(collection);
                    ArrayList c = new ArrayList(length);
                    for (int i = 0; i < length; i++) {
                        c.add(Array.get(collection, i));
                    }
                    iterator = c.iterator();
                }
            } else if (collection instanceof Collection) {
                iterator = ((Collection) collection).iterator();
            } else if (collection instanceof Iterator) {
                iterator = (Iterator) collection;
            } else if (collection instanceof Map) {
                iterator = ((Map) collection).entrySet().iterator();
            } else if (collection instanceof Enumeration) {
                iterator = IteratorUtils.asIterator((Enumeration) collection);
            } else {
                JspException e = new JspException(messages.getMessage("iterate.iterator"));
                TagUtils.getInstance().saveException(pageContext, e);
                throw e;
            }

            // Calculate the starting offset
            if (offset == null) {
                offsetValue = 0;
            } else {
                try {
                    offsetValue = Integer.parseInt(offset);
                } catch (NumberFormatException e) {
                    Integer offsetObject = (Integer) TagUtils.getInstance().lookup(pageContext, offset, null);
                    if (offsetObject == null) {
                        offsetValue = 0;
                    } else {
                        offsetValue = offsetObject.intValue();
                    }
                }
            }
            if (offsetValue < 0) {
                offsetValue = 0;
            }

            // Calculate the rendering length
            if (length == null) {
                lengthValue = 0;
            } else {
                try {
                    lengthValue = Integer.parseInt(length);
                } catch (NumberFormatException e) {
                    Integer lengthObject = (Integer) TagUtils.getInstance().lookup(pageContext, length, null);
                    if (lengthObject == null) {
                        lengthValue = 0;
                    } else {
                        lengthValue = lengthObject.intValue();
                    }
                }
            }
            if (lengthValue < 0) {
                lengthValue = 0;
            }
            lengthCount = 0;

            // Skip the leading elements up to the starting offset
            for (int i = 0; i < offsetValue; i++) {
                if (iterator.hasNext()) {
                    iterator.next();
                }
            }

            // Store the first value and evaluate, or skip the body if none
            if (iterator.hasNext()) {
                Object element = iterator.next();
                if (element == null) {
                    pageContext.removeAttribute(id);
                } else {
                    pageContext.setAttribute(id, element);
                }
                lengthCount++;
                started = true;
                if (indexId != null) {
                    pageContext.setAttribute(indexId, new Integer(getIndex()));
                }
                return (EVAL_BODY_TAG);
            } else {
                return (SKIP_BODY);
            }

        }

    =========================================================
    不急,其实该标签做到这一步已经可以了,因为在我们使用logic:Iterator标签的同时,一般还会使用bean:write标签,如下一段:
    =========================================================
    Code: Select all
    <logic:iterate id="myuserinfo" name="browseresult" scope="request">
      <tr>
        <td align="center">
          <bean:write name="myuserinfo" property="username" filter="true"/>
        </td>
        <td align="center">
          <bean:write name="myuserinfo" property="userdesc" filter="true"/>
        </td>
      </tr>
    </logic:iterate>

    =========================================================
    所以,bean:write这个标签将会到pageContext里面,以id变量值为key值,查找这个元素对象,然后将其属性(property属性定义)取出、显示。

    OK,至此,应该已经很清楚了。最后还要一提id这个属性,很多example中可能会对我们有误解,认为id属性的定义也对应一个实体类(实体bean),
    其实不然,通过以上的源代码,可以看到,id这个属性只是一个key而已,Struts用这个值来将Collection中的每个元素对象绑定到pageContext
    里面去,所以,对于id属性的值,完全可以自定义,只要遵守一条规则:

    在logic:Iterator标签中定义的id属性值必须和下面bean:write标签中的name属性的值一致!
  • 相关阅读:
    StringBuffer
    Mysql语法大全
    String类
    装箱拆箱
    修饰符
    杨辉三角
    基本变量类型
    随手快递app开发第五天
    随手快递app开发第四天
    随手快递app开发第三天
  • 原文地址:https://www.cnblogs.com/super119/p/1988613.html
Copyright © 2020-2023  润新知