天天看點

自定義JSP标簽詳解------簡單标簽

簡單标簽庫開發常用功能 ,實作SimpleTag接口标簽類 (SimpleTag JSP2.0之後為了簡化标簽開發提供的 )

** ***  編寫簡單标簽類 隻需要繼承 SimpleTagSupport 類

實作SimpleTag接口的标簽通常稱為簡單标簽。簡單标簽共定義了5個方法:

  • setJspContext方法
  • setParent和getParent方法
  • setJspBody方法
  • doTag方法
  • setJspContext方法
用于把JSP頁面的pageContext對象傳遞給标簽處理器對象 
  • setParent方法
用于把父标簽處理器對象傳遞給目前标簽處理器對象 
  • getParent方法
用于獲得目前标簽的父标簽處理器對象 
  • setJspBody方法
用于把代表标簽體的JspFragment對象傳遞給标簽處理器對象 
  • doTag方法
用于完成所有的标簽邏輯,包括輸出、疊代、修改标簽體内容等。在doTag方法中可以抛出javax.servlet.jsp.SkipPageException異常,用于通知WEB容器不再執行JSP頁面中位于結束标記後面的内容,這等效于在傳統标簽的doEndTag方法中傳回Tag.SKIP_PAGE常量的情況。

Tip:SimpleTag接口方法的執行順序

當web容器開始執行标簽時,會調用如下方法完成标簽的初始化

  1. WEB容器調用标簽處理器對象的setJspContext方法,将代表JSP頁面的pageContext對象傳遞給标簽處理器對象。
  2. WEB容器調用标簽處理器對象的setParent方法,将父标簽處理器對象傳遞給這個标簽處理器對象。注意,隻有在标簽存在父标簽的情況下,WEB容器才會調用這個方法。
  3. 如果調用标簽時設定了屬性,容器将調用每個屬性對應的setter方法把屬性值傳遞給标簽處理器對象。如果标簽的屬性值是EL表達式或腳本表達式,則WEB容器首先計算表達式的值,然後把值傳遞給标簽處理器對象。
  4. 如果簡單标簽有标簽體,容器将調用setJspBody方法把代表标簽體的JspFragment對象傳遞進來。

執行标簽時 :

  1. 容器調用标簽處理器的doTag()方法,開發人員在方法體内通過操作JspFragment對象,就可以實作是否執行、疊代、修改标簽體的目的。

Tip:JspFragment類

javax.servlet.jsp.tagext.JspFragment類是在JSP2.0中定義的,它的執行個體對象代表JSP頁面中的一段符合JSP文法規範的JSP片段,這段JSP片段中不能包含JSP腳本元素。
對于簡單标簽,其<tag>元素的<body-content>子元素的可選值包括empty、scriptless和tagdependent,預設值為scriptless。對于傳統的自定義标簽,<body-content>子元素的可選值包括empty、Jsp、scriptless和tagdependent。由于簡單标簽的主體不能包含Java程式片段等腳本元素,是以<body-content>子元素的值不能為JSP。

WEB容器在處理簡單标簽的标簽體時,會把标簽體内容用一個JspFragment對象表示,并調用标簽處理器對象的setJspBody方法把JspFragment對象傳遞給标簽處理器對象。JspFragment類中隻定義了兩個方法,如下所示:

getJspContext方法

•用于傳回代表調用頁面的JspContext對象. ----pageContext

public abstract void invoke(java.io.Writer out)  -- 輸出标簽體内容

•用于執行JspFragment對象所代表的JSP代碼片段

•參數out用于指定将JspFragment對象的執行結果寫入到哪個輸出流對象中,如果傳遞給參數out的值為null,則将執行結果寫入到JspContext.getOut()方法傳回的輸出流對象中。(簡而言之,可以了解為寫給浏覽器)

Tip:invoke方法詳解  

JspFragment.invoke方法是JspFragment最重要的方法,利用這個方法可以控制是否執行和輸出标簽體的内容、是否疊代執行标簽體的内容或對标簽體的執行結果進行修改後再輸出。

例如:

  • 在标簽處理器中如果沒有調用JspFragment.invoke方法,其結果就相當于忽略标簽體内容;
  • 在标簽處理器中重複調用JspFragment.invoke方法,則标簽體内容将會被重複執行;
  • 若想在标簽處理器中修改标簽體内容,隻需在調用invoke方法時指定一個可取出結果資料的輸出流對象(例如StringWriter),讓标簽體的執行結果輸出到該輸出流對象中,然後從該輸出流對象中取出資料進行修改後再輸出到目标裝置,即可達到修改标簽體的目的。

 例一:控制标簽體内容是否執行

