在 Struts 框架開發中,logic:iterator 標籤是最常用的迭代標籤之一,其核心職責是遍歷指定容器對象(如 ArrayList、Map 等)並將其中的元素依次暴露給頁面上下文。本文將深入剖析該標籤的源碼實現,揭示其底層工作原理。
Collection 接口統一表示各類容器,所有傳入的容器對象(ArrayList、Map、數組等)都會被轉換為 Collection 型別。offset(起始偏移)和 length(迭代長度)屬性控制。name(容器綁定鍵值)、property(屬性路徑)、scope(作用域)、id(元素暴露鍵值)。標籤啟動時(doStartTag()),首要任務是獲取待迭代的集合對象:
Object collection = this.collection;
if (collection == null) {
collection = TagUtils.getInstance().lookup(pageContext, name, property, scope);
}
TagUtils.lookup() 的查找邏輯:
property 為 null,直接在指定 scope 中查找名為 name 的對象。property 不為 null,先按上述方式找到父對象,再通過 PropertyUtils.getProperty() 獲取目標屬性值。獲取集合後,框架會根據其實際型別動態構建 Iterator:
if (collection.getClass().isArray()) {
// 處理對象數組與基本型別數組
iterator = Arrays.asList((Object[]) collection).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 {
// 拋出異常:不支援的集合型別
}
處理 offset 和 length 參數後,標籤會跳過前導元素,然後將首個有效元素綁定到 pageContext:
if (iterator.hasNext()) {
Object element = iterator.next();
if (element == null) {
pageContext.removeAttribute(id);
} else {
pageContext.setAttribute(id, element);
}
// 同時綁定索引值(若指定了 indexId)
if (indexId != null) {
pageContext.setAttribute(indexId, new Integer(getIndex()));
}
started = true;
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 會以 id 值(此處為 "myuserinfo")為鍵從 pageContext 取出當前元素對象,再根據 property 讀取屬性值並輸出。
源碼揭示:id 僅是一個字符串鍵值,Struts 用它將集合中的每個元素對象綁定到 pageContext。因此 id 可以任意自定義,唯一規則是:logic:iterator 的 id 必須與內部 bean:write 的 name 保持一致。