天天看點

jsp自定義标簽(taglib)編寫的原理和實作

jsp自定義标簽(taglib)編寫的原理和實作

轉:http://www.javaeye.com/topic/157737

個tag就是一個普通的java類,它惟一特别之處是它必須繼承TagSupport或者BodyTagSupport類。這兩個類提供了一些方法,負責jsp頁面和你編寫的類之間的互動,例如輸入,輸出。而這兩個類是由jsp容器提供的,無須開發人員自己實作。換句話說,你隻需把實作了業務邏輯的類繼承TagSupport或者BodyTagSupport,再做一些特别的工作,你的類就是一個Tag。并且它自己負責和jsp 頁面的互動,不用你多操心。 

“特别的工作”通常有以下幾個步驟: 

[1]提供屬性的set方法,此後這個屬性就可以在jsp頁面設定。以jstl标簽為例 c:out value=""/,這個value就是jsp資料到tag之間的入口。是以tag裡面必須有一個setValue方法,具體的屬性可以不叫value。例如setValue(String data){this.data = data;} 

這個“value”的名稱是在tld裡以attribute元素存在的。 

取什麼名字都可以,隻需tag裡提供相應的set方法即可。 

[2]處理 doStartTag 或 doEndTag 。這兩個方法是 TagSupport提供的。 還是以c:out value=""/為例,當jsp解析這個标簽的時候,在“<”處觸發 doStartTag 事件,在“>”時觸發 doEndTag 事件。通常在 doStartTag 裡進行初始化,流程選擇操作,在 doEndTag 裡後續頁面輸出控制。 

[3]編寫tld檔案,就是把編寫的tag元件的資訊以mxl形式告訴容器,它才好以一定步驟解釋tag元件 

[4]在jsp頁面導入tld。這樣,你的jsp頁面就可以使用自己的tag元件了。 

通常你會發現自己絕大多數活動都集中在 doStartTag 或 doEndTag方法裡,如果在伺服器端處理标簽中的正文或則是嵌套标簽時的話,還是過問一下doAfterBody。 

一個簡單的例子:OutputTag 

package test; 

import javax.servlet.jsp.JspException; 

import javax.servlet.jsp.JspWriter; 

import javax.servlet.jsp.tagext.TagSupport; 

public class OutputTag extends TagSupport { 

private String name=null; 

public void setName(String name) { 

this.name = name; 

public int doEndTag() throws JspException 

try { 

JspWriter out = pageContext.getOut(); 

out.print("Hello! " + name); 

  } catch (Exception e) { throw new JspException(e); } 

return EVAL_PAGE; 

簡要說明: 

1 如何輸出到jsp頁面:調用JspWriter JspWriter out = pageContext.getOut();out.print......記住這個方法就可以了。 

2 輸出後如何作處理,函數會傳回幾個值之一。EVAL_PAGE 表示tag已處理完畢,傳回jsp頁面。還有幾個值,例如 EVAL_BODY_AGAIN 和EVAL_BODY_INCLUDE等 跟流程控制有關. 

編寫tld 

<?xml version="1.0" encoding="ISO-8859-1" ?> 

<!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"> 

<taglib> 

<tlib-version>1.0</tlib-version> 

<jsp-version>1.2</jsp-version> 

<short-name>test</short-name> 

<!--OutputTag--> 

<tag> 

<name>out</name> 

<tag-class>test.OutputTag</tag-class> 

<body-content>empty</body-content> 

<attribute> 

<name>name</name> 

<required>false</required> 

<rtexprvalue>false</rtexprvalue> 

</attribute> 

</tag> 

</taglib> 

在WEB-INF下建立tlds檔案夾,把這個檔案取名為test.tld,放到tlds檔案夾下。引用時的路徑應該這樣:WEB-INF\tlds\test.tld 

關于tld的簡單說明: 

short-name:taglib的名稱,也稱為字首。比如“c:out value=""/” 裡的“c” 

name:tag的名字。例如“c:out value=""/” 裡的"out”,我們的類也取名為out,由于有字首作區分,不會同其他庫的同名tag元件混淆 

tag-class:完整的tag元件路徑,記着帶包名 

body-content:指tag之間的内容。例如c:out value="" ...... /c 起始和關閉标簽之間就是body-content。由于沒有處理body-content ,是以上面設為empty,如果是嵌套标簽,或則是要在伺服器端處理标簽體的話,就是jsp了 

“attribute”裡的name:屬性名字。例如c:out value=""/裡的value。名字可任意取,隻要類裡提供相應的set方法即可。 

required:是否必填屬性。 

rtexprvalue:是否支援運作時表達式取值就是是否可以<%=%>或則是${}方式傳值。 

這是tag的強大功能。 

編寫jsp頁面 

<%@ page language="java"%> 

<%@ taglib uri="/WEB-INF/tlds/test.tld" prefix="test"%> 

<html> 

<body> 

Test Tag: <test:out name="TEST"/> 

</body> 

</html> 

啟動伺服器,如果一切按照上面步驟的話,就能看到 Test Tag: Hello! TEST 字樣。最簡單的tag就這麼出來了。并不難,是不是? 

------------------------------------------------------------------ 

Tag系列的Interface裡定義的靜态int,通過他們也能一窺tag組鍵的執行流程,這幾個靜态值分别是: 

SKIP_BODY : 跳過了開始和結束标簽之間的代碼,一般是在doStartTag中使用 

EVAL_BODY_INCLUDE :處理嵌套的标簽,一般是在doStartTag中使用,由負責處理标簽正文的tag接口提供 

EVAL_BODY_BUFFERED :對包含的内容進行解析 一般是在doStartTag中使用,由負責處理标簽正文的bodyTag接口提供,目的是通知jsp容器作好讀取正文的工作(建立一個body-content包裝正文和擷取存放操作結果的out對象,便于以後的操作和輸出). 

EVAL_BODY_AGAIN:處理标簽正文,嵌套标簽的iteratorTag接口的使用 

SKIP_PAGE : 忽略剩下的頁面,一般是在doEndTag中使用 

EVAL_PAGE : 繼續執行下面的頁, 一般是在doEndTag中使用