标簽處理類Class:

<span style="font-size:18px;">public class Demo1Tag extends SimpleTagSupport{

	@Override
	public void doTag() throws JspException, IOException {
		//什麼都不寫就是标簽體不執行,因為在執行流程中setJspBody講标簽體寫到的緩存中,</span>
           
<span style="font-size:18px;">                //如果不調用invoke方法标簽體就會在緩存中不會顯示在頁面上。
		//如果想執行标簽體,就調用invoke方法
                //getJspBody().invoke(getJspContext().getOut());
		//可以直接簡化傳遞的輸出流的參數,如果為NULL,則采用預設的輸出流,預設的輸出流就是out對象
		getJspBody().invoke(null);
	}
}</span>
           

描述标簽TLD:

<span style="font-size:18px;"><tag>
 	<!-- 标簽名稱 -->
 	<name>demo1Tag</name>
 	<!-- 标簽類 -->
 	<tag-class>com.rxtmedia.foot.text.Demo1Tag</tag-class> 
 	<body-content>scriptless</body-content>
 </tag></span>
           

例二:控制标簽後的jsp頁面是否執行

标簽處理類class:

public class Demo2Tag extends SimpleTagSupport {
	@Override
	public void doTag() throws JspException, IOException {
		// 什麼都不寫剩餘頁面會繼續執行
		// 如果不想執行頁面後面内容
		throw new SkipPageException();
	}
}
           

标簽描述TLD:

<span style="font-size:18px;"> <tag>
 	<!-- 标簽名稱 -->
 	<name>demo2Tag</name>
 	<!-- 标簽類 -->
 	<tag-class>com.rxtmedia.foot.text.Demo2Tag</tag-class> 
 	<body-content>scriptless</body-content>
 </tag></span>
           

例三:控制jsp頁面内容重複執行

public class Demo3Tag extends SimpleTagSupport{

	@Override
	public void doTag() throws JspException, IOException {
		for(int i = 0 ; i < 10 ; i++){
			// 執行标簽體
			getJspBody().invoke(null);
		}
	}
}
           

描述标簽檔案TLD:

<span style="font-size:18px;"> <tag>
 	<!-- 标簽名稱 -->
 	<name>demo3Tag</name>
 	<!-- 标簽類 -->
 	<tag-class>com.rxtmedia.foot.text.Demo3Tag</tag-class> 
 	<body-content>scriptless</body-content>
 </tag></span>
           

例四:修改jsp頁面内容輸出

标簽處理類class:

public class Demo4Tag extends SimpleTagSupport{
	@Override
	public void doTag() throws JspException, IOException {
		// 獲得緩存中标簽體内容
		StringWriter stringWriter = new StringWriter();
		// 将标簽體内容寫入stringwriter
		getJspBody().invoke(stringWriter);
		String str = stringWriter.toString();
		str = str.toUpperCase();
		
		// 輸出到頁面 需要out對象
		JspWriter out = this.getJspContext().getOut();
		out.print(str);
	}

}
           

描述标簽檔案TLD:

<span style="font-size:18px;"><tag>
 	<!-- 标簽名稱 -->
 	<name>demo4Tag</name>
 	<!-- 标簽類 -->
 	<tag-class>com.rxtmedia.foot.text.Demo4Tag</tag-class> 
 	<body-content>scriptless</body-content>
 </tag></span>
           

例五:建立和使用帶動态屬性的簡單标簽

标簽處理類class:

public class Demo5Tag extends SimpleTagSupport implements DynamicAttributes{

	private ArrayList<String> al = new ArrayList<String>();
	
	@Override
	public void setDynamicAttribute(String uri, String localName, Object value)
			throws JspException {
		al.add((String) value);
	}

	@Override
	public void doTag() throws JspException, IOException {
		int max = 0 ;
		for(int i =0 ; i < al.size() ; i++){
			int num = Integer.parseInt(al.get(i));
			max = num > max ? num : max ;
		}
		System.out.println(max);
		// 将最大的值寫到頁面
//		context.setAttribute("max",new Integer(max));
	}
} 
           

标簽描述檔案TLD:

<span style="color:#336666;"><tag>
 	<!-- 标簽名稱 -->
 	<name>demo5Tag</name>
 	<!-- 标簽類 -->
 	<tag-class>com.rxtmedia.foot.text.Demo5Tag</tag-class> 
 	<body-content>scriptless</body-content>
 	</span><span style="color:#cc0000;"><dynamic-attributes>true</dynamic-attributes></span><span style="color:#336666;">
 </tag></span>
           

繼續閱讀