Filter、Servlet、Listener的學(xué)習(xí)_動力節(jié)點Java學(xué)院整理
Java中Filter、Servlet、Listener的學(xué)習(xí)資料,希望大家喜歡
1、Filter的功能
filter功能,它使用戶可以改變一個 request和修改一個response. Filter 不是一個servlet,它不能產(chǎn)生一個response,它能夠在一個request到達(dá)servlet之前預(yù)處理request,也可以在離開 servlet時處理response.換種說法,filter其實是一個”servlet chaining”(servlet 鏈).
一個Filter包括:
1)、在servlet被調(diào)用之前截獲;
2)、在servlet被調(diào)用之前檢查servlet request;
3)、根據(jù)需要修改request頭和request數(shù)據(jù);
4)、根據(jù)需要修改response頭和response數(shù)據(jù);
5)、在servlet被調(diào)用之后截獲.
服務(wù)器每次只調(diào)用setFilterConfig方法一次準(zhǔn)備filter 的處理;調(diào)用doFilter方法多次以處理不同的請求.FilterConfig接口有方法可以找到filter名字及初始化參數(shù)信息.服務(wù)器可以設(shè)置 FilterConfig為空來指明filter已經(jīng)終結(jié)。
每一個filter從doFilter()方法中得到當(dāng)前的request及response.在這個方法里,可以進(jìn)行任何的針對request及 response的操作.(包括收集數(shù)據(jù),包裝數(shù)據(jù)等).filter調(diào)用chain.doFilter()方法把控制權(quán)交給下一個filter.一個 filter在doFilter()方法中結(jié)束.如果一個filter想停止request處理而獲得對response的完全的控制,那它可以不調(diào)用下 一個filter
例子:
首先新建一個Filter
/**
*
*/
package com.ee.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* @author Administrator
*
*/
public class LogFilter implements Filter {
private FilterConfig filterConfig;
public FilterConfig getFilterConfig() {
System.err.println("...getFilterConfig...");
return filterConfig;
}
public void setFilterConfig(FilterConfig filterConfig) {
System.err.println("...setFilterConfig...");
this.filterConfig = filterConfig;
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
System.err.println("...filter destroy...");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.err.println("...doFilter...");
chain.doFilter(request, response);//看到這沒,這只要是傳遞下一個Filter
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.err.println("...init Filter...");
this.filterConfig = filterConfig;
}
}
在web.xml里配置
<filter> <filter-name>LogFilter</filter-name> <filter-class>com.ee.filter.LogFilter</filter-class> </filter> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
啟動運行
可以看到...init Filter...首先在TOMCAT啟動時即被打印,然后在運行里面再看到...doFilter...被打印。
2、servlet功能
1).Servlet 是什么?
Servlet是使用Java Servlet 應(yīng)用程序設(shè)計接口(API)及相關(guān)類和方法的 Java 程序。除了 Java Servlet API,Servlet 還可以使用用以擴(kuò)展和添加到 API 的 Java 類軟件包。Servlet 在啟用 Java 的 Web 服務(wù)器上或應(yīng)用服務(wù)器上運行并擴(kuò)展了該服務(wù)器的能力。Java servlet對于Web服務(wù)器就好象Java applet對于Web瀏覽器。Servlet裝入Web服務(wù)器并在Web服務(wù)器內(nèi)執(zhí)行,而applet裝入Web瀏覽器并在Web瀏覽器內(nèi)執(zhí)行。Java Servlet API 定義了一個servlet 和Java使能的服務(wù)器之間的一個標(biāo)準(zhǔn)接口,這使得Servlets具有跨服務(wù)器平臺的特性。
Servlet 通過創(chuàng)建一個框架來擴(kuò)展服務(wù)器的能力,以提供在 Web 上進(jìn)行請求和響應(yīng)服務(wù)。當(dāng)客戶機(jī)發(fā)送請求至服務(wù)器時,服務(wù)器可以將請求信息發(fā)送給 Servlet,并讓 Servlet 建立起服務(wù)器返回給客戶機(jī)的響應(yīng)。 當(dāng)啟動 Web 服務(wù)器或客戶機(jī)第一次請求服務(wù)時,可以自動裝入 Servlet。裝入后, Servlet 繼續(xù)運行直到其它客戶機(jī)發(fā)出請求。Servlet 的功能涉及范圍很廣。例如,Servlet 可完成如下功能:
(1) 創(chuàng)建并返回一個包含基于客戶請求性質(zhì)的動態(tài)內(nèi)容的完整的 HTML頁面。
(2) 創(chuàng)建可嵌入到現(xiàn)有 HTML 頁面中的一部分 HTML 頁面(HTML 片段)。
(3) 與其它服務(wù)器資源(包括數(shù)據(jù)庫和基于 Java 的應(yīng)用程序)進(jìn)行通信。
(4) 用多個客戶機(jī)處理連接,接收多個客戶機(jī)的輸入,并將結(jié)果廣播到多個客戶機(jī)上。例如,Servlet 可以是多參與者的游戲服務(wù)器。
(5) 當(dāng)允許在單連接方式下傳送數(shù)據(jù)的情況下,在瀏覽器上打開服務(wù)器至applet的新連接,并將該連
接保持在打開狀態(tài)。當(dāng)允許客戶機(jī)和服務(wù)器簡單、高效地執(zhí)行會話的情況下,applet也可以啟動客戶瀏覽器和服務(wù)器之間的連接??梢酝ㄟ^定制協(xié)議或標(biāo)準(zhǔn)(如 IIOP)進(jìn)行通信。
(6) 對特殊的處理采用 MIME 類型過濾數(shù)據(jù),例如圖像轉(zhuǎn)換和服務(wù)器端包括(SSI)。
(7) 將定制的處理提供給所有服務(wù)器的標(biāo)準(zhǔn)例行程序。例如,Servlet 可以修改如何認(rèn)證用戶。
2).Servlet 的生命周期
Servlet 的生命周期始于將它裝入 Web 服務(wù)器的內(nèi)存時,并在終止或重新裝入 Servlet 時結(jié)束。
(1) 初始化
在下列時刻裝入 Servlet:
如果已配置自動裝入選項,則在啟動服務(wù)器時自動裝入
在服務(wù)器啟動后,客戶機(jī)首次向 Servlet 發(fā)出請求時
重新裝入 Servlet 時裝入 Servlet 后,服務(wù)器創(chuàng)建一個 Servlet 實例并且調(diào)用 Servlet 的 init() 方法。在初始化階段,Servlet 初始化參數(shù)被傳遞給 Servlet 配置對象。
(2) 請求處理
對于到達(dá)服務(wù)器的客戶機(jī)請求,服務(wù)器創(chuàng)建特定于請求的一個“請求”對象和一個“響應(yīng)”對象。服務(wù)器調(diào)用 Servlet 的 service() 方法,該方法用于傳遞“請求”和“響應(yīng)”對象。service() 方法從“請求”對象獲得請求信息、處理該請求并用“響應(yīng)”對象的方法以將響應(yīng)傳回客戶機(jī)。service() 方法可以調(diào)用其它方法來處理請求,例如 doGet()、doPost() 或其它的方法。
(3) 終止
當(dāng)服務(wù)器不再需要 Servlet, 或重新裝入 Servlet 的新實例時,服務(wù)器會調(diào)用 Servlet 的 destroy() 方法。
3). Java Servlet API
Java Servlet 開發(fā)工具(JSDK)提供了多個軟件包,在編寫 Servlet 時需要用到這些軟件包。其中包括兩個用于所有 Servlet 的基本軟件包:javax.servlet 和 javax.servlet.http。可從sun公司的Web站點下載 Java Servlet 開發(fā)工具。 下面主要介紹javax.servlet.http提供的HTTP Servlet應(yīng)用編程接口。
HTTP Servlet 使用一個 HTML 表格來發(fā)送和接收數(shù)據(jù)。要創(chuàng)建一個 HTTP Servlet,請擴(kuò)展 HttpServlet 類, 該類是用專門的方法來處理 HTML 表格的 GenericServlet 的一個子類。 HTML 表單是由 <FORM> 和 </FORM> 標(biāo)記定義的。表單中典型地包含輸入字段(如文本輸入字段、復(fù)選框、單選按鈕和選擇列表)和用于提交數(shù)據(jù)的按鈕。當(dāng)提交信息時,它們還指定服務(wù)器應(yīng)執(zhí)行哪一個Servlet(或其它的程序)。 HttpServlet 類包含 init()、destroy()、service() 等方法。其中 init() 和 destroy() 方法是繼承的。
(1) init() 方法
在 Servlet 的生命期中,僅執(zhí)行一次 init() 方法。它是在服務(wù)器裝入 Servlet 時執(zhí)行的。 可以配置服務(wù)器,以在啟動服務(wù)器或客戶機(jī)首次訪問 Servlet 時裝入 Servlet。 無論有多少客戶機(jī)訪問 Servlet,都不會重復(fù)執(zhí)行 init() 。
缺省的 init() 方法通常是符合要求的,但也可以用定制 init() 方法來覆蓋它,典型的是管理服務(wù)器端資源。 例如,可能編寫一個定制 init() 來只用于一次裝入 GIF 圖像,改進(jìn) Servlet 返回 GIF 圖像和含有多個客戶機(jī)請求的性能。另一個示例是初始化數(shù)據(jù)庫連接。缺省的 init() 方法設(shè)置了 Servlet 的初始化參數(shù),并用它的 ServletConfig 對象參數(shù)來啟動配置, 因此所有覆蓋 init() 方法的 Servlet 應(yīng)調(diào)用 super.init() 以確保仍然執(zhí)行這些任務(wù)。在調(diào)用 service() 方法之前,應(yīng)確保已完成了 init() 方法。
(2) service() 方法
service() 方法是 Servlet 的核心。每當(dāng)一個客戶請求一個HttpServlet 對象,該對象的service() 方法就要被調(diào)用,而且傳遞給這個方法一個“請求”(ServletRequest)對象和一個“響應(yīng)”(ServletResponse)對象作為參數(shù)。 在 HttpServlet 中已存在 service() 方法。缺省的服務(wù)功能是調(diào)用與 HTTP 請求的方法相應(yīng)的 do 功能。例如, 如果 HTTP 請求方法為 GET,則缺省情況下就調(diào)用 doGet() 。Servlet 應(yīng)該為 Servlet 支持的 HTTP 方法覆蓋 do 功能。因為 HttpServlet.service() 方法會檢查請求方法是否調(diào)用了適當(dāng)?shù)奶幚矸椒?,不必要覆蓋 service() 方法。只需覆蓋相應(yīng)的 do 方法就可以了。
當(dāng)一個客戶通過HTML 表單發(fā)出一個HTTP POST請求時,doPost()方法被調(diào)用。與POST請求相關(guān)的參數(shù)作為一個單獨的HTTP 請求從瀏覽器發(fā)送到服務(wù)器。當(dāng)需要修改服務(wù)器端的數(shù)據(jù)時,應(yīng)該使用doPost()方法。
當(dāng)一個客戶通過HTML 表單發(fā)出一個HTTP GET請求或直接請求一個URL時,doGet()方法被調(diào)用。與GET請求相關(guān)的參數(shù)添加到URL的后面,并與這個請求一起發(fā)送。當(dāng)不會修改服務(wù)器端的數(shù)據(jù)時,應(yīng)該使用doGet()方法。
Servlet的響應(yīng)可以是下列幾種類型:
一個輸出流,瀏覽器根據(jù)它的內(nèi)容類型(如text/HTML)進(jìn)行解釋。
一個HTTP錯誤響應(yīng), 重定向到另一個URL、servlet、JSP。
(3) destroy() 方法
destroy() 方法僅執(zhí)行一次,即在服務(wù)器停止且卸裝Servlet 時執(zhí)行該方法。典型的,將 Servlet 作為服務(wù)器進(jìn)程的一部分來關(guān)閉。缺省的 destroy() 方法通常是符合要求的,但也可以覆蓋它,典型的是管理服務(wù)器端資源。例如,如果 Servlet 在運行時會累計統(tǒng)計數(shù)據(jù),則可以編寫一個 destroy() 方法,該方法用于在未裝入 Servlet 時將統(tǒng)計數(shù)字保存在文件中。另一個示例是關(guān)閉數(shù)據(jù)庫連接。
當(dāng)服務(wù)器卸裝 Servlet 時,將在所有 service() 方法調(diào)用完成后,或在指定的時間間隔過后調(diào)用 destroy() 方法。一個Servlet 在運行service() 方法時可能會產(chǎn)生其它的線程,因此請確認(rèn)在調(diào)用 destroy() 方法時,這些線程已終止或完成。
(4) GetServletConfig()方法
GetServletConfig()方法返回一個 ServletConfig 對象,該對象用來返回初始化參數(shù)和 ServletContext。ServletContext 接口提供有關(guān)servlet 的環(huán)境信息。
(5) GetServletInfo()方法
GetServletInfo()方法是一個可選的方法,它提供有關(guān)servlet 的信息,如作者、版本、版權(quán)。
當(dāng)服務(wù)器調(diào)用sevlet 的Service()、doGet()和doPost()這三個方法時,均需要 “請求”和“響應(yīng)”對象作為參數(shù)?!罢埱蟆睂ο筇峁┯嘘P(guān)請求的信息,而“響應(yīng)”對象提供了一個將響應(yīng)信息返回給瀏覽器的一個通信途徑。javax.servlet 軟件包中的相關(guān)類為ServletResponse和ServletRequest,而javax.servlet.http 軟件包中的相關(guān)類為HttpServletRequest 和 HttpServletResponse。Servlet 通過這些對象與服務(wù)器通信并最終與客戶機(jī)通信。Servlet 能通過調(diào)用“請求”對象的方法獲知客戶機(jī)環(huán)境,服務(wù)器環(huán)境的信息和所有由客戶機(jī)提供的信息。Servlet 可以調(diào)用“響應(yīng)”對象的方法發(fā)送響應(yīng),該響應(yīng)是準(zhǔn)備發(fā)回客戶機(jī)的。
例子:
創(chuàng)建一個servlet
/**
*
*/
package com.ee.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Administrator
*
*/
public class LogServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.err.println("...doPost(req, resp)...");
}
}
在web.xml中的配置:
<servlet> <servlet-name>LogServlet</servlet-name> <servlet-class>com.ee.servlet.LogServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>LogServlet</servlet-name> <url-pattern>/*</url-pattern><!-- 看到此沒有,這個攔截所有路徑 --> </servlet-mapping>
它的攔截規(guī)則:
當(dāng)一個請求發(fā)送到servlet容器的時候,容器先會將請求的url減去當(dāng)前應(yīng)用上下文的路徑作為servlet的映射url,比如我訪問的是http://localhost/test/aaa.html,我的應(yīng)用上下文是test,容器會將http://localhost/test去掉,剩下的/aaa.html部分拿來做servlet的映射匹配。這個映射匹配過程是有順序的,而且當(dāng)有一個servlet匹配成功以后,就不會去理會剩下的servlet了(filter不同,后文會提到)。其匹配規(guī)則和順序如下:
1.精確路徑匹配。例子:比如servletA 的url-pattern為 /test,servletB的url-pattern為 /* ,這個時候,如果我訪問的url為http://localhost/test ,這個時候容器就會先 進(jìn)行精確路徑匹配,發(fā)現(xiàn)/test正好被servletA精確匹配,那么就去調(diào)用servletA,也不會去理會其他的servlet了。
2.最長路徑匹配。例子:servletA的url-pattern為/test/*,而servletB的url-pattern為/test/a/*,此時訪問http://localhost/test/a時,容器會選擇路徑最長的servlet來匹配,也就是這里的servletB。
3.擴(kuò)展匹配,如果url最后一段包含擴(kuò)展,容器將會根據(jù)擴(kuò)展選擇合適的servlet。例子:servletA的url-pattern:*.action
4.如果前面三條規(guī)則都沒有找到一個servlet,容器會根據(jù)url選擇對應(yīng)的請求資源。如果應(yīng)用定義了一個default servlet,則容器會將請求丟給default servlet
3、Listener功能
它是基于觀察者模式設(shè)計的,Listener 的設(shè)計對開發(fā) Servlet 應(yīng)用程序提供了一種快捷的手段,能夠方便的從另一個縱向維度控制程序和數(shù)據(jù)。目前 Servlet 中提供了 5 種兩類事件的觀察者接口,它們分別是:4 個 EventListeners 類型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener 和 2 個 LifecycleListeners 類型的,ServletContextListener、HttpSessionListener。如下圖所示:

Listener是Servlet的監(jiān)聽器,它可以監(jiān)聽客戶端的請求、服務(wù)端的操作等。通過監(jiān)聽器,可以自動激發(fā)一些操作,比如監(jiān)聽在線的用戶的數(shù)量。當(dāng)增加一個HttpSession時,就激發(fā)sessionCreated(HttpSessionEvent se)方法,這樣就可以給在線人數(shù)加1。常用的監(jiān)聽接口有以下幾個:
ServletContextAttributeListener監(jiān)聽對ServletContext屬性的操作,比如增加、刪除、修改屬性。
ServletContextListener監(jiān)聽ServletContext。當(dāng)創(chuàng)建ServletContext時,激發(fā)contextInitialized(ServletContextEvent sce)方法;當(dāng)銷毀ServletContext時,激發(fā)contextDestroyed(ServletContextEvent sce)方法。
HttpSessionListener監(jiān)聽HttpSession的操作。當(dāng)創(chuàng)建一個Session時,激發(fā)session Created(HttpSessionEvent se)方法;當(dāng)銷毀一個Session時,激發(fā)sessionDestroyed (HttpSessionEvent se)方法。
HttpSessionAttributeListener監(jiān)聽HttpSession中的屬性的操作。當(dāng)在Session增加一個屬性時,激發(fā)attributeAdded(HttpSessionBindingEvent se) 方法;當(dāng)在Session刪除一個屬性時,激發(fā)attributeRemoved(HttpSessionBindingEvent se)方法;當(dāng)在Session屬性被重新設(shè)置時,激發(fā)attributeReplaced(HttpSessionBindingEvent se) 方法。
下面我們開發(fā)一個具體的例子,這個監(jiān)聽器能夠統(tǒng)計在線的人數(shù)。在ServletContext初始化和銷毀時,在服務(wù)器控制臺打印對應(yīng)的信息。當(dāng)ServletContext里的屬性增加、改變、刪除時,在服務(wù)器控制臺打印對應(yīng)的信息。
要獲得以上的功能,監(jiān)聽器必須實現(xiàn)以下3個接口:
HttpSessionListener
ServletContextListener
ServletContextAttributeListener
例子:
/**
*
*/
package com.ee.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/**
* @author Administrator
*
*/
public class OnlineUserListener implements HttpSessionListener,
ServletContextListener, ServletContextAttributeListener {
private long onlineUserCount = 0;
public long getOnlineUserCount() {
return onlineUserCount;
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextAttributeListener#attributeAdded(javax.servlet.ServletContextAttributeEvent)
*/
@Override
public void attributeAdded(ServletContextAttributeEvent arg0) {
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextAttributeListener#attributeRemoved(javax.servlet.ServletContextAttributeEvent)
*/
@Override
public void attributeRemoved(ServletContextAttributeEvent arg0) {
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextAttributeListener#attributeReplaced(javax.servlet.ServletContextAttributeEvent)
*/
@Override
public void attributeReplaced(ServletContextAttributeEvent attributeEvent) {
System.err.println("...attributeReplaced...");
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)
*/
@Override
public void contextDestroyed(ServletContextEvent arg0) {
}
/* (non-Javadoc)
* @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)
*/
@Override
public void contextInitialized(ServletContextEvent arg0) {
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)
*/
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
onlineUserCount ++;
toUpdateCount(httpSessionEvent);
}
/* (non-Javadoc)
* @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)
*/
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
onlineUserCount --;
toUpdateCount(httpSessionEvent);
}
private void toUpdateCount(HttpSessionEvent httpSessionEvent){
httpSessionEvent.getSession().setAttribute("onlineUserCount", onlineUserCount);
}
}
Web.xml
<listener> <listener-class>com.ee.listener.OnlineUserListener</listener-class> </listener>
JSP頁面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>主頁</title>
</head>
<body>
<h4>你好!</h4>
在線人數(shù):<h1><%=request.getSession().getAttribute("onlineUserCount") %></h1>
</body>
</html>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Socket+JDBC+IO實現(xiàn)Java文件上傳下載器DEMO詳解
這篇文章主要介紹了Socket+JDBC+IO實現(xiàn)Java文件上傳下載器DEMO詳解,需要的朋友可以參考下2017-05-05
springboot配置項目啟動后自動打開瀏覽器訪問項目方式
這篇文章主要介紹了springboot配置項目啟動后自動打開瀏覽器訪問項目方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01

