Servlet、Filter和ListenerJava Servlet是與平臺(tái)無關(guān)的服務(wù)器端組件,運(yùn)行于Servlet容器中(如Tomcat),Servlet容器負(fù)責(zé)Servlet和客戶端的通信以及調(diào)用Servlet的方法,Servlet和客戶端的通信采用“請(qǐng)求/響應(yīng)”的模式。Servlet可完成以下功能:
1、創(chuàng)建并返回基于客戶請(qǐng)求的動(dòng)態(tài)HTML頁面。
2、創(chuàng)建可以嵌入到現(xiàn)有HTML頁面中的HTML片段。
3、與其它服務(wù)器資源(如數(shù)據(jù)庫或基于Java的應(yīng)用程序)進(jìn)行通信。
4、接收多個(gè)客戶端的輸入,并將結(jié)果廣播到多個(gè)客戶端上,例如,Servlet可以實(shí)現(xiàn)支持多個(gè)參與者的游戲服務(wù)器。
5、根據(jù)客戶請(qǐng)求采用特定的MIME(Multipurpose Internet Mail Extensions)類型對(duì)數(shù)據(jù)過濾,例如進(jìn)行圖像格式轉(zhuǎn)換。
Servlet的框架由兩個(gè)包組成:javax.servlet和javax.servlet.http。在javax.servlet包中定義了所有Servlet類必須實(shí)現(xiàn)或擴(kuò)展的通用接口和類。在javax.servlet.http包中定義了采用HTTP協(xié)議通信的HttpServlet類。
Servlet框架的核心是javax.servlet.Servlet接口,所有的Servlet類都必須實(shí)現(xiàn)這個(gè)接口。Servlet接口定義的方法如下:
1、init方法,負(fù)責(zé)初始化Servlet對(duì)象。
2、service方法,負(fù)責(zé)響應(yīng)客戶端的請(qǐng)求。
3、destroy方法,當(dāng)Servlet對(duì)象退出生命周期時(shí),負(fù)責(zé)釋放占用的資源。
4、getServletConfig方法,獲得ServletConfig接口,可以得到Servlet的相關(guān)參數(shù)。
5、getServletInfo方法,獲得Servlet的相關(guān)信息。
在javax.servlet包中,GenericServlet類實(shí)現(xiàn)了Servlet接口,在javax.servlet.http包中,HttpServlet類擴(kuò)展了GenericServlet
類。當(dāng)用戶開發(fā)自己的Servlet時(shí),必須擴(kuò)展以上兩個(gè)類中的一個(gè),如果擴(kuò)展自GenericServlet類,則必須自己實(shí)現(xiàn)service方法,
如果擴(kuò)展自HttpServlet類,則不需要自己實(shí)現(xiàn)service方法,因?yàn)镠ttpServlet類已經(jīng)實(shí)現(xiàn)了該方法。
GenericServlet類的service方法是一個(gè)抽象方法,只有兩個(gè)參數(shù):ServletRequest和ServletResponse。HttpServlet類的service方法也只有兩個(gè)參數(shù):HttpServletRequest和HttpServletResponse。HttpSevletRequest接口和HttpResponse接口分別擴(kuò)展自ServletRequest和ServletResponse接口,都提供了與特定協(xié)議HTTP相關(guān)的數(shù)據(jù)。
ServletRequest接口的方法如下:
getAttribute 獲得屬性值
getContentType 獲得客戶請(qǐng)求數(shù)據(jù)的MIME類型。
getInputStream 獲得可以讀取客戶請(qǐng)求數(shù)據(jù)的輸入流。
getParameter 獲得參數(shù)值
getRemoteAddr 獲得客戶端的IP
getRemoteHost 獲得客戶端的主機(jī)名
getRemotePort 獲得客戶端的端口
setAttribute 設(shè)置屬性值。
ServletResponse接口的方法如下:
getOutputStream 獲得可以向客戶羰發(fā)送二進(jìn)制數(shù)據(jù)的輸出流對(duì)象ServletOutputStream
getWriter 獲得可以向客戶端發(fā)送字符數(shù)據(jù)的PrintWriter對(duì)象
getCharacterEncoding 獲得Servlet發(fā)送的響應(yīng)數(shù)據(jù)的字符編碼
getContentType 返回Servlet發(fā)送的響應(yīng)數(shù)據(jù)的MIME類型
setCharacterEncoding 設(shè)置Servlet發(fā)送的響應(yīng)數(shù)據(jù)的字符編碼。
setContentType 設(shè)置Servlet發(fā)送的響應(yīng)數(shù)據(jù)的MIME類型。
Servlet的init方法有如下兩種形式:
public void init(ServletConfig config) throws ServletException
public void init() throws ServletException
在Servlet的初始化分階段,Servlet容器會(huì)為Servlet創(chuàng)建一個(gè)ServletConfig對(duì)象,用來存放Servlet的初始化配置信息,如Servlet的初始參數(shù)。如果Servlet覆蓋了帶參數(shù)的init方法,則必須在函數(shù)體內(nèi)先調(diào)用super.init(config); 以確保config參數(shù)引用了ServletConfig對(duì)象。如果Servlet覆蓋了沒有帶參數(shù)的init方法,則不需要調(diào)用super.init(); 方法,可以通過調(diào)用getServletConfig()方法來獲得ServletConfig對(duì)象。
Servlet容器會(huì)為Web應(yīng)用創(chuàng)建一個(gè)唯一的全局的ServletContext對(duì)象,可以把它看成是一個(gè)Web應(yīng)用的服務(wù)器端組件的共享內(nèi)存。它有如下方法:
etAttribute(String name,Object obj) 將一個(gè)對(duì)象與一個(gè)屬性名綁定,并存放到
ServletContext中
getAttribute(String name) 獲得指定名稱的屬性值。
removeAttribute(String name) 刪除指定名稱的屬性。
getAttributeNames() 返回所有屬性名的一個(gè)Enumeration對(duì)象。
getInitParameter(String name) 獲得指定名稱的參數(shù)值,該參數(shù)是Web應(yīng)用的初始化參數(shù).
getInitParameterNames() 返回Web應(yīng)用的所有初始化參數(shù)的名稱的Enumeration對(duì)象.
getMimeType(String file) 返回文件的MIME類型.
getRealPath(String path) 返回網(wǎng)絡(luò)路徑path對(duì)應(yīng)的文件系統(tǒng)路徑.
getServerInfo() 返回Servlet容器的名稱和版本
注意: 一般在HptpServlet的子類中,將doPost方法的實(shí)現(xiàn)合并到doGet方法中,也就是在doPost方法中簡(jiǎn)單地調(diào)用doGet方法.因?yàn)橐话闱闆r下對(duì)于Get和Post請(qǐng)求,它們都是一樣的處理.
編譯了Servlet后,將它打包成jar放到WEB-INF/lib目錄下,或?qū)ervlet的class文件放到WEB-INF/classes/目錄下,再在WEB-INF/web.xml配置文件中配置這些servlet,就可以在Web應(yīng)用中訪問servlet了,配置如下:
<servlet>
<servlet-name>my_servlet</servlet-name>
<servlet-class>com.mycompany.ServletClass1</servlet-class>
< init-param> <!--定義servlet的初始化參數(shù), 可以有多個(gè)init-param參數(shù)-->
< param-name>iParam< /param-name>
< param-value>2< /param-value>
< /init-param>
< load-on-startup>2< /load-on-startup> <!--定義servlet的加載順序-->
</servlet>
<servlet-mapping>
<servlet-name>my_servlet</servlet-name>
<url-pattern>*.hello</url-pattern>
</servlet-mapping>
Session相關(guān)
在Servlet API中定義了javax.servlet.http.HttpSession接口,Servlet容器必須實(shí)現(xiàn)這一個(gè)接口。當(dāng)一個(gè)Session開始時(shí),Servlet容器將創(chuàng)建一個(gè)HttpSession對(duì)象,在HttpSession對(duì)象中可以存放客戶狀態(tài)的信息。Servlet容器為HttpSession對(duì)象分配一個(gè)唯一的標(biāo)識(shí)符,叫做Session ID,Servlet容器把Session ID作為Cookie保存在客戶的瀏覽器中,每次客戶發(fā)出HTTP請(qǐng)求時(shí),Servlet容器可以從HttpRequest對(duì)象中讀取Session ID,然后根據(jù)Session ID找到相應(yīng)的HttpSession對(duì)象,從而獲得客戶的狀態(tài)信息。HttpSession接口有如下方法:
getId() 返回Session ID
invalidate() 使當(dāng)前的Session失效,Servlet容器會(huì)釋放HttpSession對(duì)象占用的資源。
setAttribute(String name,Object obj) 將一對(duì)name/value屬性保存到HttpSession對(duì)象中。
getAttribute(String name) 返回名字為name的屬性值。
getAttributeNames() 返回HttpSession對(duì)象中所有的屬性名。
isNew() 判斷這個(gè)Session是不是新創(chuàng)建的。
setMaxInactiveInterval() 設(shè)定Session可以處于不活動(dòng)狀態(tài)的最大時(shí)間(以秒為單位), 超過這個(gè)時(shí)間,Session就會(huì)自動(dòng)失效,如果設(shè)置為負(fù)數(shù),則不 限制Session的不活動(dòng)狀態(tài)時(shí)間。
getMaxInactiveInterval() 返回Session可以處于不活動(dòng)狀態(tài)的最大時(shí)間。
當(dāng)客戶第一次訪問Web應(yīng)用中支持Session的某個(gè)頁面時(shí),就會(huì)開始一個(gè)新的Session,接下來,當(dāng)客戶瀏覽這個(gè)Web應(yīng)用的其它頁面時(shí),始終處于同一個(gè)Session中。以下情況之一,Session就會(huì)失效:
1、客戶端關(guān)閉瀏覽器。
2、Session過期,即客戶在指定的最大時(shí)間內(nèi)沒有與Web服務(wù)器交互。
3、服務(wù)器端調(diào)用了HttpSession的invalidate()方法。
如果客戶端瀏覽器不支持或禁用Cookie,則Servlet容器無法從客戶端瀏覽器中取得作為Cookie的Session ID,也就無法跟蹤客戶的狀態(tài),因此客戶端的每次請(qǐng)求支持Session的JSP頁面時(shí),Servlet容器都會(huì)創(chuàng)建一個(gè)新的HttpSession對(duì)象。對(duì)于這種情況,需要通過HttpServletResponse的encodeURL()方法重寫客戶請(qǐng)求的URL,它把Session ID添加到URL信息中,也就是說,對(duì)于支持Session的JSP頁面中的所有連接URL,都要調(diào)用encodeURL()方法來重寫這些URL,例如:
對(duì)于<a href=”login.jsp”/>應(yīng)該改為<a href=”<%=response.encodeURL(“l(fā)ogin.jsp”)%>”/>
這樣,即使客戶禁用Cookie,也能使用Session來跟蹤客戶的狀態(tài)信息了。
Session的持久化:
Session的持久化就是將HttpSession對(duì)象從內(nèi)存中轉(zhuǎn)移到文件系統(tǒng)或數(shù)據(jù)庫中,這樣做的好處是:減少系統(tǒng)資源的占用,如果Servlet容器突然關(guān)閉或重啟,或Web應(yīng)用重啟,這些持久化了的HttpSession對(duì)象可以再重新加載進(jìn)來,對(duì)于客戶端,還是使用同一個(gè)Session。
Session的持久化是由Session Manager來管理的,Tomcat提供了兩個(gè)實(shí)現(xiàn)類:
l org.apache.catalina.session.StandarManager
l org.apache.catalina.session.PersistentManager
1、StandarManager是默認(rèn)的Session Manager。它的實(shí)現(xiàn)機(jī)制是:當(dāng)Tomcat服務(wù)器關(guān)閉或重啟,或Web應(yīng)用被重新加載時(shí),會(huì)將內(nèi)存中所有的HttpSession對(duì)象保存到文件系統(tǒng)中,默認(rèn)的文件路徑是:%CATALINA_HOME%\work\Catalina\<applicaton-name>\SESSIONS.ser
重啟Tomcat后,Tomcat服務(wù)器把SESSIONS.ser中的持久化HttpSession對(duì)象加載到內(nèi)存中。
2、PersistentManager能夠把HttpSession對(duì)象保存到Session Store中,它提供了比較StandarManager更靈活的管理功能,具有容錯(cuò)能力,控制內(nèi)存中HttpSession對(duì)象的數(shù)目等。
Tomcat實(shí)現(xiàn)Session Store的接口為org.apache.catalina.session.Store,目前提供了兩個(gè)實(shí)現(xiàn)這一接口的類:org.apache.catalina.session.FileStore和org.apache.catalina.session.JDBCStore。FileStore會(huì)將HttpSession對(duì)象保存到文件系統(tǒng)中;而JDBCStore則將HttpSession對(duì)象保存到數(shù)據(jù)庫表中。
下面給出這兩個(gè)類的配置:
配置FileStore:
在server.xml中,在Web應(yīng)用的<Context>元素加入<Manager>元素,例如:
<Context path=”/helloapp” docBase=”helloapp” debug=”0” reloadable=”true”>
<Manager className=”org.apache.catalina.session.PersistentManager”>
debug=0;
saveOnRestart=”true”
maxActiveSessions=”-1”
minIdleSwap=”-1”
maxIdleSwap=”-1”
maxIdleBackup=”-1”
<Store className=”org.apache.catalina.session.FileStore” directory=”mydir”/>
</Manager>
</Context>
屬性
作用
className
指定Session Manager的實(shí)現(xiàn)類名,或Session Store的實(shí)現(xiàn)類名
debug
設(shè)定Session Manager采用的跟蹤級(jí)別,取值0到99,越小越跟蹤信息越少,發(fā)布產(chǎn)品時(shí),應(yīng)該設(shè)置為0,以提高性能。
saveOnRestart
如果為true,則當(dāng)Tomcat關(guān)閉時(shí),所有的有效HttpSession對(duì)象都保存到Session Store中;當(dāng)Tomcat重啟時(shí),加載這些HttpSession對(duì)象。
maxActiveSessions
設(shè)置處于活動(dòng)狀態(tài)的Session的最大數(shù)目,如果超過這一數(shù)目,Tomcat把一些超過的Sessin對(duì)象保存到Session Store中。-1表示不限制。
minIdleSwap
Session處于不活動(dòng)狀態(tài)的最小時(shí)間,單位為秒,超過這一時(shí)間,Tomcat有可能把這個(gè)Session對(duì)象移到Session Store中。
maxIdleSwap
Session處于不活動(dòng)狀態(tài)的最大時(shí)間,超過這一時(shí)間,Tomcat就一定會(huì)將這個(gè)Session對(duì)象移到Session Store中。
maxIdleBackup
Session處于不活動(dòng)狀態(tài)的最大時(shí)間,超過這一時(shí)間,Tomcat就就會(huì)將這個(gè)Session對(duì)象拷貝到Session Store中進(jìn)行備份。
directory
指定Session Store在哪個(gè)文件系統(tǒng)目錄下存放持久化的Session對(duì)象的信息,文件名是Session ID.session。
配置JDBCStore:
在server.xml中,在Web應(yīng)用的<Context>元素加入<Manager>元素,例如:
<Context path=”/helloapp” docBase=”helloapp” debug=”0” reloadable=”true”>
<Manager className=”org.apache.catalina.session.PersistentManager”>
debug=0;
saveOnRestart=”true”
maxActiveSessions=”-1”
minIdleSwap=”-1”
maxIdleSwap=”-1”
maxIdleBackup=”-1”
<Store className=”org.apache.catalina.session.JDBCStore”
driverName=”com.mysql.jdbc.Driver”
connectionURL=”jdbc:mysql://localhost:3306/demo?user=root password=1234”
sessionTable=”tomcat_sessions”
sessionIdCol=”session_id”
sessionDataCol=”session_data”
sessionValidCol=”session_valid”
sessionMaxInactiveCol=”max_inactive”
sessionLastAccessedCol=”last_access”
sessionAppCol=”app_name”
checkInterval=”60”
debug=”0”
/>
</Manager>
</Context>
說明:上面的元素屬性的含義與FileStore的相同,上面的配置假設(shè)在MySQL服務(wù)器上的demo數(shù)據(jù)庫的tomcat_sessions表中存放持久化Session對(duì)象的信息,這個(gè)表的結(jié)構(gòu)如下:
CREATE TABLE tomcat_sessions(
session_id VARCHAR(10) NOT NULL PRIMARY KEY,
session_data MEDIUMBLOB,
session_valid CHAR(1) NOT NULL,
max_inactive INT NOT NULL,
last_access BIGINT NOT NULL,
app_name VARCHR(255),
KEY kapp_name(app_name)
);
Filter相關(guān)
Servlet過濾器是在Java Servlet規(guī)范2.3中定義的,它能夠?qū)ervlet容器的請(qǐng)求和響應(yīng)對(duì)象進(jìn)行檢查和修改,它在Servlet被調(diào)用之前檢查Request對(duì)象,修改Request Header和Request內(nèi)容;在Servlet被調(diào)用之后檢查Response對(duì)象,修改Response Header和Response內(nèi)容。Servlet過濾器負(fù)責(zé)過濾的Web組件可以是Servlet、JSP或HTML文件,具有以下特點(diǎn):
l Servlet過濾器可能檢查和修改ServletRequest和ServletResponse對(duì)象
l 可以指定Servlet過濾器和特定的URL關(guān)聯(lián),只有當(dāng)客戶請(qǐng)求訪問此URL時(shí),才會(huì)觸發(fā)該過濾器工作
l 多個(gè)Servlet過濾器可以被串聯(lián)起來,形成管道效應(yīng),協(xié)同修改請(qǐng)求和響應(yīng)對(duì)象
l 所有支持Java Servlet規(guī)范2.3的Servlet容器,都支持Servlet過濾器
所有的Servlet過濾器類都必須實(shí)現(xiàn)javax.servlet.Filter接口。該接口定義了以下3個(gè)方法:
l init(FilterConfig) 這是Servlet過濾器的初始化方法,Servlet容器創(chuàng)建Servlet過濾器實(shí)例后就會(huì)調(diào)用這個(gè)方法。在這個(gè)方法中可以通過FilterConfig來讀取web.xml文件中Servlet過濾器的初始化參數(shù)。
l doFilter(ServletRequest, ServletResponse, FilterChain) 這是完成實(shí)際的過濾操作的方法,當(dāng)客戶請(qǐng)求訪問與過濾器關(guān)聯(lián)的URL時(shí),Servlet容器先調(diào)用該方法。FilterChain參數(shù)用來訪問后續(xù)的過濾器的doFilter()方法。
l destroy() Servlet容器在銷毀過濾器實(shí)例前調(diào)用該方法,在這個(gè)方法中,可以釋放過濾器占用的資源。
下面是一個(gè)過濾器的例子,它可以拒絕列在黑名單上的客戶訪問留言簿,而且能將服務(wù)器響應(yīng)客戶請(qǐng)求所花的時(shí)間寫入日志:
//WEB-INF/classes/NoteFilter.class
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class NoteFilter implements Filter{
private FilterConfig config=null;
private String blackList=null;
public void init(FilterConfig config)throws ServletException{
this.config=config;
blackList=config.getInitParameter(“blacklist”);
}
public void destroy(){
config=null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException{
String userName=((HttpServletRequest)request).getParameter(“user_name”);
if(userName!=null)
userName=new String(userName.getBytes(“ISO-8859-1”),”GB2312”);
if(userName!=null && userName.indexOf(blackList)!=-1){
PrintWriter out=response.getWriter();
out.print(“<html><body>”);
out.print(“<h1>對(duì)不起,”+userName+”,你沒有權(quán)限留言</h1>”);
out.print(“</body></html>”);
out.flush();
return;
}
long before=System.currentTimeMillis();
config.getServletContext().log(“NoteFilter:before call chain.doFilter()”);
chan.doFilter(request, response);
config.getServletContext().log(“NoteFilter:after call chain.doFilter()”);
logn after=System.currentTimeMillis();
String name=””;
if(request instanceof HttpServletRequest)
name=((HttpServletRequest)request).getRequestURL();
config.getServletContext().log(“NoteFilter:”+name+”:”+(after-before)+”ms”);
}
}
發(fā)布Servlet過濾器,必須在web.xml文件中加入<filter>和<filter-mapping>元素,如下:
<filter>
<filter-name>NoteFilter</filter>
<filter-class>NoteFilter</filter-class>
<init-param>
<param-name>blackList</param-name>
<param-value>搗蛋鬼</param-value>
</init-param>
<filter>
<filter-mapping>
<filter-name>NoteFilter</filter-name>
<url-pattern>/note</url-pattern>
</filter-mapping>
多個(gè)過濾器可以串連起來協(xié)同工作,Servlet容器將根據(jù)它們?cè)趙eb.xml中定義的先后順序,依次調(diào)用它們的doFilter()方法。而這些過濾之間的關(guān)系不需要任何配置。
Listener的作用類似于load-on-startup的Servlet,在Web應(yīng)用啟動(dòng)時(shí)被加載,在Web應(yīng)用關(guān)閉時(shí)被銷毀,Listener用來作為Web應(yīng)用的后臺(tái)服務(wù),比load-on-startup的Servlet更早被加載到Servlet容器中。自定義的Listener類必須實(shí)現(xiàn)ServletContextListener接口,并實(shí)現(xiàn)該接口的兩個(gè)方法:contextInitialized(ServletContextEvent)和contextDestroyed(ServletContextEvent),例如:
public class GetConnListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
try{
ServletContext application=sce.getServletContext();
String driver=application.getInitParameter("driver");
String url=application.getInitParameter("url");
String user=application.getInitParameter("user");
String password=application.getInitParameter("password");
Class.forName(driver);
Connection conn=DriverManager.getConnection(url, user, password);
application.setAttribute("conn", conn);
}catch(Exception e){
System.out.println("Listener中獲取數(shù)據(jù)庫連接出現(xiàn)異常:"+e.getMessage());
}
}
public void contextDestroyed(ServletContextEvent sce){
ServletContext application=sce.getServletContext();
Connection conn=(Connection)application.getAtrribute("conn");
if(conn!=null){
try{
conn.close();
conn=null;
}catch(Exception e){}
}
}
}
Listener配置:
<listener>
<listener-class>lee.GetConnListener</listener-class>
</listener>
自定義JSP標(biāo)簽庫
實(shí)現(xiàn)自定義標(biāo)簽的處理類
JSP容器編譯JSP網(wǎng)頁時(shí),遇到自定義標(biāo)簽,就會(huì)調(diào)用這個(gè)標(biāo)簽的處理類。標(biāo)簽處理類必須擴(kuò)展自javax.servlet.jsp.TagSupport類或javax.servlet.jsp.BodyTagSupport類。
1、TagSupport類的主要方法如下:
l doStartTag JSP容器遇到自定義標(biāo)簽的起始標(biāo)志時(shí)調(diào)用該方法。
l doEndTag JSP容器遇到自定義標(biāo)簽的結(jié)束標(biāo)志時(shí)調(diào)用該方法。
l setValue(String k, Object v) 在標(biāo)簽處理類中設(shè)置key/value。
l getValue(String k) 在標(biāo)簽處理類中獲得key對(duì)應(yīng)的value。
l removeValue(String k) 在標(biāo)簽處理類中刪除key/value。
l setPageContext(PageContext pc) 設(shè)置PageContext對(duì)象,由JSP容器在調(diào)用doStartTag或doEndTag方法之前調(diào)用。
l setParent(Tag t) 設(shè)置該標(biāo)簽的上層標(biāo)簽的處理類,由JSP容器在調(diào)用doStartTag或 doEndTag方法之前調(diào)用。
l getParent() 返回該標(biāo)簽的上層標(biāo)簽的處理類。
2、TagSupport類有兩個(gè)重要屬性:
l parent 該標(biāo)簽的上層標(biāo)簽的處理類。
l pageContext Web應(yīng)用中的javax.servlet.jsp.PageContext對(duì)象,提供了保存和訪問Web應(yīng)用的共享數(shù)據(jù)方法:setAttribute(String name, Object value, int scope)和getAttribute(String name, int scope)。其中scope參數(shù)用來指定屬性存在的范圍,可選值有:PageContext.PAGE_SCOPE、PageContext.REQUEST_SCOPE、PageContext.SESSION_SCOPE和PageContext.APPLICATION_SCOPE。
注意:在TagSupport的構(gòu)造函數(shù)中不能訪問pageContext成員,因?yàn)榇藭r(shí)JSP容器還沒有調(diào)用setPageContext 方法對(duì)pageContext進(jìn)行初始化。
3、處理標(biāo)簽的方法:
當(dāng)JSP容器遇到自定義標(biāo)簽的起始標(biāo)志時(shí),就會(huì)調(diào)用該標(biāo)簽處理類的doStartTag()方法。doStartTag()方法返回一個(gè)整數(shù)值,用來決定程序的后續(xù)流程,有兩個(gè)可選值:Tag.SKIP_BODY和Tag.EVAL_BODY_INCLUDE。Tag.SKIP_BODY表示標(biāo)簽之間的內(nèi)容被忽略,例如:
<prefix:mytag>
Hello World!
</prefix:mytag>
如果這個(gè)標(biāo)簽的處理類的doStartTag()方法返回Tag.SKIP_BODY,則Hello World!字符串不會(huì)顯示在網(wǎng)頁上。Tag.EVAL_BODY_INCLUDE表示標(biāo)簽之間的內(nèi)容會(huì)被處理。
當(dāng)JSP容器遇到自定義標(biāo)簽的結(jié)束標(biāo)志時(shí),就會(huì)調(diào)用該標(biāo)簽處理類的doEndTag()方法。doEndTag()方法也返回一個(gè)整數(shù)值,表示程序的后續(xù)流程,也是有兩個(gè)可選值:Tag.SKIP_PAGE和Tag.EVAL_PAGE。Tag.SKIP_PAGE表示立刻停止執(zhí)行JSP頁面,該標(biāo)簽的結(jié)束標(biāo)志之后的所有頁面內(nèi)容全部會(huì)初忽略,任何已有的輸出內(nèi)容立刻返回到客戶的瀏覽器上;Tag.EVAL_PAGE表示按正常的流程繼續(xù)執(zhí)行JSP頁面的內(nèi)容。
4、自定義標(biāo)簽的屬性
例如:<prefix:mytag attribute1=”value1”>…</prefix:mytag>
那么在標(biāo)簽處理類中必須將這個(gè)屬性作為類的成員變量,并且必須提供相應(yīng)的getter和setter方法,例如:
private int attribute1;
public void setAttribute1(int value){ attribute1=value;}
public int getAttribute1(){return attribute1;}
以下是一個(gè)自定義標(biāo)簽<message>的處理類的例子:
// WEB-INF/classess/mypack/MessageTag.class
package mypack;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspTagException;
import javax.servlet.jsp.TagSupport;
import javax.servlet.http.HttpSession;
import java.util.Properties;
import java.io.*;
public class MessageTag extends TagSupport{
private String key=null;
public MessageTag(){}
public void setKey(String key){
this.key=key;
}
public String getKey(){
return key;
}
public int doEndTag() throws JspException{
try{
pageContext.getOut.print(key);
}catch(Exception e){
throw new JspTagException(e.getMessage());
}
return SkIP_BODY;
}
public void release(){
super.release();
}
}
創(chuàng)建標(biāo)簽庫描述文件(Tag Library Descriptor, TLD)
TLD文件中的元素可分為3類:
l <taglib>元素用來設(shè)置標(biāo)簽庫的相關(guān)信息,它有如下屬性:
tlibversion 指定標(biāo)簽庫的版本
jspversion 指定JSP的版本
shortname 指定標(biāo)簽庫默認(rèn)的前綴名(prefix)
uri 設(shè)置標(biāo)簽庫的唯一訪問標(biāo)示符
info 標(biāo)簽庫的說明信息
l <tag>元素用來定義一個(gè)標(biāo)簽,它的屬性如下:
name 標(biāo)簽的名字
tagclass 標(biāo)簽的處理類
bodycontent 標(biāo)簽主體(body)的內(nèi)容
info 標(biāo)簽的說明信息
說明:bodycontent屬性有3個(gè)可選值:empty、JSP和tagdependent。empty表示標(biāo)簽沒有主體,JSP表示標(biāo)簽的主體中可以加入JSP代碼,tagdependent表示標(biāo)簽的主體的內(nèi)容由標(biāo)簽的處理類自己去處理。
l <attribute>元素用來定義標(biāo)簽的屬性,它有如下屬性:
name 屬性名
required 該屬性是否必須,默認(rèn)是false
rtexprvalue 該屬性的值是否可能通過”<%=…%>”的方式獲得,當(dāng)設(shè)置為true時(shí),該屬性就可以采用如下的方式設(shè)置值:<% int num=1;%> <prefix:mytag attribute1=”<%=num%>”/>
以下是一個(gè)標(biāo)簽庫描述文件的例子:
<!--WEB-INF/mytag.tld-->
<?xml version=”1.0” encoding=”ISO-8859-1”?>
<!DOCTYPE taglib PUBLIC “-//Sun Microsystems,Inc.//DTD JSP TagLibrary 1.1//EN”
“http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd”>
<taglib>
<tlibversion>1.0</tlibversion>
<jspversion>1.1</jspversion>
<shortname>mytaglib</shortname>
<uri>/mytaglib</uri>
<tag>
<name>message</name>
<tagclass>mypack.MessageTag</tagclass>
<bodycontent>empty</bodycontent>
<info>produce message by key</info>
<attribute>
<name>key</name>
<required>true</required>
<rtexprvalue>true</rtexprvalue>
</attribute>
</tag>
</taglib>
在web.xml文件中加入標(biāo)簽庫的定義
<taglib>
<!--標(biāo)簽庫的唯一標(biāo)示符,與標(biāo)簽庫描述文件中的<uri>元素的內(nèi)容相同,在JSP頁面中,也要通過這個(gè)定義來使用標(biāo)簽庫-->
<taglib-uri>/mytaglib</taglib-uri>
<!--指定標(biāo)簽庫描述文件所在的位置-->
<taglib-location>/WEB-INF/mytaglib.tld</taglib-location>
</taglib>
在JSP頁面中使用自定義的標(biāo)簽
例如:
<%@ taglib uri=”/mytaglib” prefix=”mm”%>
<html>
<body>
<mm:message key=”hello world!”/>
</body>
</html>