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上。看到这里,心急的人可能会问,怎么就这么结束了么?她不将元素对象取出,然后显示么?

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标签,如下一段:
<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属性的值一致! 


 

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