1、概述html
JSP 2.0 中提供了兩種新的開發自定義標記的方法:java
一、簡單標籤機制SimpleTagweb
JSP 2.0 中加入了新的建立自定義標記的API:javax.servlet.jsp.tagext.SimpleTag,該API 定義了用來實現簡單標記的接口。和JSP 1.2 中的已有接口不一樣的是,SimpleTag 接口不使用doStartTag()和doEndTag()方法,而提供了一個簡單的doTag()方法。這個方法在調用該標記時只被使用一次。一個自定義標記中實現的全部邏輯都在這個方法中實現。相對JSP1.2 中自定義標記機制,SimpleTag 的方法和處理週期要簡單得多。後端
二、 標籤文件瀏覽器
標籤文件容許JSP 網頁做者使用JSP 語法建立可複用的標籤庫。標籤文件的擴展名必須是.tag。緩存
1.1 使用簡單標籤機制網絡
與JSP1.2 類似,開發自定義標籤要遵循「開發標記類---配置TLD 文件----在JSP 中使用」的過程,session
示例以下:app
步驟一:編寫標記處理類AddTag.javajsp
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 標籤
3、自結束標籤(不帶標籤體,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、標籤中的屬性
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、標籤中的標記體
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 的處理流程以下:
一、當容器建立一個新的標籤實例後,經過setPageContext 來設置標籤的頁面上下文。
二、使用setParent 方法設置這個標籤的上一級標籤,若是沒有上一級嵌套,設置爲null。
三、設置標籤的屬性,若是沒有定義屬性,就不調用此類方法。
四、調用doStartTag 方法,這個方法能夠返回如下三者之一:EVAL_BODY_INCLUDE、
EVAL_BODY_BUFFERED、SKIP_BODY,當返回EVAL_BODY_INCLUDE 時,就將標記
體直接寫到輸出流中,若是返回SKIP_BODY,就再也不計算標籤的正文,若是返回EVAL_BODY_BUFFERED,就將標記體的正文包含到bodyContent 成員中。
五、調用setBodyContent 設置當前的BodyContent.
六、調用doInitBody,能夠在該方法中對BodyContent 進行一些初始化操做.每次計算完Body 後調用doAfterBody,若是返回EVAL_BODY_AGAIN,表示繼續處理一次標記體,直到返回SKIP_BODY 才繼續往下執行.
七、調用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,則這段文字加粗傾斜++
另外,附上各標籤的方法的返回值綜述:
6、標籤中的子標記
一個標籤中能夠再包含其餘的子標記,這種標籤稱爲嵌套標記。建立嵌套標籤時,標記處理類與普通標籤類似,但在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>
運行界面以下: