簡介 Simple Tag


相較於 Tag File 的使用,實作 Simple Tag 時有更多的東西必須了解。首先來使用 Simple Tag 模彷 JSTL 的 <c:if> 標籤功能,了解一個簡單的 Simple Tag 要如何開發,由於這是個「偽」JSTL 標籤,姑且叫它作 <f:if> 標籤好了。

首先要撰寫標籤處理器,這是一個 Java 類別,可以繼承 javax.servlet.jsp.tagext.SimpleTagSupport 來實作標籤處理器(Tag Handler),並重新定義 doTag() 方法來進行標籤處理。

package cc.openhome;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class IfTag extends SimpleTagSupport {
    private boolean test;

    @Override
    public void doTag() throws JspException {
        if (test) {
            try {
                getJspBody().invoke(null);
            } catch (java.io.IOException ex) {
                throw new JspException("IfTag 執行錯誤", ex);
            }
        }
    }

    public void setTest(boolean test) {
        this.test = test;
    }
}

在這邊的 <f:if> 標籤有個 test 屬性,所以標籤處理器必須有個接受 test 屬性的設值方法(Setter)。如果 test 屬性為 true,則呼叫 SimpleTagSupportgetJspBody() 方法,這會傳回一個 JspFragment 物件,代表 <f:if></f:if> 間的本體內容,如果呼叫 JspFragmentinvoke() 並傳入一個 null,表示執行 <f:if></f:if> 間的本體內容,如果沒有呼叫 invoke(),則 <f:if></f:if> 間的本體內容不會執行,也就不會有結果輸出至使用者的瀏覽器。

為了讓 Web 容器了解 <f:if> 標籤與 IfTag 標籤處理器之間的關係,要定義一個標籤程式庫描述檔(Tag Library Descriptor),也就是一個副檔名為 *.tld 的檔案。

 f.tld

<?xml version="1.0" encoding="UTF-8"?>
<taglib xsi:schemaLocation="
            http://java.sun.com/xml/ns/javaee 
            http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
        xmlns="http://java.sun.com/xml/ns/javaee" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        version="2.1">
    <tlib-version>1.0</tlib-version>
    <short-name>f</short-name>
    <uri>https://openhome.cc/jstl/fake</uri>
    <tag>
        <name>if</name>
        <tag-class>cc.openhome.IfTag</tag-class>
        <body-content>scriptless</body-content>
        <attribute>
            <name>test</name>
            <required>true</required>
            <rtexprvalue>true</rtexprvalue>
            <type>boolean</type>
        </attribute>
    </tag>
</taglib> 

其中 <uri> 設定是在 JSP 中與 taglib 指示元素的 url 屬性對應用的。每個 <tag> 標籤中使用 <name> 定義了自訂標籤的名稱,使用 <tag-class> 定義標籤處理器類別,而 <body-content> 設定為 scriptless,表示標籤本體中不允許使用 Scriptlet 等元素。

如果標籤上有屬性,則是使用 <attribute> 來設定,<name> 設定屬性名稱,<required> 表示是否一定要設定這個屬性,<rtexprvalue>(也就是 runtime expression value)表示屬性是否接受執行時期運算的結果(例如 EL 運算式的結果),如果設定為 false 或不設定 <rtexprvalue>,表示在 JSP 上設定屬性時僅接受字串形式,<type> 則設定屬性型態。

可以將 TLD 檔案放在 WEB-INF 資料夾下,如此容器就會自動載入它。如果要使用這個標籤,同樣必須在JSP頁面上使用 taglib 指示元素。例如:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="f" uri="https://openhome.cc/jstl/fake" %>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>自訂 if 標籤</title>
    </head>
    <body>
        <f:if test="${param.password == '123456'}">
            你的秘密資料在此!
        </f:if>
    </body>
</html> 

在這個示範的 JSP 頁面中,使用自訂的 <f:if> 標籤,檢查 password 請求參數是否為所設定的數值,如果正確才會顯示 <f:if> 本體的內容。

JSTL 本身並非用 Simple Tag 來實作的,而是使用之後要介紹的 Tag 自訂標籤來實作。在這邊只是用 Simple Tag 來模彷 JSTL 的功能。