Tag接口
任何1個標簽都對應著1個java類,該類必須實現(xiàn)Tag接口,JSP遇到1個標簽后后,將通過1個tld文件查找該標簽的實現(xiàn)類,并運行該類的相干方法
import javax.servlet.jsp.JspException; import javax.servlet.jsp.PageContext; import javax.servlet.jsp.tagext.Tag; public class TagTest implements Tag { private Tag parent; private PageContext pageContext; @Override public int doEndTag() throws JspException{ //標簽結(jié)束時履行 JspWriter out =pageContext.getOut(); try{ out.println("……"); }catch(IOExceptione){ throw new JspException(e); } return EVAL_PAGE; } @Override public int doStartTag() throwsJspException { //標簽開始時履行 return SKIP_BODY; } @Override public Tag getParent() { // TODO Auto-generated method stub return null; } @Override public void release() { // TODO Auto-generated method stub } @Override public void setPageContext(PageContextarg0) { // TODO Auto-generated method stub } @Override public void setParent(Tag arg0) { // TODO Auto-generated method stub } }
doStartTag方法可以返回兩種參數(shù),如果為SKIP_BODY,表示標簽體內(nèi)的內(nèi)容不被輸出,如果為EVAL_BODY_INCLUDE,則履行標簽體內(nèi)的代碼
doEndTag也能夠返回兩種參數(shù),如果為SKIP_PAGE,表示不履行標簽后面的內(nèi)容。如果為EVAL_PAGE,則履行標簽后面的內(nèi)容
此類中有兩個屬性,parent和pageContext,parent為該標簽的父標簽(或是上1層的標簽),pageContext為運行該標簽的JSP頁面,這兩個參數(shù)都是JSP在運行時通過setter方法注射進去的
Tag實現(xiàn)類有了,還需要tld文件(Tag Library Descriptor)
<?xml version="1.0" ecoding="UTF⑻"> <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 web-jsptaglibrary_2_0.xsd version="2.0"> <tlibversion>1.0</tlibversion> <jspversion> 1.1</jspversion> <shortname>tagname</shortname> <uri>http://www.clf.com/tags</uri> <info>A simple tag test</info> <tag> <name>tagname</name> <tagclass>com.chen.tags.TagTest</tagclass> <bodycontent>JSP</ bodycontent> <info>tag information</info> </tag> </taglib>
shortname也就是推薦使用的prefix,uri就是援用這個標簽庫時使用的uri
bodycontent為標簽體的限制,有3種取值
empty:不允許有標簽體的存在,如果有會拋出異常
JSP:允許有標簽體存在,可以為JSP代碼
tagdependent:允許有標簽體存在,但是標簽里的JSP代碼不會被履行
如果tld文件位于/WEB-INF/下面,Tomcat會自動加載;如果位于其他位置,可以在web.xm中配置
<jsp-config> <taglib> <taglib-uri> http://www.clf.com/tags</taglib-uri> <taglib-location>/WEB-INF/taglib.tld</taglib-location> </taglib> </jsp-config>
TagSupport
多數(shù)情況下不需要直接實現(xiàn)Tag接口,使用TagSupport類就能夠了,此類是java提供的1個模板類,1般來講,只需要實現(xiàn)doStartTag方法和doEndTag方法就能夠了
import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.TagSupport; public class Tagtest extends TagSupport { private int num1; private int num2; @Override public int doEndTag() throws JspException{ try { this.pageContext.getOut().println("兩數(shù)相加等于:"+(num1+num2)); } catch (Exception e) { } return EVAL_PAGE; } @Override public int doStartTag() throwsJspException { return super.doStartTag(); } public int getNum1() { return num1; } public void setNum1(int num1) { this.num1 = num1; } public int getNum2() { return num2; } public void setNum2(int num2) { this.num2 = num2; } }
配置文件
<tag> <name>add</name> <tagclass>com.chen.tags.TagTest</tagclass> <bodycontent>JSP</bodycontent> <info>tag information</info> <attribute> <name>num1</name> <required>true</required > <rtexprvalue>true</rtexprvalue > </attribute> <attribute> <name>num2</name> <required>true</required > <rtexprvalue>true</rtexprvalue > </attribute> </tag>
name代表屬性的名字,required代表是不是是必須的,rtexprvalue代表此屬性是不是允許使用EL表達式
以上這個標簽這樣使用:
<taglib:add num1=”2” num2=”3”/>
則頁面會輸出2和3 的相加上和
BodyTagSupport
BodyTagSupport是Tag接口的子類,專門處理帶標簽體的標簽
public class ToLowerCaseTag extends BodyTagSupport{ public int doEndTag throws JspException{ //獲得標簽體內(nèi)的代碼 String contend = this.getBodyContent().getString(); try{ this.pageContent.getOut().println(content.toLowerCase()); }catch(Exception e){ } return EVAL_PAGE; } }
只要在setBodyContent()方法以后被調(diào)用的方法中,都可使用getBodyContent()方法獲得標簽體的內(nèi)容,1般為doAfterBody()或doEndTag()
BodyTagSupport的履行流程以下:
1.當容器創(chuàng)建1個新的標簽實例后,通過setPageContext來設置標簽的頁面上下文.
2.使用setParent方法設置這個標簽的上1級標簽,如果沒有上1級嵌套,設置為null.
3.設置標簽的屬性,這個屬性在標簽庫描寫文件中定義,如果沒有定義屬性,就不調(diào)用此類方法.
4.調(diào)用doStartTag方法,這個方法可以返回EVAL_BODY_INCLUDE和SKIP_BODY,當返回EVAL_BODY_INCLUDE時,就計算標簽的body,如果返回SKIP_BODY,就不再計算標簽的body,如果為EVAL_BODY_BUFFERED,則不會輸出,而是將標簽體內(nèi)容通過setBodyContent()方法注射到標簽類中,然后就能夠使用getBodyContent()獲得標簽體的內(nèi)容
5.調(diào)用setBodyContent設置當前的BodyContent.
6.調(diào)用doInitBody,如果計算BodyContent時需要進行1些初始化,就在這個方法中進行.
7.每次計算完Body后調(diào)用doAfterBody,如果返回EVAL_BODY_AGAIN,表示繼續(xù)計算1次Body,直到返回SKIP_BODY才繼續(xù)往下履行.
8.調(diào)用doEndTag方法,這個方法可以返回EVAL_PAGE或SKIP_PAGE,當返回EVAL_PAGE時,容器將在標簽結(jié)束時繼續(xù)計算JSP頁面其他的部份;如果返回SKIP_PAGE,容器將在標簽結(jié)束時停止計算JSP頁面其他的部份.
9.調(diào)用release()方法釋放標簽程序占用的任何資源。
public class LoopTag extends BodyTagSupport{ private int times; public int doStartTag() throwsJspException{ times = 5; return super.doStartTag(); } public int doAfterBody() throwsJspException{ if(times-- >0){ 只要times大于零繼續(xù)循環(huán),同時times自減 try{ this.getPreviousOut().println(this.getBodyContent().getString()); }catch(Exception e){ } return EVAL_BODY_AGAIN; //繼續(xù)履行 }else{ return SKIP_BODY; } } }
以上定義了1個循環(huán)標簽
<taglib:loop>loop.</taglib:loop>
會得到以下輸出:
loop.
loop. loop.
loop. loop. loop.
loop. loop. loop.loop.
loop. loop. loop.loop. loop.
實際上,doAfterBody方法內(nèi)的輸出是寫到bodyContent緩存中的
BodyTagSupport中,里面的標簽可以通過getparent()方法取得上層的標簽