09.javaweb簡單標簽編程
一、簡單標簽
1, 簡介:由於傳統標簽使用三個標簽接口來完成不同的功能,顯得過於繁瑣,不利於標簽技術的推廣, SUN公司為降低標簽技術的學習難度,在JSP 2.0中定義了一個更為簡單、便於編寫和調用的SimpleTag接口來實現標簽的功能。
2, 實現SimpleTag接口的標簽稱為簡單標簽。簡單標簽共有五個方法
setJspContext方法:用於把JSP頁面的pageContext對象傳遞給標簽處理器對象
setParent方法:用於把父標簽處理器對象傳遞給當前標簽處理器對象
getParent方法:用於獲得當前標簽的父標簽處理器對象
setJspBody方法:用於把代表標簽體的JspFragment對象傳遞給標簽處理器對象
doTag方法:
用於完成所有的標簽邏輯,包括輸出、叠代、修改標簽體內容等。在doTag方法中可以拋出 javax.servlet.jsp.SkipPageException異常,用於通知WEB容器不再執行JSP頁面中位於結束標記後面的內容,這等效於在傳統標簽的doEndTag方法中返回Tag.SKIP_PAGE常量的情況。
3, web容器執行簡單標簽的步驟
a.WEB容器調用標簽處理器對象的setJspContext方法,將代表JSP頁面的pageContext對象傳遞給標簽處理器對象。
b.WEB容器調用標簽處理器對象的setParent方法,將父標簽處理器對象傳遞給這個標簽處理器對象。註意,只有在標簽存在父標簽的情況下,WEB容器才會調用這個方法。
c.如果調用標簽時設置了屬性,容器將調用每個屬性對應的setter方法把屬性值傳遞給標簽處理器對象。如果標簽的屬性值是EL表達式或腳本表達式,則WEB容器首先計算表達式的值,然後把值傳遞給標簽處理器對象。
d.如果簡單標簽有標簽體,WEB容器將調用setJspBody方法把代表標簽體的JspFragment對象傳遞進來。
e.執行標簽時WEB容器調用標簽處理器的doTag()方法,開發人員在方法體內通過操作JspFragment對象,就可以實現是否執行、叠代、修改標簽體的目的。
4,簡單標簽實例:sun公司針對SimpleTag接口提供了一個默認實現類SimpleTagSupport
4.1編寫標簽處理器類
package com.chen.ying; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class SimpleTagDemo01 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表標簽體的JspFragment用以操作標簽體; JspFragment jfm=this.getJspBody(); jfm.invoke(null);//默認將標簽體內容輸出到瀏覽器 } }
4.2在標簽庫中配置標簽
4.3在jsp中使用
5,控制標簽體內容重復執行
5.1編寫標簽處理類
package com.chen.ying; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.JspFragment; import javax.servlet.jsp.tagext.SimpleTagSupport; public class SimpleTagDemo02 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表標簽體的JspFragment用以操作標簽體; JspFragment jfm=this.getJspBody(); for(int i=1;i<=3;i++){ jfm.invoke(null);//默認將標簽體內容重復輸出到瀏覽器 } } }
6,修改jsp內容並輸出
6.1編寫標簽處理器類,將標簽體內容轉換成大寫
public class SimpleTagDemo03 extends SimpleTagSupport { public void doTag()throws JspException,IOException{ //得到代表標簽體的JspFragment用以操作標簽體; JspFragment jfm=this.getJspBody(); StringWriter sw=new StringWriter();//String流 jfm.invoke(sw);//將標簽體輸出到String流中 String content=sw.getBuffer().toString();//得到流中內容 content=content.toUpperCase();//轉換成大寫 PageContext pageContext=(PageContext)this.getJspContext(); //將修改後的content輸出到瀏覽器中 pageContext.getOut().write(content); } }
7,控制整個jsp頁面是否執行
編寫一個類繼承SimpleTagSupport,然後再重寫doTag方法,在doTag方法拋出SkipPageException異常即可,jsp收到這個異常,將忽略標簽余下jsp頁面的執行。
public void doTag() throws JspException, IOException { //拋出一個SkipPageException異常就可以控制標簽之後的Jsp不執行 throw new SkipPageException(); }
8,JspFragment類
javax.servlet.jsp.tagext.JspFragment類的實例對象代表jsp中一段不包括jsp腳本元素的片段。WEB容器在處理簡單標簽的標簽體時,會把標簽體內容用一個JspFragment對象表示,並調用標簽處理器對象的setJspBody方法把JspFragment對象傳遞給標簽處理器對象。JspFragment有兩個方法
getJspContext(),返回代表調用頁面的JspContext()對象
public abstract void invoke(java.io.Writer out)
用於執行JspFragment對象所代表的JSP代碼片段,參數out用於指定將JspFragment對象的執行結果寫入到哪個輸出流對象中,如果 傳遞給參數out的值為null,則將執行結果寫入到JspContext.getOut()方法返回的輸出流對象中。(簡而言之,可以理解為寫給瀏覽器)
Invoke方法詳解
JspFragment.invoke方法是JspFragment最重要的方法,利用這個方法可以控制是否執行和輸出標簽體的內容、是否叠代執行標簽體的內容或對標簽體的執行結果進行修改後再輸出。例如:
在標簽處理器中如果沒有調用JspFragment.invoke方法,其結果就相當於忽略標簽體內容;
在標簽處理器中重復調用JspFragment.invoke方法,則標簽體內容將會被重復執行;
若想在標簽處理器中修改標簽體內容,只需在調用invoke方法時指定一個可取出結果數據的輸出流對象(例如StringWriter),讓標簽體的執行結果輸出到該輸出流對象中,然後從該輸出流對象中取出數據進行修改後再輸出到目標設備,即可達到修改標簽體的目的。
9,帶屬性的簡單標簽開發
簡單標簽的屬性設置與傳統標簽的屬性設置類似。需要註意的是如果標簽的屬性值是8種基本數據類型,那麽在JSP頁面在傳遞字符串時,JSP引擎會自動轉換成相應的類型,但如果標簽的屬性值是復合數據類型,那麽JSP引擎是無法自動轉換的
下面研究如何為復合數據類型的屬性值賦值:
上面對一個日期類型的屬性賦值,可以用表達式語言或表達式給屬性賦值。
10,DynamicAttribute接口:使用此接口,可以接收動態屬性
此接口只有一個接收動態屬性的方法,當標簽中含有未在標簽庫配置的動態屬性時便會循環調用此方法
public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {
}
10.1編寫一個標簽處理類,可以接收動態填寫的屬性,並將屬性相加值輸出到瀏覽器
public class SimpleTagDemo04 extends SimpleTagSupport implements DynamicAttributes{ private Map<String,Float> map=new HashMap<String,Float>(); public void doTag()throws JspException,IOException{ Float sum=0.0f; for(Map.Entry<String, Float> m:map.entrySet()){ sum+=m.getValue();//將map中的屬性值累加 } super.getJspContext().getOut().write(sum+"");//輸出到瀏覽器 } public void setDynamicAttribute(String uri, String localName, Object value) throws JspException { //循環執行此函數,接收動態屬性 map.put(localName,Float.parseFloat(value.toString())); } }
10.2在標簽庫中配置此標簽
10.3在jsp使用此標簽
結果
二、 標簽開發細節
1,開發簡單標簽類時,不要直接去實現SimpleTag接口,而是應該繼承SimpleTagSupport類,SimpleTagSupport類是 SimpleTag接口的一個默認實現類,通過繼承SimpleTagSupport類,就可以直接使用SimpleTagSupport類已經實現的那 些方法,如果SimpleTagSupport類的方法實現不滿足業務要求,那麽就可以根據具體的業務情況將相應的方法進行重寫。
2,tld文件中有四種標簽體(body-content)類型 :empty、JSP、scriptless、tagdependent
在簡單標簽(SampleTag)中標簽體body-content的值只允許是empty、scriptless、tagdependent,不允許設置成JSP,如果設置成JSP就會出現異常: jsp標簽技術出現的目的就是為了移除在jsp頁面上編寫的java代碼的,如果在jsp標簽中允許出現java代碼,那麽就違背了jsp標簽技術設計時的初衷了。所以在簡單標簽的標簽體中是不允許出現java代碼的。
如果標簽體body-content的值設置成tagdepentend,那麽就表示標簽體裏面的內容是給標簽處理器類使用的,
例如:開發一個查詢用戶的sql標簽,此時標簽體中的SQL語句就是給SQL標簽的標簽處理器來使用的
<gacl:sql>SELECT * FROM USER</gacl:sql>
3,如果有兩個標簽庫的uri相同,則不能簡單地通過uri引用標簽庫,可通過uri=”標簽庫tld目錄”區分
<%@taglib uri="/WEB-INF/gacl.tld" prefix="gacl"%>、
<%@taglib uri="/WEB-INF/simpletag.tld" prefix="gacl"%>
三、小結
1、編寫一個類繼承SimpleTagSupport類,然後根據業務需要重寫SimpleTagSupport類中已經實現了的方法,一般情況下只需要重寫doTag()方法即可。
2、在WEB-INF目錄下創建一個tld文件,在tld文件中添加對該標簽的描述。tld文件不一定放在WEB-INF目錄下,也可以放在別的目錄,習慣是放在WEB-INF目錄下。
09.javaweb簡單標簽編程