首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

JSP 標籤庫 (Tag Library) 深度解析:架構、TLD、標籤處理器、標籤檔完整指南

     編輯:關於JSP

JSP 標籤庫是將 Java 邏輯封裝為可重用標記的標準機制,讓頁面作者以宣告式標籤替代 Scriptlet。本文系統解析標籤庫四大核心組件、TLD 結構、標籤處理器生命週期、SimpleTag vs Classic Tag、BodyTag 緩衝機制、TagExtraInfo (TEI)、標籤檔 現代替代方案,並提供最佳實務建議。

標籤庫四大核心組件

組件角色形式載入位置
標籤處理器實作標籤行為的 Java 類別.class (實作 Tag/SimpleTag/BodyTag)`WEB-INF/classes/` 或 `WEB-INF/lib/*.jar`
標籤庫描述器 (TLD)XML 元資料,描述標籤名稱、屬性、體內容、處理器類別.tld (XML)`WEB-INF/tld/` 或 JAR 內 `META-INF/tld/`
標籤附加資訊 (TEI)提供編譯期驗證、變數宣告資訊 (可選).class (實作 TagExtraInfo)同標籤處理器
標籤檔純 JSP 片段實作標籤 (JSP 2.0+),無需 Java 類別/TLD.tag`WEB-INF/tags/`

TLD 結構詳解 (taglib.xml)

<?xml version="1.0" encoding="UTF-8"?>
<taglib xmlns="https://java.sun.com/xml/ns/javaee"
        version="2.1">
    <!-- 整個庫的元資料 -->
    <tlib-version>1.2</tlib-version>
    <jsp-version>2.1</jsp-version>
    <short-name>my</short-name> <!-- 預設前綴 -->
    <uri>https://mycompany.com/tags</uri> <!-- 唯一識別 URI -->
    <description>企業通用標籤庫</description>

    <!-- 單一標籤定義 -->
    <tag>
        <name>formatDate</name> <!-- 標籤名稱 -->
        <tag-class>com.my.tags.FormatDateTag</tag-class>
        <tei-class>com.my.tags.FormatDateTagTEI</tei-class> <!-- 可選 -->
        <body-content>scriptless</body-content> <!-- empty | scriptless | tagdependent | JSP -->
        <description>格式化日期輸出</description>
        
        <attribute> <!-- 屬性定義 -->
            <name>pattern</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue> <!-- 支援 EL/運算式 -->
            <type>java.lang.String</type>
            <description>SimpleDateFormat 模式</description>
        </attribute>
        <attribute>
            <name>date</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.util.Date</type>
        </attribute>
        
        <variable> <!-- 宣告變數 (供 TEI 使用) -->
            <name-given>formattedDate</name-given>
            <variable-class>java.lang.String</variable-class>
            <declare>true</declare>
            <scope>NESTED</scope> <!-- AT_BEGIN | AT_END | NESTED -->
        </variable>
    </tag>
</taglib>

body-content 四種模式

值行為適用場景
empty標籤體必須為空 ``無需內容的功能性標籤 (如 ``)
scriptless允許 EL、標準/自訂標籤、模板文字,**禁止** Scriptlet (`<% %>`)、宣告 (`<%! %>`)**最常用**,現代 JSP 最佳實務
tagdependent標籤體視為純文字,不解析 EL/標籤,原樣傳給處理器SQL、JavaScript、樣板語言、原始碼輸出
JSP完整 JSP 語法 (含 Scriptlet) — **不推薦**舊版相容

標籤處理器兩大體系

1. Classic Tag (Tag / BodyTag / IterationTag) — JSP 1.1 遺產

  • 介面:`javax.servlet.jsp.tagext.Tag` → `IterationTag` → `BodyTag`
  • 基底類:`TagSupport`、`BodyTagSupport`
  • 生命週期方法:`doStartTag()` → `doInitBody()` → `doAfterBody()` → `doEndTag()` → `release()`
  • 回傳碼控制流程:`EVAL_BODY_INCLUDE`、`EVAL_BODY_TAG`、`SKIP_BODY`、`EVAL_PAGE`、`SKIP_PAGE`
  • 體內容處理:`BodyContent` (繼承 `JspWriter`),緩衝區需手動 `getString()`/`writeOut()` 刷新。

2. SimpleTag (JSP 2.0+) — 現代標準,強烈推薦

  • 介面:`javax.servlet.jsp.tagext.SimpleTag`
  • 基底類:`SimpleTagSupport`
  • 單一核心方法:`doTag()` — **一次性執行**,無 `doStartTag`/`doEndTag` 分離。
  • 體內容存取:`getJspBody()` 回傳 `JspFragment`,呼叫 `invoke(writer)` 輸出。
  • 無 `doAfterBody` 迴圈機制,**不支援迭代標籤** (需自行在 `doTag` 內迴圈 `invoke`)。
  • 優點:API 簡潔、無狀態、易測試、支援標籤檔 直接編譯為 SimpleTag。

