1.定製標籤的實現類稱為標籤處理器,簡單標籤處理器指實現SimpleTag介面的類,如下圖的SimpleTagSupport類,該類為SimpleTag介面的預設實現類。
注:不要直接實現SimpleTag介面,應該繼承SimpleTagSupport類,可以直接使用該類已經實現的方法,若該類方法不能滿足業務需求,可重寫相應方法。
.
2.SimpleTag介面定義了5個方法:
- setJspContext方法
- setParent和getParent方法
- setJspBody方法
- doTag方法(非常重要),簡單標籤使用這個方法就可以完成所有的業務邏輯
2.1 setJspContext方法:
用於把JSP頁面的pageContext物件傳遞給標籤處理器物件,若重寫該方法,必須把PageContext賦於成員變數jspContext
2.2 setParent方法:
用於把父標籤處理器物件傳遞給當前標籤處理器物件
2.3 getParent方法:
用於獲得當前標籤的父標籤處理器物件
2.4 setJspBody方法:
用於把代表標籤體的JspFragment物件傳遞給標籤處理器物件,若重寫了該方法,必須賦於成員變數jspFragment
2.5 doTag方法:
用於完成所有的標籤邏輯,包括輸出、迭代、修改標籤體內容等。在doTag方法中可以丟擲javax.servlet.jsp.SkipPageException異常,用於通知WEB容器不再執行JSP頁面中位於結束標記後面的內容,這等效於在傳統標籤的doEndTag方法中返回Tag.SKIP_PAGE常量的情況。
3. SimpleTag介面方法的執行順序
當web容器開始執行標籤時,會呼叫如下方法完成標籤的初始化:
- WEB容器呼叫標籤處理器物件的setJspContext方法,將代表JSP頁面的pageContext物件傳遞給標籤處理器物件。
- WEB容器呼叫標籤處理器物件的setParent方法,將父標籤處理器物件傳遞給這個標籤處理器物件。注意,只有在標籤存在父標籤的情況下,WEB容器才會呼叫這個方法。
- 如果呼叫標籤時設定了屬性,容器將呼叫每個屬性對應的setter方法把屬性值傳遞給標籤處理器物件。如果標籤的屬性值是EL表示式或指令碼表示式,則WEB容器首先計算表示式的值,然後把值傳遞給標籤處理器物件。
- 如果簡單標籤有標籤體,WEB容器將呼叫setJspBody方法把代表標籤體的JspFragment物件傳遞進來。
- 執行標籤時WEB容器呼叫標籤處理器的doTag()方法,開發人員在方法體內透過操作JspFragment物件,就可以實現是否執行、迭代、修改標籤體的目的。
4.JspFragment類介紹
4.1全稱javax.servlet.jsp.tagext.JspFragment,WEB容器在處理簡單標籤的標籤體時,會把標籤體內容用一個JspFragment物件表示,並呼叫標籤處理器物件的setJspBody方法把JspFragment物件傳遞給標籤處理器物件。
4.2 JspFragment類中只定義了兩個方法:
4.2.1 getJspContext方法:public abstract void invoke(java.io.Writer out) ;//用於返回代表呼叫頁面的JspContext物件。
4.2.2 invoke方法:public abstract void invoke(java.io.Writer out);
/*用於執行JspFragment物件所代表的JSP程式碼片段,引數out用於指定將JspFragment物件的執行結果寫入到哪個輸出流物件中,如果 傳遞給引數out的值為null,則將執行結果寫入到JspContext.getOut()方法返回的輸出流物件中。(簡而言之,可以理解為寫給瀏覽器);
該方法是JspFragment最重要的方法,利用這個方法可以控制是否執行和輸出標籤體的內容、是否迭代執行標籤體的內容或對標籤體的執行結果進行修改後再輸出。例如:
在標籤處理器中如果沒有呼叫JspFragment.invoke方法,其結果就相當於忽略標籤體內容;
在標籤處理器中重複呼叫JspFragment.invoke方法,則標籤體內容將會被重複執行;
若想在標籤處理器中修改標籤體內容,只需在呼叫invoke方法時指定一個可取出結果資料的輸出流物件(例如StringWriter),讓標籤體的執行結果輸出到該輸出流物件中,然後從該輸出流物件中取出資料進行修改後再輸出到目標裝置,即可達到修改標籤體的目的。*/
5. 標籤屬性描述:
6.開發簡單標籤實現頁面邏輯
6.1 標籤處理器類:
1 package com.webtest.tag; 2 3 import java.io.IOException; 4 import java.io.StringWriter; 5 6 import javax.servlet.jsp.JspException; 7 import javax.servlet.jsp.PageContext; 8 import javax.servlet.jsp.tagext.JspFragment; 9 import javax.servlet.jsp.tagext.SimpleTagSupport; 10 11 public class TestTag extends SimpleTagSupport { 12 //private JspContext jspContext; 13 //private JspFragment jspFragment; 14 private int count;//定義標籤屬性 15 16 public void setCount(int count){ 17 this.count=count; 18 } 19 @Override 20 public void doTag() throws JspException, IOException { 21 // TODO Auto-generated method stub 22 23 //獲取PageContext物件,若重寫了setJspContext方法,必須把PageContext賦於成員變數jspContext 24 PageContext pageContext = (PageContext) this.getJspContext(); 25 26 pageContext.getOut().print("這裡是10086<br>"); 27 28 29 //得到代表jsp標籤體的JspFragment,若這個類重寫了setJspBody方法,必須賦於成員變數jspFragment,所以不需要呼叫getJspBody方法 30 JspFragment jspFragment=this.getJspBody(); 31 32 //將標籤體的內容輸出到瀏覽器 33 jspFragment.invoke(null); 34 pageContext.getOut().print("<br>"); 35 36 /* 37 * 或者把標籤條輸入緩衝流中,然後對資料進行修改 38 */ 39 StringWriter sw=new StringWriter(); 40 jspFragment.invoke(sw); 41 String str=sw.getBuffer().toString(); 42 str="####"+str+"####"; 43 44 45 pageContext.getOut().print(str+"<br>"); 46 47 //使用標籤屬性 48 for(int i=0;i<count;i++){ 49 jspFragment.invoke(null); 50 } 51 //得到jsp頁面的的PageContext物件 52 //PageContext pageContext = (PageContext) jspFragment.getJspContext(); 53 //呼叫JspWriter將標籤體的內容輸出到瀏覽器 54 //jspFragment.invoke(pageContext.getOut()); 55 System.out.println("doTag方法"); 56 57 } 58 59 /* public JspTag getParent() { 60 // TODO Auto-generated method stub 61 System.out.println("getParent方法"); 62 return null; 63 }*/ 64 65 /** 66 * 當重寫setJspBody方法時,需要把傳如的JspFragment物件賦值給一個類變數,以供使用 67 */ 68 /* 69 public void setJspBody(JspFragment jspBody) { 70 // TODO Auto-generated method stub 71 jspFragment=jspBody; 72 System.out.println("setJspBody方法"); 73 } 74 75 public void setJspContext(JspContext pc) { 76 // TODO Auto-generated method stub 77 System.out.println("setJspContext方法"); 78 jspContext=pc; 79 } 80 81 public void setParent(JspTag parent) { 82 // TODO Auto-generated method stub 83 System.out.println("setParent方法"); 84 }*/ 85 86 }
6.2 標籤描述檔案,是xml檔案,以tld為字尾名,一般放在WEB-INF目錄下,也可以置於其他目錄:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <taglib xmlns="http://java.sun.com/xml/ns/j2ee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" 5 version="2.0"> 6 <!-- 用於對自定義標籤庫的描述 --> 7 <description>自定義標籤庫</description> 8 <!-- 標籤庫的 版本號 --> 9 <tlib-version>1.0</tlib-version> 10 <short-name>GaclSimpleTagLibrary</short-name> 11 <!-- 12 為自定義標籤庫設定uri,以 / 開頭,/之後的內容隨意,如這裡的/simpletag,但應該把其設定成與檔名相同,以便知道引用哪個標籤庫 13 在jsp頁面使用自定義標籤時,需要先引入標籤庫,其透過uri找到標籤庫, 14 jsp頁面引入標籤庫:<%@taglib uri="/simpletag" prefix="gacl" %> 15 其中的prefix屬性用於使用自定義標籤時的字首,如同EL中的c,如:<gacl:tagtest/> 16 --> 17 <uri>/mytags</uri> 18 <!-- 一個taglib(標籤庫)可以包含多個自定義標籤,每個自定義標籤使用一個tag來描述 --> 19 <tag> 20 <!-- 描述 --> 21 <description>SimpleTag(簡單標籤)tagtest</description> 22 <!-- 標籤名,為標籤處理器類配一個標籤名,使其在jsp頁面可以透過標籤名找到 --> 23 <name>tagtest</name> 24 <!-- 標籤對應的標籤處理器類 --> 25 <tag-class>com.webtest.tag.TestTag</tag-class> 26 <!-- 27 tld檔案中有四種標籤體型別 :empty JSP scriptless tagdepentend 28 在簡單標籤(SampleTag)中標籤體body-content的值只允許是empty和scriptless,不允許設定成JSP,如果設定成JSP就會出現異常 29 在傳統標籤中標籤體body-content的值只允許是empty和JSP 30 如果標籤體body-content的值設定成tagdepentend,那麼就表示標籤體裡面的內容是給標籤處理器類使用的, 31 例如:開發一個查詢使用者的sql標籤,此時標籤體重的SQL語句就是給SQL標籤的標籤處理器來使用的 32 <gacl:sql>SELECT * FROM USER</gacl:sql> 33 在這種情況下,sql標籤的<body-content>就要設定成tagdepentend,tagdepentend用得比較少,瞭解一下即可 34 --> 35 <body-content>scriptless</body-content> 36 <!-- 標籤屬性描述 --> 37 <attribute> 38 <description>描述標籤的count屬性</description> 39 <name>count</name> 40 <!-- 用於表示此屬性是否必須設定,預設為false,即可以不設定該屬性的值 --> 41 <required>true</required> 42 <!-- rtexprvalue用於指示標籤屬性值是否可以是一個表示式,一般設定為true,表示可以是表示式 --> 43 <rtexprvalue>true</rtexprvalue> 44 </attribute> 45 </tag> 46 </taglib>
6.3 jsp檔案:
1 <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> 2 3 <%--匯入自定義標籤庫 --%> 4 <%@taglib uri="/mytags" prefix="gacl" %> 5 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 7 <html> 8 <head> 9 <title>My JSP 'index.jsp' starting page</title> 10 <meta http-equiv="pragma" content="no-cache"> 11 <meta http-equiv="cache-control" content="no-cache"> 12 <meta http-equiv="expires" content="0"> 13 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> 14 <meta http-equiv="description" content="This is my page"> 15 <!-- 16 <link rel="stylesheet" type="text/css" href="styles.css"> 17 --> 18 </head> 19 20 <body> 21 <gacl:tagtest count="5">我是自定義標籤<p></gacl:tagtest> 22 23 </body> 24 </html>