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

JSP 自訂標籤開發完整指南:SimpleTagSupport、標籤體處理、屬性定義與 TLD 配置實戰

     編輯:JSP 入門

JSP 自訂標籤開發完整指南


掌握 JSP 2.0+ SimpleTagSupport 架構,從基本標籤開發到標籤體處理、屬性支援、TLD 配置與部署,建立可重用的標籤庫擴展 JSP 功能。


自訂標籤架構概覽

  • JSP 2.0 引入 SimpleTagSupport 簡化開發
  • 繼承 SimpleTagSupport 並重寫 doTag() 方法
  • 透過 TLD (Tag Library Descriptor) 註冊標籤
  • JSP 頁面使用 <%@ taglib %> 引入使用

第一個自訂標籤:Hello 標籤

1. 標籤處理類別

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!");
    }
}

2. TLD 檔案配置

位置: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>

3. JSP 頁面使用

<%@ taglib prefix="ex" uri="/WEB-INF/hello.tld" %>
<html><body>
    <ex:hello/>
</body></html>

4. 輸出結果

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());
    }
}

TLD 修改:允許標籤體

<tag>
    <name>hello</name>
    <tag-class>com.example.tags.HelloTag</tag-class>
    <body-content>scriptless</body-content>
</tag>

body-content 屬性值

值說明
empty不允許標籤體內容 (預設)
scriptless允許 JSP 內容、EL、標準標籤,但不允許 Scriptlet
tagdependent標籤自行處理原始內容,容器不解析

使用標籤體

<ex:hello>這是標籤體內容</ex:hello>

輸出結果

這是標籤體內容

標籤屬性支援

屬性對應 Setter 方法

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());
        }
    }
}

TLD 定義屬性

<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}" />

輸出結果

自訂屬性訊息

多屬性標籤範例

TLD 多屬性定義

<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>

標籤檔案 - 替代開發方式

.tag 檔案 (JSP 2.0+)

無需 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>

使用 .tag 檔案

<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %>
<tags:panel title="動態面板" collapsible="true">
    面板內容...
</tags:panel>

部署與最佳實務

打包為 JAR

  1. 編譯標籤類別
  2. 建立 META-INF/tlds/ 目錄放置 TLD
  3. 打包為 JAR:jar cf mytags.jar com/ META-INF/
  4. 放入專案 WEB-INF/lib/ 或伺服器共用庫
  5. JSP 使用 URI 引入:<%@ taglib prefix="ex" uri="https://example.com/tags" %>

命名慣例建議

  • 標籤名:小寫、連字號分隔 (如 panel-header)
  • 前綴:簡短、有意義 (如 ex、ui、fmt)
  • URI:反向網域名 (如 https://com.example/tags)

效能考量

  • 避免在 doTag() 中建立大量物件
  • 重用 StringWriter/StringBuilder
  • 大量輸出考慮直接寫入 JspWriter
  • 快取昂貴計算結果

進階主題

  • 標籤巢狀:父標籤透過 findAncestorWithClass() 存取子標籤
  • 標籤協作:共享資料透過 pageContext 屬性
  • 動態屬性:實作 DynamicAttributes 介面支援任意屬性
  • 標籤驗證:實作 TagLibraryValidator 編譯期驗證
  • 事件標籤:BodyTag 介面支援 body 處理事件
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved