Java ---自定義標簽


     本篇文章介紹自定義標簽,可能在工作中很少涉及到自己來定義一個標簽庫,因為我們基本上都是使用的大神寫的標簽庫,基本上直接使用即可,但是從自身的發展來看,通往高級程序員的道路上,開發框架就需要大量的使用到標簽庫技術。本文將從以下幾個方面介紹自定義標簽庫的基本知識點:

  • 背景以及作用
  • 開發簡單的標簽
  • 開發帶屬性的標簽
  • 開發帶標簽體的標簽
  • 以頁面片段為屬性的標簽
  • 具有動態屬性的標簽

一、標簽庫有什么作用
     自定義標簽庫是一種優秀的表現層技術,之前介紹的MVC模式,我們使用jsp作為表現層,但是jsp語法嵌套在html頁面,美工還是很難直接參與開發,並且jsp腳本和html代碼耦合在一起,維護成本較高。我們能不能開發一套和html風格類似並且能完成jsp腳本功能的標簽來解決這種低效的協作方式呢?於是標簽庫就誕生了。
這里寫圖片描述

這是Java中標簽規范的繼承體系,實現Tag接口的我們叫做傳統式標簽庫開發,這種開發模式略顯發復雜,基本已經被SimpleTag式的簡單式開發標簽庫給取代了。Java中提供了一個默認的實現類SimpleTagSupport來實現自定義標簽,我們只要繼承此類即可。

二、開發一個最簡單的標簽庫
     開發一個自定義標簽庫的過程如下:

  • 開發自定義標簽處理類
  • 創建*.tld文件,每個此文件對應一個標簽庫,標簽庫中可以由多個標簽
  • 在jsp頁面使用標簽

首先我們先從自定義標簽處理類開始,正如上文所說,這個類只有繼承了SimpleTagSupport這個類可以省去省去重寫SimpleTag接口中的一些方法。我們說個doTag()這個方法很重要,這個方法類似於我么main方法一樣,當jsp頁面加載到我們定義的標簽的時候就會過來調用這個方法。

public class MyTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().write("hello walker");
    }
}

這是一個簡單的標簽處理類,具體的細節暫時不用關心,只需要知道,它負責向jsp頁面輸出字符串即可。下面我們看看第二步,創建*tld文件。這個文件我們沒有必要重新寫一遍,到Tomcat服務器上的webapps/examples/WEB-INF/jsp2中復制一個過來,修改名字存放到我們的項目中WEB-INF的任意子路徑下。刪除一些標簽成如下內容:
這里寫圖片描述
我們看到這是一個XML文件,根元素為taglib,而taglib主要有以下幾個子元素:

  • description //描述信息
  • tlib-version //指定標簽庫的版本號,基本不用我們操心
  • short-name //指定標簽庫的短名字,也是沒什么用
  • uri //這是一個重要的子元素,是該標簽庫的唯一標識
  • tag //看名字就知道,這是定義標簽的子元素,很重要

     對於taglib這個根元素,我們主要關心他下面的uri和tag兩個子元素,一個標簽庫可以由多個標簽,也就是可以有多個tag標簽。關於tag標簽,主要有以下幾個子元素:

  • description //描述信息
  • name //該標簽的唯一標識,很重要
  • tag-class //指定了處理該標簽的類,也就是使用該標簽誰給我返回結果
  • body-content //標簽體,后面詳說,很重要
  • attribute //屬性,后面介紹,很重要

對於以上標簽大家可能已經知道什么意思,但是具體用在什么地方可能不清楚,本小節的最后會綜合三個步驟自定義一個簡單的標簽。接下來介紹在jsp頁面是如何使用標簽。
     使用標簽庫也是有兩個步驟,首先導入標簽庫,然后引用標簽。我們使用taglib編譯指令導入標簽庫,具體格式如下:

<%@ taglib uri="tld文件中指定的唯一標識" prefix="指定標簽前綴"%>

我們看到這個導入標簽庫的編譯指令主要有兩個屬性,一個是用於定位我們已經寫好的標簽庫,定位的方法就是讀取每個tld文件中的URI元素的值,prefix用於指定我們使用標簽時的前綴,等用的時候就很容易理解了,現在解釋反而不容易說清楚。我們使用標簽的格式如下:

<剛剛指定的前綴 :標簽名 />

標簽名就是我們標簽庫中每個tag都會有的name的值,這指定了該語句是引用的那個標簽。下面我們通過具體的例子直觀感受下。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytags"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <mytags:hello />
  </body>
</html>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
    <description>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <uri>mytid</uri>

    <tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>empty</body-content>
    </tag>

</taglib>
public class MyTag extends SimpleTagSupport {

    @Override
    public void doTag() throws JspException, IOException {
        getJspContext().getOut().write("hello walker");
    }
}

