在 JSP 開發中,經常需要遍歷物件屬性中的集合並輸出其元素屬性。例如,request 域中存在一個 People 物件,其 men 屬性為一個包含多個 Man 物件的 Collection。需求是將集合中每個 Man 的 name 屬性顯示出來。這是一個典型的巢狀標籤應用場景:外層標籤獲取根物件,中間標籤提取集合並迭代,內層標籤負責輸出單個元素的屬性值。
採用三層標籤協作:
${people})。name)。<diego:withObject value="${people}">
<diego:withCollection property="men">
<diego:elementout property="name"/>
</diego:withCollection>
</diego:withObject>
package diegoyun.vo;
import java.util.Collection;
public class People {
private Collection men;
public Collection getMen() { return men; }
public void setMen(Collection men) { this.men = men; }
}
package diegoyun;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.BodyTagSupport;
import org.apache.taglibs.standard.lang.support.ExpressionEvaluatorManager;
public class WithObjectTag extends BodyTagSupport {
private Object value;
public Object getValue() { return value; }
public void setValue(Object value) throws JspException {
this.value = ExpressionEvaluatorManager.evaluate(
"value", value.toString(), Object.class, this, pageContext);
}
public int doStartTag() { return EVAL_BODY_INCLUDE; }
public int doEndTag() throws JspException { return EVAL_PAGE; }
}
該標籤需實現 IterationTag 或繼承 BodyTagSupport,在 doStartTag 中從父標籤獲取物件,利用反射取得集合屬性,並使用 pageContext.setAttribute 將當前元素暴露給子標籤,配合 doAfterBody 實現循環。
從 pageContext 取得當前迭代元素,反射讀取指定屬性並寫入 JspWriter。
findAncestorWithClass 獲取父標籤實例,實現資料傳遞。EVAL_BODY_AGAIN 與 SKIP_BODY 返回值。ExpressionEvaluatorManager(JSTL 1.0 風格),現代項目建議改用 JSP 2.0+ 原生 EL 支援。通過巢狀自定義標籤,可將複雜的集合遍歷邏輯封裝為聲明式標籤,使 JSP 頁面更簡潔、可重用。實際專案中推薦使用 JSTL <c:forEach> 替代手寫迭代標籤,但理解其原理有助於開發更高階的標籤庫。