javascript
JSP自定义标签学习笔记
http://blog.csdn.net/liangbinny/article/details/6309893
本文是本人學習《JavaWeb學習》書籍所記下的學習筆記
?
一、概述
?
JSP 2.0 中提供了兩種新的開發自定義標記的方法:
1、簡單標簽機制SimpleTag
JSP 2.0 中加入了新的創建自定義標記的API:javax.servlet.jsp.tagext.SimpleTag,該API 定義了用來實現簡單標記的接口。和JSP 1.2 中的已有接口不同的是,SimpleTag 接口不使用doStartTag()和doEndTag()方法,而提供了一個簡單的doTag()方法。這個方法在調用該標記時只被使用一次。一個自定義標記中實現的所有邏輯都在這個方法中實現。相對JSP1.2 中自定義標記機制,SimpleTag 的方法和處理周期要簡單得多。
?
2、 標簽文件
標簽文件允許JSP 網頁作者使用JSP 語法創建可復用的標簽庫。標簽文件的擴展名必須是.tag。
?
1.1 使用簡單標簽機制
與JSP1.2 相似,開發自定義標簽要遵循“開發標記類---配置TLD 文件----在JSP 中使用”的過程,
示例如下:
步驟一:編寫標記處理類AddTag.java
package tag;
?
import java.io.IOException;
?
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.SimpleTagSupport;
?
public class AddTag extends SimpleTagSupport{
???????? private int num1 = 0;
???????? private int num2 = 0;
???????? public void setNum1(int num1) {
?????????????????? this.num1 = num1;
???????? }
???????? public void setNum2(int num2) {
?????????????????? this.num2 = num2;
???????? }
???????? public void doTag() throws JspException, IOException {
?????????????????? JspContext ctx = getJspContext();
?????????????????? JspWriter out = ctx.getOut();
?????????????????? int sun = num1+num2;
?????????????????? out.print(num1+"+"+num2+"="+sun);
???????? }
}
?
步驟二:編寫描述符文件 test.tld:放在/WEB-INF/test-tld/test.tld下
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">
<taglib><!-- 標簽定義成<test:add /> -->
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.2</jspversion>
??? <shortname>test</shortname><!-- 這個test可以設置為空,你標簽就可以定義成<add />了,不過一般比較常見的都是<test:add />這種類型的 -->
??? <tag>
?????? <name>add</name>
?????? <tagclass>tag.AddTag</tagclass>
?????? <bodycontent>empty</bodycontent><!-- 就是<test:add ></test>中間的內容是空的 -->
?????? <info>Add Tag</info>
?????? <attribute>
?????????? <name>num1</name>
?????????? <required>true</required>
?????????? <rtexprvalue>true</rtexprvalue>
?????? </attribute>
?????? <attribute>
?????????? <name>num2</name>
?????????? <required>true</required>
?????????? <rtexprvalue>true</rtexprvalue>
?????? </attribute>
??? </tag>
</taglib>
?
?
步驟三:在JSP 中使用標記:
<%@ page language="java"?? pageEncoding="UTF-8"%>
<%@ taglib prefix="test" uri="/WEB-INF/test-tld/test.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>測試自定義標簽</title>
? </head>
? <body>
? ????? SimpleTag 測試:<br />
? ????? <h1><test:add num1="2" num2="3"/></h1>
? </body>
</html>
?
無需在web.xml下配置,
運行結果如下:
?
?
?
?
?
1.2 使用標簽文件
通過標簽文件實際上可以將一個JSP 文件的內容作為標簽處理程序,但該文件擴展名必須是.tag,
示例如下:
1) 標記文件hello.tag,該文件存放在 WEB-INF/tags 目錄下
hello.tag.<br>
IP:<%= request.getRemoteAddr() %>
2) 在JSP 中使用tag 文件
<%@ page contentType="text/html;charset=gb2312" %>
<%@ taglib prefix="test" tagdir="/WEB-INF/tags/" %>
<h2>Tag File 測試</h2>
<test:hello/>
3) 運行效果如下:
?
二 、自定義標簽簡介
?
2.1 自定義標簽概念
?
JSP標簽分為標準JSP 環境自帶的標簽(即前面章節中學習過的JSP 動作標簽)和JSP 自定義標簽。JSP 自定義標簽是用戶定義的標記,它遵循XML 語法。當servlet 容器處理自定義標記時,會自動調用一個Java 類文件完成相對應的功能。
Java 開發人員編寫標記處理程序類以處理標記并處理所有需要的Java 代碼和數據操作。對于Web頁面設計者來說,自定義標記與標準HTML 標記使用起來沒什么區別,但HTML 標記只能完成前臺顯示的功能,而自定義標記可以在后臺完成某些操作。
正確編寫自定義標記可以讓 Web 設計者創建、查詢和操作數據而無需編寫一行Java 代碼。正確使用自定義標記使 Java 開發人員不必再在編碼過程中考慮表示層。這樣應用程序開發小組的每一位成員都可以關注于他或者她最擅長的事物。
所以說,JSP 自定義標記為在動態Web 頁中將表示與業務邏輯分離提供了一種標準化的機制,使頁面設計者可以將注意力放到表示上,而應用程序開發人員編寫后端的代碼。
?
2.2 標簽相關概念
JSP 自定義標簽的使用語法與普通HTML標簽相同,與自定義標簽相關的基本術語簡單說明如下,
這些術語在開發JSP 自定義標簽時要用到:
1) 自結束標簽——沒有標記體的標簽
示例:<test:myhrtag />
說明:假設myhrtag 是一個自定義標簽
2) 屬性
示例:<test:myhrtag color=”red” />
說明:以上標簽中包含了color 屬性,值為red
3) 帶標記體的標簽
示例:<test:myhrtag > xxxxx </test:myhrtag>
說明:以上標簽中間的xxxxx 即為標記體
4) 子標記
示例: <test:myhrtag >
<test:mytag2/>
</test:myhrtag>
說明:以上myhrtag 標簽中間的mytag2 即為子標記
?
?
2.3 如何創建自定義標簽
?
自定義標簽功能的實現要求在后臺必須有一個相關的JAVA 類的支持,但并不是任意編寫一個JAVA 類就能處理JSP 標簽,這個類也必須實現指定的規范才能用于支持JSP 標簽,這些規范表現形式也是接口和類,它們在javax.servlet.jsp.tagext包中聲明,主要接口/類的描述如下:
javax.servlet.jsp.tagext.Tag 接口,所有處理JSP 標簽的類必須實現該接口。該接口中聲明了6個方法,如果直接從該接口生成類則必須實現所有的6 個方法,通常不會直接通過該接口生成標簽的處理類。
?javax.servlet.jsp.tagext.TagSupport 類,該類實現了Tag 接口,用于創建不帶標記體的自結束標簽,這些標簽中可以帶屬性。
javax.servlet.jsp.tagext.BodyTagSupport 類,該類繼承了TagSupport,用于創建帶標記體的標簽。
??? 通常我們自定義的標簽,編寫處理程序時使用TagSupport 和BodyTagSupport 即可,不需要涉及到標簽體的,繼承TagSupport,需要用標簽體的,用BodyTagSupport,以下是開發和使用一個JSP 自定義標簽的全過程:
1) 開發標記處理類,編譯生成class 文件,該類要繼承TagSupport 或BodyTagSupport;
2) 創建標記庫描述符文件*.tld,在該文件中為標記處理類指定標簽名、聲明標簽屬性;
3) 在JSP 中引用標簽庫;
4) 在JSP 中使用標JSP 標簽
?
三、自結束標簽(不帶標簽體,TagSupport)
3.1 自結束標簽簡介
這是一種不帶標記體的標簽,所以該類標簽的處理類直接繼承javax.servlet.jsp.tagext.TagSupport即可。TagSupport 的主要方法如下:
public int doStartTag() throws JspException
在WEB 容器遇到標簽開始時,該方法會運行。
public int doEndTag() throws JspException
在WEB 容器遇到標簽結束時,該方法會運行。
???????? TagSupport 類中有一個重要的成員:pageContext,該成員的功能與JSP 的內置對象pageContex完全相同。通過該對象可以得到其他幾個JSP 對象的引用。這樣,我們就可以在JAVA 類中與JSP 進行交互了。如: JspWriter out=pageContext.getOut();這一語句可以得到JSP 內置對象out 的引用,通過out 我們就可以向客戶端瀏覽器中輸出內容了。要使用其他幾個JSP 對象原理與此相同。
?
3.2自結束標簽開發示例
?
方式二:動態引用
步驟一:編寫標記處理類
package tag;
?
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
?
/**
?*自定義自結束標簽,不含標簽體。
?*
?*1、在自定義的類中,重寫了父類TagSupport的兩個方法:doStartTag()、doEndTag(),在容器遇到標記開始時會運行doStartTag(),遇到標記結束時運行doEndTag()方法;
?*2、doStartTag()方法的返回值:通??梢匀蓚€值:
?* ???? EVAL_BODY_INCLUDE——包含標記體,本例中要編寫自結束標記所以不使用該值;
?* ???? SKIP_BODY——跳過標記體,即不處理標記體,開發自結束標記應該使用該值。
?*3、doEndTag()方法的返回值:通??梢匀蓚€值:
?* ???? SKIP_PAGE——返回這個值,則終止頁面執行;
?* ???? EVAL_PAGE——返回該值則處理完當前標記后,JSP頁面中止運行。
?*/
?
publicclass MyHrTag extends TagSupport{
?
??? /**
??? ?*
??? ?*/
??? privatestaticfinallongserialVersionUID = 1L;
?
??? /*
??? ?* 在WEB 容器遇到標簽開始時,該方法會運行。
??? ?* 該方法可以自行定義,也可以不定義。不定義該方法則遇到開始標簽什么都不做
??? ?* */
??? publicint doStartTag() throws JspException {
?????? try {
?????????? //得到網絡輸出流,pageContext 是從父類繼承過來的成員
?????????? JspWriter out = pageContext.getOut();
?????????? //向網頁輸出內容
?????????? out.println("<h4>開始執行doStartTag()......</h4>");
?????????? //輸出5 條水平線;
?????????? for(int i=1; i<=5; i++){
????????????? out.println("<hr>");
?????????? }
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
?????? //return EVAL_BODY_INCLUDE; //處理標記體
?????? return Tag.SKIP_BODY; //跳過標記體;
??? }
???
??? /*
??? ?* 在WEB 容器遇到標簽結束時,該方法會運行。
??? ?* 該方法可以自行定義,也可以不定義。不定義該方法則遇到結束標簽什么都不做
??? ?* */
??? publicint doEndTag() throws JspException {
?????? try {
?????????? JspWriter out=pageContext.getOut();
?????????? out.println("<h3>開始執行doEndTag().....</h3>.");
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
?????? //return Tag.SKIP_PAGE; //返回這個值,則終止頁面執行;
?????? returnEVAL_PAGE;
??? }
}
?
步驟二:創建標記庫描述符文件myhr.tld,該文件要存放在 WEB-INF/test-tld 目錄下:
?
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
在tld 文件中,映射了標記名和處理程序類;
<tallib>元素,代表開始一個標記庫的描述
<tligversion>元素,代表標記庫的版本
<jspversion>元素,代表標記所支持的JSP 的版本
<shortname>為標記庫起別名,相當于注釋,無實際用途
<tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>myhr</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>MyHr</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.MyHrTag</tagclass>
?????? <bodycontent>EMPTY</bodycontent>
??? </tag>
</taglib>
?
?
步驟三:在JSP 中引用標記庫描述文件
引用標記庫有兩種方式,分別稱為靜態引用和動態引用。
方式一:動態引用(即直接在JSP 頁面中使用TLD 文件)
<%@ page language="java"? pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/test-tld/myhr.tld" prefix="myhr" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>My JSP 'MyHr1.jsp' starting page</title>
? </head>
? <body>
?? <myhr:MyHr/>
? </body>
</html>
?
JSP 指令<%@ taglib... %>用于引用標記庫,該指令的兩個屬性作用如下:
uri——指明要引用的標記庫,在靜態引用中就是TLD 文件的路徑
prefix——為標記起的前綴名,可以防止多個標記重名的情況出現
?
方式二:靜態引用
首先在web.xml 中為TLD 文件聲明別名:
<?xml version="1.0" encoding="ISO-8859-1" ?>
<Web-app>
……
<taglib>
<taglib-uri>myhr2</taglib-uri>
<taglib-location>/WEB-INF/myhr.tld</taglib-location>
</taglib>
……
</Web-app>
然后在JSP 中通過別名引用TLD 文件:
<%@ page language="java"? pageEncoding="UTF-8"%>
<%@ taglib uri="myhr2" prefix="myhr" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>My JSP 'MyHr1.jsp' starting page</title>
? </head>
? <body>
?? <myhr:MyHr/>
? </body>
</html>
到此為止,自結束標簽開發完畢,其中主要工作有兩個:開發標記處理類、配置TLD 文件。訪
問JSP,運行結果如下:
?
?
四、標簽中的屬性
4.1 為自定義標簽添加屬性
以上的示例中開發了一個簡單的JSP 標簽,但一個實用的標簽通常還要由屬性來制定標簽的特定行為,以下示例演示為自定義標簽添加屬性。該示例在1.2 示例基礎上,為標簽添加了color 和loop兩個自定義屬性,以控制水平線的顏色和輸出的水平線的數量。
步驟一:編寫標記處理類
package tag;
?
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
?
/**
?*
?*該類為自定義標簽添加了兩個屬性,屬性的聲明與javabean語法完全相同,即屬性本身是private類型,
?*但要求提供public的get、set方法。
?*?
?*/
?
publicclass MyHrTag2 extends TagSupport{
???
??? //聲明屬性
??? private String color = "black"; //定義線條顏色
??? private String loop = "1"; //定義輸出水平線的條數
???
??? //嚴格按照javabean模式
??? publicvoid setColor(String color) {
?????? this.color = color;
??? }
???
??? //嚴格按照javabean模式
??? publicvoid setLoop(String loop) {
?????? this.loop = loop;
??? }
???
??? //只定義遇到開始標簽執行方法即可了。
??? publicint doStartTag() throws JspException {
?????? try {
?????????? //得到網絡輸出流
?????????? JspWriter out = pageContext.getOut();
?????????? //向網頁輸出內容;
?????????? out.println("<h4>開始執行doStartTag()......</h4>");
?????????? int n = Integer.parseInt(loop);
?????????? for (int i=1;i<=n;i++) {
????????????? out.print("<hr color='"+this.color+"' />");
?????????? }
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
?????? return Tag.SKIP_BODY;
??? }
???
}
?
步驟二:創建TLD 文件,本例中是在1.2 中的myhr.tld 文件中進行修改得到:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
?? 在tld 文件中,映射了標記名和處理程序類;
?? <tallib>元素,代表開始一個標記庫的描述
?? <tligversion>元素,代表標記庫的版本
?? <jspversion>元素,代表標記所支持的JSP 的版本
?? <shortname>為標記庫起別名,相當于注釋,無實際用途
?? <tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
??? <tag>中的子元素
?????? <attribute>用于為標簽聲明屬性,其子元素如下:
?????????? <name>——用于指定屬性名稱
?????????? <required>——用于聲明該屬性是否為必需的,本例中聲明color、loop 兩個屬性都不是必需的。
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>myhr</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>MyHr</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.MyHrTag</tagclass>
?????? <bodycontent>EMPTY</bodycontent>
??? </tag>
??? <tag>
?????? <name>MyHr2</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.MyHrTag2</tagclass>
?????? <bodycontent>EMPTY</bodycontent>
?????? <attribute>
?????????? <name>color</name>
?????????? <required>false</required>
?????? </attribute>
?????? <attribute>
?????????? <name>loop</name>
?????????? <required>false</required>
?????? </attribute>
??? </tag>
</taglib>
?
步驟三:在JSP 中引用TLD,并使用標簽
<%@ page language="java"? pageEncoding="UTF-8"%>
<%@ taglib uri="/WEB-INF/test-tld/myhr.tld" prefix="myhr" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>My JSP 'MyHr3.jsp' starting page</title>
? </head>
? <body>
??? 第一次測試(未賦屬性值):<br>
??? <myhr:MyHr2/>
???
??? 第二次測試(使用兩個屬性):<br>
??? <myhr:MyHr2 color="red" loop="3"/>
???
??? 第三次測試(使用一個屬性):<br>
??? <myhr:MyHr2 color="blue"/>
???
??? 測試完畢.
? </body>
</html>
?
運行圖
?
?
?
4.2 標簽綜合示例
該示例中創建了一個JSP 標簽,用于在JSP 中判斷用戶是否登錄過,如果沒登錄過則自動轉到登錄頁,這樣就可以避免在JSP 中使用代碼段進行業務判斷了。
第一步:定義標簽類LoginTag.java,為標記處理程序,從session 中取出登錄標志進行判斷用戶是否登錄過:
package tag;
?
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.Tag;
import javax.servlet.jsp.tagext.TagSupport;
?
publicclass LoginTag extends TagSupport{
?
??? publicint doStartTag() throws JspException {
?????? try {
?????????? HttpSession session = pageContext.getSession();
?????????? Object obj = session.getAttribute("User");
?????????? //判斷是否從未登錄過,如果沒登錄過則轉到登錄頁;
?????????? if(obj==null){
????????????? ((HttpServletResponse)pageContext.getResponse()).sendRedirect("login.html");
????????????? returnSKIP_BODY;
?????????? }
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
?????? return Tag.SKIP_BODY;
??? }
}
?
第二步:編寫login.tld
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
??? 在tld 文件中,映射了標記名和處理程序類;
??? <tallib>元素,代表開始一個標記庫的描述
??? <tligversion>元素,代表標記庫的版本
??? <jspversion>元素,代表標記所支持的JSP 的版本
??? <shortname>為標記庫起別名,相當于注釋,無實際用途
??? <tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
??? <tag>中的子元素
?????? <attribute>用于為標簽聲明屬性,其子元素如下:
?????????? <name>——用于指定屬性名稱
?????????? <required>——用于聲明該屬性是否為必需的,本例中聲明color、loop 兩個屬性都不是必需的。
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>test</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>islogin</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.LoginTag</tagclass>
?????? <bodycontent>EMPTY</bodycontent>
??? </tag>
</taglib>
?
第三步:動態調用標簽
部分內容如下:
<%@ page language="java" contentType="text/html;charset=GB2312"%>
<%@ taglib uri="/WEB-INF/myhr.tld" prefix="test" %>
….
<test:islogin/>
<h3>歡迎</h3>
….
?
?
?
4.3 TLD 文件概述
以上示例中創建了標記描述符文件*.TLD,現總結該文件的用法如下:
該文件必須放在 WEB-INF 目錄下;
該文件是XML 格式的文件,各元素及功能說明如下:
元素??? 說明
<taglib> 代表開始一個標記庫的描述
<tlibversion> 代表標記庫的版本,是自定義的
<jspversion> 代表標記所支持的JSP 的版本
<shortname> 為標記庫起別名,相當于注釋,無實際用途
<tag> ??? 代表開始描述一個標記
表11-1 標記描述符TLD 文件元素說明
其中<tag>元素中又包含若干子元素,說明如下:
元素 說明
<name> 為標記處理類起的標記名
<tagclass> 指定標記處理類的全名(即帶包的名字)
<bodycontent> 標記體的內容類型,如果為EMPTY 代表無標記體
<attribute> 用于為標簽聲明屬性
表11-2 <tag>元素的子元素
<attribute>元素為標簽聲明屬性時,需要兩個子元素:
<name> 用于指定屬性名稱
<required> 用于聲明該屬性是否為必需的
?
?
五、標簽中的標記體
5.1 標記體簡介
標簽的標記體是 JSP 頁中出現在自定義標簽的開始和結束標簽之間的數據,標記體也稱正文。操縱其正文的標簽稱為帶標記體的標簽(也稱為正文標簽)。
可以編寫標簽處理程序對標簽的標記體進行操作。要編寫標記體標簽處理程序,必須實現BodyTag 接口。BodyTag 繼承了Tag 的所有方法,而且還實現了另外兩個處理正文內容的方法,見下表:
?????????????????? 方法 ?????????????????????????? 說明
setBodyContent(BodyContent b)???????????????? bodyContent 屬性的 Setter 方法
doInitBody() ?????????????????????????????????????????? ?對正文內容進行初始化操作
?
為方便開發,在JSP 類庫中為BodyTag 接口提供了實現類:javax.servlet.jsp.tagext.BodyTagSupport。該類繼承了TagSupport 并實現了BodyTag 接口。因此,標記體標簽處理程序只需要覆蓋要使用的方法。BodyTagSupport 類中定義了一個protected bodyContent 成員變量及get/setBodyContent()方法,bodyContent 是一個緩沖區,用以保存標記體正文內容。
在一個標簽處理類中,BodyTag 的處理流程如下:
???????? 1、當容器創建一個新的標簽實例后,通過setPageContext 來設置標簽的頁面上下文。
2、使用setParent 方法設置這個標簽的上一級標簽,如果沒有上一級嵌套,設置為null。
3、設置標簽的屬性,如果沒有定義屬性,就不調用此類方法。
4、調用doStartTag 方法,這個方法可以返回以下三者之一:EVAL_BODY_INCLUDE、
EVAL_BODY_BUFFERED、SKIP_BODY,當返回EVAL_BODY_INCLUDE 時,就將標記
體直接寫到輸出流中,如果返回SKIP_BODY,就不再計算標簽的正文,如果返回EVAL_BODY_BUFFERED,就將標記體的正文包含到bodyContent 成員中。
5、調用setBodyContent 設置當前的BodyContent.
6、調用doInitBody,可以在該方法中對BodyContent 進行一些初始化操作.每次計算完Body 后調用doAfterBody,如果返回EVAL_BODY_AGAIN,表示繼續處理一次標記體,直到返回SKIP_BODY 才繼續往下執行.
7、調用doEndTag 方法,結束標簽處理.
?
5.2 一個簡單的帶標記體的標簽
?
本示例中創建了一個標簽用于在瀏覽器中輸出其標記體內容,且輸出的次數由標簽的屬性決定:
???????? 步驟一:編寫標記處理類
package tag;
?
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
?
/**
?*
?*doStartTag()中的返回值EVAL_BODY_INCLUDE,可以直接將標簽的正文內容輸出到瀏覽器中。
?*doAfterBody()在處理完一次正文后會自動執行,
?*該方法如果返回EVAL_BODY_AGAIN,則代表再處理一遍正文(即輸出到瀏覽器),返回SKIP_BODY代表正文處理到此結束。
?*本例中循環向瀏覽器中輸出標記體的正文,直到屬性loop的值小于1。
?*
?*/
?
publicclass TestBodyTag extends BodyTagSupport {
??? privateintloop ; //定義輸出標簽體的次數屬性,比如:2的話就表示連續重復輸出標簽體2次
?
??? publicvoid setLoop(int loop) {
?????? this.loop = loop;
??? }
?
??? publicint doStartTag() throws JspException {
?????? if(loop>0){
?????????? returnEVAL_BODY_INCLUDE; //自動將標簽體包含到輸出流中,第一次將標簽體輸出到瀏覽器中.
?????? }else {
?????????? returnSKIP_BODY; //跳過標簽體,不將標簽體包含到輸出流,不處理標簽體,直接忽略.
?????? }
??? }
?
??? publicint doAfterBody() throws JspException {
?????? /**
?????? ?*doAfterBody()在處理完一次正文后會自動執行,
?????? ?*該方法如果返回EVAL_BODY_AGAIN,則代表再處理一遍正文(即輸出到瀏覽器),返回SKIP_BODY代表正文處理到此結束。
?????? ?*本例中循環向瀏覽器中輸出標記體的正文,直到屬性loop的值小于1。
?????? ?*/
?????? if(loop>1){
?????????? loop--;
?????????? returnEVAL_BODY_AGAIN;
?????? }else {
?????????? returnSKIP_BODY;
?????? }
??? }
}
?
步驟二:創建標記庫描述符文件testbodytag.tld,該文件要存放在 WEB-INF/test-tld 目錄下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
??? 在tld 文件中,映射了標記名和處理程序類;
??? <tallib>元素,代表開始一個標記庫的描述
??? <tligversion>元素,代表標記庫的版本
??? <jspversion>元素,代表標記所支持的JSP 的版本
??? <shortname>為標記庫起別名,相當于注釋,無實際用途
??? <tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
??? <tag>中的子元素
?????? <attribute>用于為標簽聲明屬性,其子元素如下:
?????????? <name>——用于指定屬性名稱
?????????? <required>——用于聲明該屬性是否為必需的,本例中聲明color、loop 兩個屬性都不是必需的。
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>test</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>bodytag</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.TestBodyTag</tagclass>
?????? <bodycontent>tagdependent</bodycontent>
?????? <attribute>
?????????? <name>loop</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
</taglib>
?
?
?
步驟三:在JSP 中使用該標記
<%@ page language="java"?? pageEncoding="UTF-8"%>
<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>測試自定義帶標簽體的標簽</title>
? </head>
? <body>
? ????? 測試帶標記體的自定義標記:<br>
? ????? <test:bodytag loop="4">
? ???????? 這是標記體<br />
? ????? </test:bodytag>
? </body>
</html>
?
運行圖:
?
?
?
?
5.3 一個簡單的帶標記體的標簽(二)
在doStartTag()方法中返回EVAL_BODY_INCLUDE,簡單地將標記體的內容直接輸出到了瀏覽器中,并未對內容進行任何處理,在一些業務中有時需要對標記體正文進行處理,以下示例演示了如何讀取標記體內容并進行處理:
???
步驟一:編寫標記處理類
package tag;
?
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.BodyContent;
import javax.servlet.jsp.tagext.BodyTagSupport;
?
/*
?* doStratTag()中的返回值EVAL_BODY_BUFFERED 代表不直接將標記體內容寫到輸出流中,
?* 而是緩存到成員變量bodyContent 中(該成員從BodyTagSupport 繼承過來),
?* EVAL_BODY_INCLUDE是直接將標記體內容寫到輸出流中
?* */
?
publicclass EqualTag extends BodyTagSupport{
?
??? private String name = "";
??? private String value = "";
??? publicvoid setName(String name) {
?????? this.name = name;
??? }
?
??? publicvoid setValue(String value) {
?????? this.value = value;
??? }
?
??? publicint doStartTag() throws JspException {
?????? System.out.println("do starttag()....");
?????? returnEVAL_BODY_BUFFERED;? //不直接將標記體內容寫到輸出流中,而是緩存到成員變量bodyContent 中
??? }??
?
??? publicvoid setBodyContent(BodyContent b) {
?????? System.out.println("setBodycontent()...."+b.getString()+"++");
?????? this.bodyContent = b;? //bodyContent 賦值前,bodyContent是空的
?????? System.out.println("setBodycontent()...."+bodyContent.getString()+"++");
??? }
?
??? //初始化標記體
??? publicvoid doInitBody() throws JspException {
?????? System.out.println("doInitBody()....."+bodyContent.getString()+"++");
??? }
???
??? publicint doAfterBody() throws JspException {
?????? System.out.println("doAfterBody()...."+bodyContent.getString()+"++");
?????? returnSKIP_BODY;? //停止包含
??? }
?
??? publicint doEndTag() throws JspException {? //處理標簽體內容,將標簽體的內容加租傾斜
?????? System.out.println("doEndTag()..."+bodyContent.getString()+"++");
?????? String username = (String)pageContext.getSession().getAttribute(name);? //獲得存在session的某屬性的值,該屬性值由標簽屬性提供獲取。
?????? String str = bodyContent.getString();
??????
?????? if(username.equals(value)){? //如果該值與標簽屬性相等
?????????? str = "<b><i>"+str+"</i></b>";?? //加粗傾斜,不是的話就原樣輸出
?????? }
??????
?????? try {
?????????? JspWriter out = pageContext.getOut();
?????????? out.print(str);? //將加粗傾斜后的標簽體輸出到頁面上
?????????? this.bodyContent = null;
?????? } catch (Exception e) {
?????????? e.printStackTrace();
?????? }
???
?????? returnEVAL_PAGE;
??? }
}
?
?
?
步驟二:在標記庫描述符文件testbodytag.tld,添加tag標記:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
??? 在tld 文件中,映射了標記名和處理程序類;
??? <tallib>元素,代表開始一個標記庫的描述
??? <tligversion>元素,代表標記庫的版本
??? <jspversion>元素,代表標記所支持的JSP 的版本
??? <shortname>為標記庫起別名,相當于注釋,無實際用途
??? <tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
??? <tag>中的子元素
?????? <attribute>用于為標簽聲明屬性,其子元素如下:
?????????? <name>——用于指定屬性名稱
?????????? <required>——用于聲明該屬性是否為必需的,本例中聲明color、loop 兩個屬性都不是必需的。
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>test</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>bodytag</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.TestBodyTag</tagclass>
?????? <bodycontent>tagdependent</bodycontent>
?????? <attribute>
?????????? <name>loop</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
??? <tag>
?????? <name>equal</name>
?????? <tagclass>tag.EqualTag</tagclass>
?????? <bodycontent>tagdependent</bodycontent>
?????? <attribute>
?????????? <name>name</name>
?????????? <required>true</required>
?????? </attribute>
?????? <attribute>
?????????? <name>value</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
</taglib>
?
?
步驟三:在JSP 中使用該標記
<%@ page language="java"?? pageEncoding="UTF-8"%>
<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>測試自定義帶標簽體的標簽</title>
? </head>
? <body>
? ? <% session.setAttribute("username","tom"); %>
? ? <test:equal name="username" value="tom">session中的username的屬性值如果是tom,則這段文字加粗傾斜</test:equal>
? ? <br />
? ? <test:equal name="username" value="tom1">session中的username的屬性值如果是tom,則這段文字加粗傾斜</test:equal>
? </body>
</html>
?
?
運行界面如下:
?
?
后臺輸出如下:
do starttag()....
setBodycontent()....++
setBodycontent()....++
doInitBody().....++
doAfterBody()....session中的username的屬性值如果是tom,則這段文字加粗傾斜++
doEndTag()...session中的username的屬性值如果是tom,則這段文字加粗傾斜++
do starttag()....
setBodycontent()....++
setBodycontent()....++
doInitBody().....++
doAfterBody()....session中的username的屬性值如果是tom,則這段文字加粗傾斜++
doEndTag()...session中的username的屬性值如果是tom,則這段文字加粗傾斜++
?
?
?
另外,附上各標簽的方法的返回值綜述:
?
?
?
?
六、標簽中的子標記
一個標簽中可以再包含其他的子標記,這種標簽稱為嵌套標記。創建嵌套標簽時,標記處理類與普通標簽相似,但在doStartTag()方法中必須返回EVAL_BODY_INCLUDE,JSP 容器才會處理嵌套的子標記。
?
???????? 步驟一:編寫頂級標記處理類
package tag;
?
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.BodyTagSupport;
?
publicclass NestTag extends BodyTagSupport{
??? private String name = "";
??? private String value = "";
??? publicvoid setName(String name) {
?????? this.name = name;
??? }
?
??? publicvoid setValue(String value) {
?????? this.value = value;
??? }
?
??? publicint doStartTag() throws JspException {
?????? String username = (String)pageContext.getSession().getAttribute(name);
?????? if(username.equals(value)){
?????????? returnEVAL_BODY_INCLUDE; //自動將標簽體包含到輸出流(因為頂級標簽的標簽體是一子標簽,還要進行該子標簽的標簽處理)
?????? }else{
?????????? returnSKIP_BODY; //跳過標簽體,不處理
?????? }
??? }
?
???
}
?
步驟二:在標記庫描述符文件testbodytag.tld,添加tag標記:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE taglib
??????? PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"
??????? "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd">????
<!--
解釋:
??? 在tld 文件中,映射了標記名和處理程序類;
??? <tallib>元素,代表開始一個標記庫的描述
??? <tligversion>元素,代表標記庫的版本
??? <jspversion>元素,代表標記所支持的JSP 的版本
??? <shortname>為標記庫起別名,相當于注釋,無實際用途
??? <tag>元素,代表開始描述一個標記,其下子元素如下:
??? <name>——為標記處理類起的標記名
??? <tagclass>——指定標記處理類的全名(即帶包的名字)
??? <bodycontent>——標記體的類型,該示例中不需要標記體,所有設置為EMPTY,該值的其他取值在后續內容中講解
??? <tag>中的子元素
?????? <attribute>用于為標簽聲明屬性,其子元素如下:
?????????? <name>——用于指定屬性名稱
?????????? <required>——用于聲明該屬性是否為必需的,本例中聲明color、loop 兩個屬性都不是必需的。
?-->
<taglib>
??? <tlibversion>1.0</tlibversion>
??? <jspversion>1.1</jspversion>
??? <shortname>test</shortname><!-- 標簽以<myhr:XXX />形式 -->
??? <tag>
?????? <name>bodytag</name><!-- 該標簽為<myhr:MyHr /> -->
?????? <tagclass>tag.TestBodyTag</tagclass>
?????? <bodycontent>tagdependent</bodycontent>
?????? <attribute>
?????????? <name>loop</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
??? <tag>
?????? <name>equal</name>
?????? <tagclass>tag.EqualTag</tagclass>
?????? <bodycontent>tagdependent</bodycontent>
?????? <attribute>
?????????? <name>name</name>
?????????? <required>true</required>
?????? </attribute>
?????? <attribute>
?????????? <name>value</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
??? <tag>
?????? <name>nest</name>
?????? <tagclass>tag.NestTag</tagclass>
?????? <bodycontent>JSP</bodycontent>? <!-- 該聲明標記體是其他標記,也可以是Jsp標準標記 -->
?????? <attribute>
?????????? <name>name</name>
?????????? <required>true</required>
?????? </attribute>
?????? <attribute>
?????????? <name>value</name>
?????????? <required>true</required>
?????? </attribute>
??? </tag>
</taglib>
?
?
步驟三:在JSP 中使用該標記
<%@ page language="java"?? pageEncoding="UTF-8"%>
<%@ taglib prefix="test" uri="/WEB-INF/test-tld/testbodytag.tld" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
? <head>
??? <title>測試嵌套的標簽</title>
? </head>
? <body>
? ? <% session.setAttribute("username","tom"); %>
? ? ?
? ? <test:nest name="username" value="tom">
? ????? <test:bodytag loop="3">
? ???????? session中的用戶名是tom<br/>
? ????? </test:bodytag>
? ? </test:nest>
? </body>
</html>
?
運行界面如下:
?
?
?
?
?
總結
以上是生活随笔為你收集整理的JSP自定义标签学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 详解struts2中struts.pro
 - 下一篇: struts bean static