結果如下:
這里寫圖片描述

     這就完成了一個最簡單的標簽庫的定義和使用的過程,首先我們在index.jsp頁面通過URI引入mytag標簽庫,指定了使用該標簽庫的前綴為mytags,然后<mytags:hello />引用name為hello的tag標簽,然而在加載這條語句的時候會通過我們的tag中指定的處理類,找到它並執行,最后通過此標簽處理類想我們的jsp頁面輸出了一個字符串。以上就是一個最簡單的自定義標簽的過程,為了更好的理解后續的較復雜的自定義標簽方式,上述內容值得感受體會。

三、開發帶屬性的標簽
     假如我們通過攔截器獲取了從數據庫查出來的一個結果集,我們此處希望調用標簽來將結果集以表格的形式輸出來,此時我們的這個結果集又該如何傳到標簽處理類中呢?這時我們可以使用屬性。具體看代碼:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="mytid" prefix="mytag"%>
<html>
  <head>
    <title></title>
  </head>
  <body>
  <%
    HashMap<String,Integer> maps = new HashMap<String, Integer>();
    maps.put("李四",53);
    maps.put("張三",23);
    maps.put("walker",22);
    pageContext.setAttribute("map",maps);
  %>
      <table>
        <mytag:hello map="map"/>
      </table>
  </body>
</html>
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
    <description>A tag library exercising SimpleTag handlers.</description>
    <tlib-version>1.0</tlib-version>
    <short-name>SimpleTagLibrary</short-name>
    <uri>mytid</uri>

    <tag>
        <description>Outputs a colored tile</description>
        <name>hello</name>
        <tag-class>Test.MyTag</tag-class>
        <body-content>empty</body-content>
        <attribute>
            <name>map</name>
            <required>true</required>
            <fragment>true</fragment>
        </attribute>
    </tag>

</taglib>
public class MyTag extends SimpleTagSupport {

    private String map;
    public String getMap(){
        return this.map;
    }
    public void setMap(String map){
        this.map = map;
    }
    @Override
    public void doTag() throws JspException, IOException {
        HashMap<String,Integer> maps = (HashMap<String,Integer>)(getJspContext().getAttribute(map));
        Object[] array = maps.keySet().toArray();

        for (String str : maps.keySet()){
            getJspContext().getOut().write("<tr>");
            getJspContext().getOut().write("<td>");
            getJspContext().getOut().write(str);
            getJspContext().getOut().write("</td>");
            getJspContext().getOut().write("<td>");
            getJspContext().getOut().write(""+maps.get(str));
            getJspContext().getOut().write("</td>");
            getJspContext().getOut().write("</tr>");
        }
    }
}

這里寫圖片描述

我們首先先從index.jsp頁面看起,首先我們定義了一個HashMap用來存放一個簡單的個人信息,鍵為姓名值為年齡。最后我們設置共享范圍為當前page。然后<mytag:hello map="map"/>,這里的map=“map”,第一個map是屬性名,第二個只是一個字符串。下面進入到tld頁面看,這個頁面基本沒有什么改動,只是多了個attribute元素,attribute中有幾個子元素,第一個是name指定這個屬性的唯一標識,第二個required指定該屬性是否是必須屬性。第三個fragment指定該屬性是否支持jsp腳本。主要關心name這個元素。這個值和jsp頁面調用標簽時使用的屬性名必須一樣,並且這個屬性值還必須和標簽處理類中的私有屬性名一樣,這就是為了jsp頁面的屬性值能夠自動的傳入到標簽處理類的屬性中,我們看這個標簽處理類
     這個類定義了私有屬性map,和我們的tld文件中的屬性名是一致的。getJspContext().getAttribute(map),首先是獲得了調用該標簽的jsp頁面的pageContext,這就是方法getJspContext的返回值,因為我們在jsp頁面設置了一個共享數據(maps),於是我們同名名字獲取該對象,這里的map就是我們的私有屬性,他的值被自動賦值了,具體的值就是jsp頁面傳入的參數。后面的代碼就很簡單了,循環輸出數據到jsp頁面上。
     稍微理一下思路,這種帶屬性的標簽使用其實和無屬性差不多,都是先引入了標簽庫,加載標簽的的時候通過URI找到對應的標簽庫,只不過這次將一個字符串賦值給了tld中attribute元素中名為map的屬性,然后跳向對應的標簽處理類,順便把map屬性的值自動賦值處理類中的私有屬性,然后執行輸出代碼。其中需要注意的是屬性名一定要統一,另外,如果標簽的屬性值是8種基本數據類型,那么在JSP頁面在傳遞字符串時,JSP引擎會自動轉換成相應的類型,但如果標簽的屬性值是復合數據類型,那么JSP引擎是無法自動轉換的。對於傳遞非基本數據類型的操作,后續文章會介紹。

     為了篇幅不過於長,還剩下的內容留在下篇,如有錯誤,望指出!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM