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

JSP 自定義標籤開發入門:從零構建可重用標籤庫

     編輯:關於JSP

為什麼需要自定義標籤?

JSP 早期大量使用 Scriptlet (<% ... %>) 嵌入 Java 代碼,導致業務邏輯與視圖渲染耦合,維護困難。JSP 2.0 引入標籤庫機制,允許開發者將通用展示邏輯封裝為聲明式標籤,頁面作者僅需像使用 HTML 標籤一樣調用,實現「零 Java 代碼」的頁面開發。自定義標籤的核心優勢:

  • 關注點分離:Java 邏輯移至標籤處理器類,JSP 專注結構渲染。
  • 高度復用:跨專案共享標籤庫 JAR,減少重複代碼。
  • 友好語法:支援屬性、體內容、巢狀標籤、EL 表達式,體驗接近原生 HTML。
  • 工具支援:IDE 提供標籤提示、屬性驗證、文檔 hover。

標籤庫開發完整流程

步驟 1:定義標籤庫描述符

在 WEB-INF/tlds/mytags.tld 建立 TLD 檔案(XML 格式):

<?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>
    <short-name>my</short-name>
    <uri>https://example.com/tags/mytags</uri>

    <tag>
        <name>hello</name>
        <tag-class>com.example.tags.HelloTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>name</name>
            <required>false</required>
            <rtexprvalue>true</rtexprvalue>
            <type>java.lang.String</type>
        </attribute>
    </tag>
</taglib>

關鍵元素說明:

  • uri:全域唯一標識,JSP 頁面透過 taglib 指令引用。
  • body-content:empty(無體)、scriptless(無 Scriptlet,可含 EL/標籤)、tagdependent(原文處理)、JSP(任意內容)。
  • rtexprvalue:屬性值是否支援運行時表達式(如 ${user.name})。

步驟 2:實現標籤處理器類

繼承 SimpleTagSupport (JSP 2.0+ 推薦) 或 TagSupport (傳統):

package com.example.tags;

import javax.servlet.jsp.tagext.SimpleTagSupport;
import javax.servlet.jsp.JspContext;
import java.io.IOException;

public class HelloTag extends SimpleTagSupport {
    private String name = "World"; // 預設值

    // 屬性 Setter(容器自動調用)
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void doTag() throws IOException {
        JspContext ctx = getJspContext();
        // 獲取輸出流
        ctx.getOut().write("Hello, " + name + "! 當前時間:" + new java.util.Date());
    }
}

步驟 3:在 JSP 頁面中使用

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="my" uri="https://example.com/tags/mytags" %>
<!DOCTYPE html>
<html>
<head><title>自定義標籤演示</title></head>
<body>
    <h1>標籤調用示例</h1>
    <!-- 無屬性調用,使用預設值 -->
    <p><my:hello /></p>
    
    <!-- 傳遞屬性 -->
    <p><my:hello name="開發者" /></p>
    
    <!-- 配合 EL 表達式動態傳值 -->
    <p><my:hello name="${param.username}" /></p>
</body>
</html>

進階標籤開發模式

1. 處理標籤體內容

若 body-content 設為 scriptless,可在 doTag() 中獲取並處理體內容:

public class RepeatTag extends SimpleTagSupport {
    private int times = 1;
    public void setTimes(int times) { this.times = times; }

    @Override
    public void doTag() throws IOException, JspException {
        // 捕獲體內容到 StringWriter
        java.io.StringWriter sw = new java.io.StringWriter();
        getJspBody().invoke(sw); // 執行體內容並寫入 sw
        String body = sw.toString();
        
        for (int i = 0; i < times; i++) {
            getJspContext().getOut().write(body);
        }
    }
}

使用方式:

<my:repeat times="3">
    <div class="item">第 ${status.index + 1} 項</div>
</my:repeat>

2. 巢狀標籤與共享狀態

父標籤可透過 findAncestorWithClass() 獲取祖先標籤實例,實現協作:

<my:form>
    <my:input name="username" label="用戶名" />
    <my:input name="password" label="密碼" type="password" />
    <my:submit value="登入" />
</my:form>

FormTag 收集子標籤資料,統一輸出 <form> 標籤與驗證腳本。

3. 標籤檔:無需 Java 類的快速開發

JSP 2.0+ 支援 .tag 檔案,放置於 WEB-INF/tags/ 目錄,即為標籤:

<%-- WEB-INF/tags/card.tag --%>
<%@ attribute name="title" required="true" %>
<%@ attribute name="image" required="false" %>
<div class="card">
    <img src="${image}" alt="${title}">
    <h3>${title}</h3>
    <jsp:doBody/> <!-- 渲染標籤體 -->
</div>

使用:<my:card title="產品" image="/img/p1.jpg">描述內容</my:card>

標籤庫打包與發佈

  1. 將 TLD 檔置於 JAR 內 META-INF/tlds/ 目錄。
  2. 在 META-INF/MANIFEST.MF 添加 Taglib-URI、Taglib-Version 屬性(可選)。
  3. Maven 打包:maven-jar-plugin 配置 <include>META-INF/tlds/**</include>。
  4. 專案引入該 JAR 後,無需配置 web.xml,容器自動掃描識別。

最佳實踐與避坑指南

  • 優先使用 SimpleTagSupport:API 更簡潔,無需管理生命週期方法 (doStartTag/doEndTag),支援標籤體靈活處理。
  • 屬性類型盡量用基本類型或 String:容器自動轉換,避免 ClassCastException。
  • 輸出內容務必轉義:防 XSS,使用 javax.servlet.jsp.JspRuntimeLibrary.escapeXml() 或 JSTL <c:out>。
  • 避免在標籤中持有請求級狀態:標籤實例可能被池化復用,字段值會殘留。請求相關資料放在 JspContext 作用域中。
  • 文檔化每個標籤:TLD 中添加 <description>、<example>,生成標籤庫文檔供前端參考。

總結

自定義標籤是 JSP 實現組件化開發的關鍵技術。掌握 TLD 定義、標籤處理器實現、標籤體處理、巢狀協作、標籤檔快速開發、打包發佈全流程,能顯著提升團隊開發效率與代碼質量。雖然現代前端框架(Vue/React)已成為主流,但在存量 JSP 專案維護、純後端渲染場景、郵件模板、報表生成等領域,標籤庫技術依然具有不可替代的價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved