所有標籤類需繼承 TagSupport (無 Body 互動) 或 BodyTagSupport (需讀取/修改 Body 內容)。核心方法:
doStartTag():遇到起始標籤,返回 EVAL_BODY_INCLUDE (處理 Body) 或 SKIP_BODY (跳過)。doEndTag():遇到結束標籤,返回 EVAL_PAGE (繼續) 或 SKIP_PAGE (停止頁面)。doAfterBody():Body 內容處理後調用,返回 EVAL_BODY_AGAIN (迭代) 或 SKIP_BODY。
public class HelloWorldTag extends TagSupport {
@Override
public int doEndTag() throws JspException {
try { pageContext.getOut().write("Hello World!"); }
catch (IOException e) { throw new JspException(e); }
return EVAL_PAGE;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="https://java.sun.com/xml/ns/j2ee">
<tlib-version>1.0</tlib-version>
<short-name>myTags</short-name>
<uri>/myTags</uri>
<tag>
<name>helloWorld</name>
<tag-class>org.lxh.taglib.HelloWorldTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>field</name>
<tag-class>com.able.tag.FieldTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>field</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
<attribute>
<name>count</name>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
<tag>
<name>forEach</name>
<tag-class>exercise.taglib.ForEach</tag-class>
<body-content>JSP</body-content>
<attribute><name>id</name><required>true</required><rtexprvalue>true</rtexprvalue></attribute>
<attribute><name>collection</name><required>true</required><rtexprvalue>true</rtexprvalue></attribute>
</tag>
<tag>
<name>getProperty</name>
<tag-class>exercise.taglib.GetProperty</tag-class>
<body-content>empty</body-content>
<attribute><name>name</name><required>true</required><rtexprvalue>true</rtexprvalue></attribute>
<attribute><name>property</name><required>true</required><rtexprvalue>true</rtexprvalue></attribute>
</tag>
<function>
<name>add</name>
<function-class>exercise.taglib.ELFunction</function-class>
<function-signature>int add(int, int)</function-signature>
</function>
</taglib>
<jsp-config>
<taglib>
<taglib-uri>/myTags</taglib-uri>
<taglib-location>/WEB-INF/tag.tld</taglib-location>
</taglib>
</jsp-config>
<%@ taglib uri="/myTags" prefix="my" %>
<my:helloWorld />
<my:field field="姓名" count="10" />
<%-- 迭代標籤 --%>
<%@ page import="java.util.*" %>
<jsp:useBean id="voList" class="java.util.ArrayList" scope="request" />
<%
voList.add(new UserVo("Alice", "123"));
voList.add(new UserVo("Bob", "456"));
pageContext.setAttribute("voList", voList);
%>
<table>
<tr><th>姓名</th><th>密碼</th></tr>
<my:forEach collection="voList" id="user">
<tr>
<td><my:getProperty name="user" property="name" /></td>
<td><my:getProperty name="user" property="password" /></td>
</tr>
</my:forEach>
</table>
<!-- EL 函數 -->
2 + 5 = ${my:add(2,5)}
public class ForEach extends BodyTagSupport {
private String id, collection;
private Iterator iter;
public int doStartTag() {
Collection coll = (Collection) pageContext.findAttribute(collection);
if (coll == null || coll.isEmpty()) return SKIP_BODY;
iter = coll.iterator();
pageContext.setAttribute(id, iter.next());
return EVAL_BODY_INCLUDE;
}
public int doAfterBody() {
if (iter.hasNext()) {
pageContext.setAttribute(id, iter.next());
return EVAL_BODY_AGAIN;
}
return SKIP_BODY;
}
}
public class GetProperty extends BodyTagSupport {
private String name, property;
public int doStartTag() {
Object obj = pageContext.findAttribute(name);
if (obj == null) return SKIP_BODY;
try {
Method m = obj.getClass().getMethod("get" + capitalize(property));
pageContext.getOut().print(m.invoke(obj));
} catch (Exception e) { throw new JspException(e); }
return SKIP_BODY;
}
}
public class ELFunction {
public static int add(int i, int j) { return i + j; }
}
TagSupport。BodyTagSupport。