掌握 JSP 2.0+ SimpleTagSupport 架構,從基本標籤開發到標籤體處理、屬性支援、TLD 配置與部署,建立可重用的標籤庫擴展 JSP 功能。
doTag() 方法<%@ taglib %> 引入使用package com.example.tags;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class HelloTag extends SimpleTagSupport {
@Override
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
out.println("Hello Custom Tag!");
}
}
位置:WEB-INF/hello.tld
<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee
https://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1">
<tlib-version>1.0</tlib-version>
<jsp-version>2.1</jsp-version>
<short-name>Example Tags</short-name>
<uri>https://example.com/tags</uri>
<tag>
<name>hello</name>
<tag-class>com.example.tags.HelloTag</tag-class>
<body-content>empty</body-content>
</tag>
</taglib>
<%@ taglib prefix="ex" uri="/WEB-INF/hello.tld" %>
<html><body>
<ex:hello/>
</body></html>
Hello Custom Tag!
package com.example.tags;
import javax.servlet.jsp.tagext.*;
import javax.servlet.jsp.*;
import java.io.*;
public class HelloTag extends SimpleTagSupport {
private StringWriter sw = new StringWriter();
@Override
public void doTag() throws JspException, IOException {
// 讀取標籤體內容到 StringWriter
getJspBody().invoke(sw);
// 輸出處理後的內容
getJspContext().getOut().println(sw.toString().toUpperCase());
}
}
<tag>
<name>hello</name>
<tag-class>com.example.tags.HelloTag</tag-class>
<body-content>scriptless</body-content>
</tag>
| 值 | 說明 |
|---|---|
| empty | 不允許標籤體內容 (預設) |
| scriptless | 允許 JSP 內容、EL、標準標籤,但不允許 Scriptlet |
| tagdependent | 標籤自行處理原始內容,容器不解析 |
<ex:hello>這是標籤體內容</ex:hello>
這是標籤體內容
public class HelloTag extends SimpleTagSupport {
private String message; // 屬性名稱:message
// Setter 方法命名慣例:set + 屬性名首字大寫
public void setMessage(String msg) {
this.message = msg;
}
private StringWriter sw = new StringWriter();
@Override
public void doTag() throws JspException, IOException {
if (message != null) {
// 使用屬性值
getJspContext().getOut().println(message);
} else {
// 使用標籤體內容
getJspBody().invoke(sw);
getJspContext().getOut().println(sw.toString());
}
}
}
<tag>
<name>hello</name>
<tag-class>com.example.tags.HelloTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>message</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
<description>自訂顯示訊息</description>
</attribute>
</tag>
| 元素 | 必要 | 說明 |
|---|---|---|
| name | 是 | 屬性名稱,標籤內唯一 |
| required | 否 | true/false,預設 false |
| rtexprvalue | 否 | true/false,是否接受 EL 運算式,預設 false |
| type | 否 | Java 類別型別,預設 String |
| description | 否 | 屬性說明 |
| fragment | 否 | true/false,是否為 JspFragment 型別 |
<ex:hello message="自訂屬性訊息" />
<!-- 支援 EL 運算式 -->
<ex:hello message="${user.welcomeMessage}" />
自訂屬性訊息
<tag>
<name>panel</name>
<tag-class>com.example.tags.PanelTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>title</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
<attribute>
<name>collapsible</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.Boolean</type>
</attribute>
<attribute>
<name>headerClass</name>
<required>false</required>
<rtexprvalue>true</rtexprvalue>
<type>java.lang.String</type>
</attribute>
</tag>
public class PanelTag extends SimpleTagSupport {
private String title;
private Boolean collapsible = false;
private String headerClass = "panel-header";
public void setTitle(String title) { this.title = title; }
public void setCollapsible(Boolean collapsible) { this.collapsible = collapsible; }
public void setHeaderClass(String headerClass) { this.headerClass = headerClass; }
@Override
public void doTag() throws JspException, IOException {
JspWriter out = getJspContext().getOut();
StringBuilder html = new StringBuilder();
html.append("<div class=\"panel\">");
html.append("<div class=\"").append(headerClass).append("\">")
.append(title);
if (collapsible) {
html.append(" <button class=\"collapse-btn\">─</button>");
}
html.append("</div>");
html.append("<div class=\"panel-body\">");
// 處理標籤體
StringWriter sw = new StringWriter();
getJspBody().invoke(sw);
html.append(sw.toString());
html.append("</div></div>");
out.println(html.toString());
}
}
<ex:panel title="使用者資料" collapsible="true" headerClass="custom-header">
<p>姓名:${user.name}</p>
<p>信箱:${user.email}</p>
</ex:panel>
無需 Java 類別,直接用 JSP 語法開發標籤:
<!-- WEB-INF/tags/panel.tag -->
<%@ tag body-content="scriptless" %>
<%@ attribute name="title" required="true" rtexprvalue="true" %>
<%@ attribute name="collapsible" required="false" type="java.lang.Boolean" %>
<div class="panel">
<div class="panel-header">${title}
<c:if test="${collapsible}">
<button class="collapse-btn">─</button>
</c:if>
</div>
<div class="panel-body">
<jsp:doBody/>
</div>
</div>
<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<tags:panel title="動態面板" collapsible="true">
面板內容...
</tags:panel>
META-INF/tlds/ 目錄放置 TLDjar cf mytags.jar com/ META-INF/WEB-INF/lib/ 或伺服器共用庫<%@ taglib prefix="ex" uri="https://example.com/tags" %>panel-header)ex、ui、fmt)https://com.example/tags)findAncestorWithClass() 存取子標籤DynamicAttributes 介面支援任意屬性TagLibraryValidator 編譯期驗證BodyTag 介面支援 body 處理事件