標籤處理器生命週期詳解 (SimpleTag)

  1. 實例化:容器調用無參建構子 (或 TagFactory),通常池化重用。
  2. 初始化:`setJspContext(JspContext)`、`setParent(Tag)`、`setJspBody(JspFragment)` (若有標籤體)。
  3. 屬性注入:對每個屬性調用 `setXxx(value)` (自動型別轉換)。
  4. 執行:調用 `doTag()` — 核心邏輯入口。
    - 可讀取屬性、`jspContext` 隱含物件 (`request`、`session`、`out` 等)。
    - 如需輸出標籤體:`getJspBody().invoke(null)` (直接輸出) 或 `invoke(sw)` (捕獲修改)。
    - 如需宣告變數:`jspContext.setAttribute(name, value, scope)`。
  5. 釋放:調用 `release()` — 重置狀態、釋放資源,準備下一次重用。

TagExtraInfo (TEI) — 編譯期驗證與變數宣告

TEI 類別實作 `javax.servlet.jsp.tagext.TagExtraInfo`,提供兩個關鍵方法:

public class MyTagTEI extends TagExtraInfo {
    // 1. 驗證屬性 (編譯期)
    @Override
    public boolean isValid(TagData data) {
        // data.getAttribute("attrName") 取得屬性值 (可能為 TagData.REQUEST_TIME_VALUE)
        String val = data.getAttributeString("count");
        if (val != null && !val.equals(TagData.REQUEST_TIME_VALUE)) {
            try { Integer.parseInt(val); return true; } 
            catch (NumberFormatException e) { return false; }
        }
        return true; // 運算式值無法驗證,假設合法
    }

    // 2. 宣告變數資訊 (供容器產生程式碼)
    @Override
    public VariableInfo[] getVariableInfo(TagData data) {
        return new VariableInfo[] {
            new VariableInfo("loopVar", "java.lang.String", true, VariableInfo.NESTED)
        };
    }
}

TLD 中 `` 指定此類別。**現代替代**:標籤檔 自動處理變數宣告,無需 TEI。

標籤檔 — 零 Java 代碼、零 TLD、熱部署

將標籤邏輯寫為 `.tag` 檔案放入 `WEB-INF/tags/` (或子目錄對應前綴命名空間)。

範例:/WEB-INF/tags/formatDate.tag

<%@ tag language="java" pageEncoding="UTF-8" %>
<%@ attribute name="date" required="true" type="java.util.Date" rtexprvalue="true" %>
<%@ attribute name="pattern" required="true" type="java.lang.String" rtexprvalue="true" %>
<%@ variable name-given="formattedDate" variable-class="java.lang.String" scope="NESTED" %>

<%@ taglib prefix="fmt" uri="https://java.sun.com/jsp/jstl/fmt" %>
<fmt:formatDate value="${date}" pattern="${pattern}" var="formattedDate" scope="NESTED" />

使用方式

<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %>
<my:formatDate date="${article.publishDate}" pattern="yyyy-MM-dd" />
格式化後: ${formattedDate}

優勢

  • 無 Java 編譯、無 TLD 維護、修改即時生效 (開發模式)。
  • 支援所有 JSP 標準功能 (EL、JSTL、其他標籤、include)。
  • 自動對應 `SimpleTag` 生命週期,`jsp:doBody` 對應 `getJspBody().invoke()`。

JSP 頁面引用標籤庫

<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %> <!-- 標準庫,容器內建 -->
<%@ taglib prefix="my" uri="https://mycompany.com/tags" %> <!-- 自訂庫,需 TLD -->
<%@ taglib prefix="my" tagdir="/WEB-INF/tags" %> <!-- 標籤檔目錄 -->
  • `uri`:對應 TLD `` 或 `web.xml` `` 映射。
  • `tagdir`:直接掃描目錄下 `.tag` 檔案,前綴為目錄名或指定值。

最佳實務與避坑指南

  1. 優先使用標籤檔:簡單顯示邏輯、封裝片段、佈局組件 → `.tag` 檔案。
  2. 複雜邏輯用 SimpleTag:需 Java API、資料庫存取、複雜運算 → `SimpleTagSupport` + TLD。
  3. 禁用 Classic Tag:除非維護舊專案,新專案無理由使用 `BodyTagSupport`。
  4. 屬性型別盡量用 String:容器自動轉換,避免型別不匹配例外;必要時用 `type="java.util.Date"` 等。
  5. rtexprvalue="true":預設開啟,支援 EL/運算式;唯有極少數靜態屬性設 `false`。
  6. body-content="scriptless":強制無 Scriptlet,推動乾淨模板。
  7. 變數作用域選 NESTED:最安全,僅標籤體內可見,避免污染頁面範圍。
  8. 標籤命名規範:動詞開頭 (``、``),避免與 HTML 標籤衝突。
  9. 文檔化:TLD ``、`` 必填,IDE 可提示。

從 JSP 遷移到現代前端架構的啟示

標籤庫本質是**伺服器端元件化**。現代前端框架 (React/Vue/Svelte/Astro) 以**客戶端元件**取代:
- `` → `` (React Component)
- `` → `{items.map(item => )}`
- `` → 條件渲染 `{isAdmin ? : }`
理解標籤庫生命週期、範圍、體內容處理,有助於設計對應的前端元件 Props、Slots、Context 模型。

JSP 標籤庫核心:**TLD 元資料 + SimpleTagSupport 處理器 + scriptless 體內容**。現代首選**標籤檔**消除樣板代碼。Classic Tag/BodyTag/TEI 僅為舊系統維護保留。掌握 `doTag()`、`JspFragment.invoke()`、`pageContext.setAttribute()` 三大核心 API 即可應對 95% 自訂標籤開發需求。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved