自定義JSP中的Taglib標籤之三簡單仿JSTL中帶標籤體的ForEach迴圈
上2篇文章分別了介紹了taglib的無屬性狀態和有帶屬性狀態,但是都是分別都是獨立的閉標籤,這次帶來的是帶屬性的和帶標籤體的例子,仿照jstl中的forEach迴圈構造一個簡單的迴圈標籤.
Java程式碼如下:
package org.lxh.taglib; import java.util.Collection; import java.util.Iterator; import java.util.Map; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.BodyTagSupport; publicclass TestForEach extends BodyTagSupport { private static final long serialVersionUID = -5210136338413610356L; private String var; private Iterator<?> iterator; public String getVar() { return var; } public void setVar(String var) { this.var = var; } public void setItem(Object item) { if(item instanceof Map) { Map items = (Map) item; this.iterator = items.entrySet().iterator(); } else { Collection<?> c = (Collection) item; this.iterator = c.iterator(); } } @Override public int doAfterBody() throws JspException { if (this.process()) { return EVAL_BODY_AGAIN; } else{ return EVAL_PAGE; } } @Override public int doStartTag() throws JspException { if (this.process()) return EVAL_BODY_INCLUDE; else return EVAL_PAGE; } private boolean process() { if (null != iterator && iterator.hasNext()) { Object item = iterator.next(); pageContext.setAttribute(var, item); return true; } else return false; } }
問題1:為什麼要繼承BodyTagSupport 而不去只實現IterationTag介面或者直接繼承TagSupport使用呢?
TagSupport與BodyTagSupport的區別主要是標籤處理類是否需要與標籤體互動,如果不需要互動的就用TagSupport,否則如果不需要互動就用BodyTagSupport。
互動就是標籤處理類是否要讀取標籤體的內容和改變標籤體返回的內容。用TagSupport實現的標籤,都可以用BodyTagSupport來實現,因為BodyTagSupport繼承了TagSupport而不去實現IterationTag介面的,因為BodyTagSupport繼承了TagSupport類,並且該類已經實現了IterationTag介面並且實現了功能.
doStartTag()方法在標籤開始時執行,要記住每次都要對類進行初始化,避免上一次的遺留資料對操作造成影響。然後判斷是否有資料需要處理,如果有,則返回EVAL_BODY_INCLUDE開始處理標籤裡的內容,如果沒有,返回 EVAL_PAGE跳過標籤內容執行標籤下面的內容。
doAfterBody()方法在每次處理完標籤內部內容後執行,判斷迴圈是否已經結束,如果可以繼續迴圈,返回EVAL_BODY_AGAIN用迴圈得到新的資料再次處理標籤內部內容,如果迴圈結束就返回EVAL_PAGE結束標籤。
tld如下:
<?xml version="1.0" encoding="UTF-8"?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>for</short-name> <uri></uri> <tag> <name>foreach</name> <tag-class>org.lxh.taglib.TestForEach</tag-class> <tei-class>org.lxh.tagei.ForEachInfo</tei-class> <body-content>JSP</body-content> <attribute> <name>var</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>item</name> <rtexprvalue>true</rtexprvalue> <type>java.lang.Object</type> <!-- <type>java.util.Collection</type>--> </attribute> </tag> </taglib>
是不是發現tld有點改變了,沒錯,如果要使用包含標籤體的標籤庫的話需要在<body-content>標籤中加入jsp,這樣的話該標籤表示可以包含jsp和html的標籤進行一起迴圈,上面是否還發現多了一個<tei-class>標籤,該標籤用途就是對當前自定義的標籤體進行驗證檢查的.
tei驗證檢查程式碼如下:
package org.lxh.tagei; import javax.servlet.jsp.tagext.TagData; import javax.servlet.jsp.tagext.TagExtraInfo; import javax.servlet.jsp.tagext.VariableInfo; public class ForEachInfo extends TagExtraInfo { final private static String ITEMS = "item"; final private static String VAR = "var"; @Override public VariableInfo[] getVariableInfo(TagData data) { return new VariableInfo[] { new VariableInfo(data.getAttributeString("var"), "java.lang.String", true, VariableInfo.AT_BEGIN), new VariableInfo(data.getAttribute("item").toString(), "java.lang.Object", true, VariableInfo.AT_BEGIN) }; } @Override public boolean isValid(TagData us) { if (!Util.isSpecified(us, ITEMS)) return false; return true; } }
public class Util { /** * Returns true if the given attribute name is specified, false otherwise. */ public static boolean isSpecified(TagData data, String attributeName) { return (data.getAttribute(attributeName) != null); }
才用驗證的好處非常之多的,可以對當前傳入的值進行驗證,還有非空的檢查,在標籤的時候如果不寫某個標籤體會出現驗證為false的提示.
jsp程式碼:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="/WEB-INF/tld/testforeach.tld"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="java.util.*"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<%
List<String> list = new ArrayList<String>();
list.add("aa");
list.add("bb");
list.add("cc");
Map map = new HashMap();
map.put("1","a");
map.put("2","b");
map.put("3","c");
map.put("4","b");
%>
<body>
<table>
<c:foreach var="hi" item="<%=map %>" >
<tr>
<td>${hi}</td>
</tr>
</c:foreach>
</table>
</body>
</html>