天天看點

filter,servlet,listener

1、Filter的功能

filter功能,它使使用者可以改變一個 request和修改一個response. Filter

不是一個servlet,它不能産生一個response,它能夠在一個request到達servlet之前預處理request,也可以在離開

servlet時處理response.換種說法,filter其實是一個”servlet chaining”(servlet 鍊).

一個Filter包括:

1)、在servlet被調用之前截獲;

2)、在servlet被調用之前檢查servlet request;

3)、根據需要修改request頭和request資料;

4)、根據需要修改response頭和response資料;

5)、在servlet被調用之後截獲.

 伺服器每次隻調用setFilterConfig方法一次準備filter

的處理;調用doFilter方法多次以處理不同的請求.FilterConfig接口有方法可以找到filter名字及初始化參數資訊.伺服器可以設定

FilterConfig為空來指明filter已經終結。

每一個filter從doFilter()方法中得到目前的request及response.在這個方法裡,可以進行任何的針對request及

response的操作.(包括收集資料,包裝資料等).filter調用chain.doFilter()方法把控制權交給下一個filter.一個

filter在doFilter()方法中結束.如果一個filter想停止request處理而獲得對response的完全的控制,那它可以不調用下

一個filter

例子:

首先建立一個Filter

[java] view plaincopy

/** 

 *  

 */  

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...");  

     * @see

javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,

javax.servlet.ServletResponse, javax.servlet.FilterChain) 

    public void doFilter(ServletRequest request, ServletResponse response,  

            FilterChain chain) throws IOException, ServletException {  

        System.err.println("...doFilter...");  

        chain.doFilter(request, response);//看到這沒,這隻要是傳遞下一個Filter  

     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) 

    public void init(FilterConfig filterConfig) throws ServletException {  

        System.err.println("...init Filter...");  

}  

在web.xml裡配置

[html] view plaincopy

<filter>  

    <filter-name>LogFilter</filter-name>  

    <filter-class>com.ee.filter.LogFilter</filter-class>  

</filter>  

<filter-mapping>  

    <url-pattern>/*</url-pattern>  

</filter-mapping>  

啟動運作

可以看到...init Filter...首先在TOMCAT啟動時即被列印,然後在運作裡面再看到...doFilter...被列印。

2、servlet功能

1.Servlet 是什麼?

  Servlet是使用Java Servlet 應用程式設計接口(API)及相關類和方法的 Java 程式。除了 Java

Servlet API,Servlet 還可以使用用以擴充和添加到 API 的 Java 類軟體包。Servlet 在啟用 Java 的 Web

伺服器上或應用伺服器上運作并擴充了該伺服器的能力。Java servlet對于Web伺服器就好象Java

applet對于Web浏覽器。Servlet裝入Web伺服器并在Web伺服器内執行,而applet裝入Web浏覽器并在Web浏覽器内執行。Java

Servlet API 定義了一個servlet 和Java使能的伺服器之間的一個标準接口,這使得Servlets具有跨伺服器平台的特性。

  Servlet 通過建立一個架構來擴充伺服器的能力,以提供在 Web

上進行請求和響應服務。當客戶機發送請求至伺服器時,伺服器可以将請求資訊發送給 Servlet,并讓 Servlet

建立起伺服器傳回給客戶機的響應。 當啟動 Web 伺服器或客戶機第一次請求服務時,可以自動裝入 Servlet。裝入後, Servlet

繼續運作直到其它客戶機送出請求。Servlet 的功能涉及範圍很廣。例如,Servlet 可完成如下功能:

  (1) 建立并傳回一個包含基于客戶請求性質的動态内容的完整的 HTML頁面。

  (2) 建立可嵌入到現有 HTML 頁面中的一部分 HTML 頁面(HTML 片段)。

  (3) 與其它伺服器資源(包括資料庫和基于 Java 的應用程式)進行通信。

  (4) 用多個客戶機處理連接配接,接收多個客戶機的輸入,并将結果廣播到多個客戶機上。例如,Servlet 可以是多參與者的遊戲伺服器。

  (5) 當允許在單連接配接方式下傳送資料的情況下,在浏覽器上打開伺服器至applet的新連接配接,并将該連

接保持在打開狀态。當允許客戶機和伺服器簡單、高效地執行會話的情況下,applet也可以啟動客戶浏覽器和伺服器之間的連接配接。可以通過定制協定或标準(如 IIOP)進行通信。

  (6) 對特殊的處理采用 MIME 類型過濾資料,例如圖像轉換和伺服器端包括(SSI)。

  (7) 将定制的處理提供給所有伺服器的标準例行程式。例如,Servlet 可以修改如何認證使用者。

  2.Servlet 的生命周期

  Servlet 的生命周期始于将它裝入 Web 伺服器的記憶體時,并在終止或重新裝入 Servlet 時結束。

(1) 初始化

  在下列時刻裝入 Servlet:

 如果已配置自動裝入選項,則在啟動伺服器時自動裝入

 在伺服器啟動後,客戶機首次向 Servlet 送出請求時

 重新裝入 Servlet 時裝入 Servlet 後,伺服器建立一個 Servlet 執行個體并且調用 Servlet 的 init() 方法。在初始化階段,Servlet 初始化參數被傳遞給 Servlet 配置對象。

  (2) 請求處理

  對于到達伺服器的客戶機請求,伺服器建立特定于請求的一個“請求”對象和一個“響應”對象。伺服器調用 Servlet 的

service() 方法,該方法用于傳遞“請求”和“響應”對象。service()

方法從“請求”對象獲得請求資訊、處理該請求并用“響應”對象的方法以将響應傳回客戶機。service() 方法可以調用其它方法來處理請求,例如

doGet()、doPost() 或其它的方法。

  (3) 終止

  當伺服器不再需要 Servlet, 或重新裝入 Servlet 的新執行個體時,伺服器會調用 Servlet 的 destroy() 方法。

  3. Java Servlet API

  Java Servlet 開發工具(JSDK)提供了多個軟體包,在編寫 Servlet 時需要用到這些軟體包。其中包括兩個用于所有

Servlet 的基本軟體包:javax.servlet 和 javax.servlet.http。可從sun公司的Web站點下載下傳 Java

Servlet 開發工具。 下面主要介紹javax.servlet.http提供的HTTP Servlet應用程式設計接口。

  HTTP Servlet 使用一個 HTML 表格來發送和接收資料。要建立一個 HTTP Servlet,請擴充

HttpServlet 類, 該類是用專門的方法來處理 HTML 表格的 GenericServlet 的一個子類。 HTML 表單是由

<FORM> 和 </FORM>

标記定義的。表單中典型地包含輸入字段(如文本輸入字段、複選框、單選按鈕和選擇清單)和用于送出資料的按鈕。當送出資訊時,它們還指定伺服器應執行哪一個Servlet(或其它的程式)。

HttpServlet 類包含 init()、destroy()、service() 等方法。其中 init() 和 destroy()

方法是繼承的。

  (1) init() 方法

  在 Servlet 的生命期中,僅執行一次 init() 方法。它是在伺服器裝入 Servlet 時執行的。

可以配置伺服器,以在啟動伺服器或客戶機首次通路 Servlet 時裝入 Servlet。 無論有多少客戶機通路 Servlet,都不會重複執行

init() 。

  預設的 init() 方法通常是符合要求的,但也可以用定制 init() 方法來覆寫它,典型的是管理伺服器端資源。

例如,可能編寫一個定制 init() 來隻用于一次裝入 GIF 圖像,改進 Servlet 傳回 GIF

圖像和含有多個客戶機請求的性能。另一個示例是初始化資料庫連接配接。預設的 init() 方法設定了 Servlet 的初始化參數,并用它的

ServletConfig 對象參數來啟動配置, 是以所有覆寫 init() 方法的 Servlet 應調用 super.init()

以確定仍然執行這些任務。在調用 service() 方法之前,應確定已完成了 init() 方法。

  (2) service() 方法

  service() 方法是 Servlet 的核心。每當一個客戶請求一個HttpServlet 對象,該對象的service()

方法就要被調用,而且傳遞給這個方法一個“請求”(ServletRequest)對象和一個“響應”(ServletResponse)對象作為參數。

在 HttpServlet 中已存在 service() 方法。預設的服務功能是調用與 HTTP 請求的方法相應的 do 功能。例如, 如果

HTTP 請求方法為 GET,則預設情況下就調用 doGet() 。Servlet 應該為 Servlet 支援的 HTTP 方法覆寫 do

功能。因為 HttpServlet.service() 方法會檢查請求方法是否調用了适當的處理方法,不必要覆寫 service()

方法。隻需覆寫相應的 do 方法就可以了。

 當一個客戶通過HTML 表單發出一個HTTP POST請求時,doPost()方法被調用。與POST請求相關的參數作為一個單獨的HTTP 請求從浏覽器發送到伺服器。當需要修改伺服器端的資料時,應該使用doPost()方法。

 當一個客戶通過HTML 表單發出一個HTTP GET請求或直接請求一個URL時,doGet()方法被調用。與GET請求相關的參數添加到URL的後面,并與這個請求一起發送。當不會修改伺服器端的資料時,應該使用doGet()方法。

  Servlet的響應可以是下列幾種類型:

  一個輸出流,浏覽器根據它的内容類型(如text/HTML)進行解釋。

  一個HTTP錯誤響應, 重定向到另一個URL、servlet、JSP。

  (3) destroy() 方法

  destroy() 方法僅執行一次,即在伺服器停止且卸裝Servlet 時執行該方法。典型的,将 Servlet

作為伺服器程序的一部分來關閉。預設的 destroy() 方法通常是符合要求的,但也可以覆寫它,典型的是管理伺服器端資源。例如,如果

Servlet 在運作時會累計統計資料,則可以編寫一個 destroy() 方法,該方法用于在未裝入 Servlet

時将統計數字儲存在檔案中。另一個示例是關閉資料庫連接配接。

當伺服器卸裝 Servlet 時,将在所有 service() 方法調用完成後,或在指定的時間間隔過後調用 destroy()

方法。一個Servlet 在運作service() 方法時可能會産生其它的線程,是以請确認在調用 destroy()

方法時,這些線程已終止或完成。

  (4) GetServletConfig()方法

  GetServletConfig()方法傳回一個 ServletConfig 對象,該對象用來傳回初始化參數和  ServletContext。ServletContext 接口提供有關servlet 的環境資訊。

  (5) GetServletInfo()方法

  GetServletInfo()方法是一個可選的方法,它提供有關servlet 的資訊,如作者、版本、版權。

  當伺服器調用sevlet 的Service()、doGet()和doPost()這三個方法時,均需要

“請求”和“響應”對象作為參數。“請求”對象提供有關請求的資訊,而“響應”對象提供了一個将響應資訊傳回給浏覽器的一個通信途徑。javax.servlet

軟體包中的相關類為ServletResponse和ServletRequest,而javax.servlet.http

軟體包中的相關類為HttpServletRequest 和 HttpServletResponse。Servlet

通過這些對象與伺服器通信并最終與客戶機通信。Servlet

能通過調用“請求”對象的方法獲知客戶機環境,伺服器環境的資訊和所有由客戶機提供的資訊。Servlet

可以調用“響應”對象的方法發送響應,該響應是準備發回客戶機的。

建立一個servlet

package com.ee.servlet;  

import javax.servlet.http.HttpServlet;  

import javax.servlet.http.HttpServletRequest;  

import javax.servlet.http.HttpServletResponse;  

public class LogServlet extends HttpServlet {  

    /** 

     *  

    private static final long serialVersionUID = 1L;  

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  

            throws ServletException, IOException {  

        doPost(req, resp);  

    protected void doPost(HttpServletRequest req, HttpServletResponse resp)  

        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>  

    <url-pattern>/*</url-pattern><!-- 看到此沒有,這個攔截所有路徑 -->  

</servlet-mapping>  

它的攔截規則:

當一個請求發送到servlet容器的時候,容器先會将請求的url減去目前應用上下文的路徑作為servlet的映射url,比如我通路的是http://localhost/test/aaa.html,我的應用上下文是test,容器會将http://localhost/test去掉,剩下的/aaa.html部分拿來做servlet的映射比對。這個映射比對過程是有順序的,而且當有一個servlet比對成功以後,就不會去理會剩下的servlet了(filter不同,後文會提到)。其比對規則和順序如下:

1.     精确路徑比對。例子:比如servletA 的url-pattern為 /test,servletB的url-pattern為

/* ,這個時候,如果我通路的url為http://localhost/test ,這個時候容器就會先

進行精确路徑比對,發現/test正好被servletA精确比對,那麼就去調用servletA,也不會去理會其他的servlet了。

2.    

最長路徑比對。例子:servletA的url-pattern為/test/*,而servletB的url-pattern為/test/a/*,此時通路http://localhost/test/a時,容器會選擇路徑最長的servlet來比對,也就是這裡的servletB。

3.     擴充比對,如果url最後一段包含擴充,容器将會根據擴充選擇合适的servlet。例子:servletA的url-pattern:*.action

4.     如果前面三條規則都沒有找到一個servlet,容器會根據url選擇對應的請求資源。如果應用定義了一個default servlet,則容器會将請求丢給default servlet

3、Listener功能

它是基于觀察者模式設計的,Listener 的設計對開發 Servlet

應用程式提供了一種快捷的手段,能夠友善的從另一個縱向次元控制程式和資料。目前 Servlet 中提供了 5

種兩類事件的觀察者接口,它們分别是:4 個 EventListeners

類型的,ServletContextAttributeListener、ServletRequestAttributeListener、ServletRequestListener、HttpSessionAttributeListener

和 2 個 LifecycleListeners

類型的,ServletContextListener、HttpSessionListener。如下圖所示:

Listener是Servlet的監聽器,它可以監聽用戶端的請求、服務端的操作等。通過監聽器,可以自動激發一些操作,比如監聽線上的使用者的數量。當增加一個HttpSession時,就激發sessionCreated(HttpSessionEvent

se)方法,這樣就可以給線上人數加1。常用的監聽接口有以下幾個:

ServletContextAttributeListener監聽對ServletContext屬性的操作,比如增加、删除、修改屬性。

ServletContextListener監聽ServletContext。當建立ServletContext時,激發contextInitialized(ServletContextEvent

sce)方法;當銷毀ServletContext時,激發contextDestroyed(ServletContextEvent

sce)方法。

HttpSessionListener監聽HttpSession的操作。當建立一個Session時,激發session

Created(HttpSessionEvent se)方法;當銷毀一個Session時,激發sessionDestroyed

(HttpSessionEvent se)方法。

HttpSessionAttributeListener監聽HttpSession中的屬性的操作。當在Session增加一個屬性時,激發attributeAdded(HttpSessionBindingEvent

se) 方法;當在Session删除一個屬性時,激發attributeRemoved(HttpSessionBindingEvent

se)方法;當在Session屬性被重新設定時,激發attributeReplaced(HttpSessionBindingEvent se)

方法。

下面我們開發一個具體的例子,這個監聽器能夠統計線上的人數。在ServletContext初始化和銷毀時,在伺服器控制台列印對應的資訊。當ServletContext裡的屬性增加、改變、删除時,在伺服器控制台列印對應的資訊。

要獲得以上的功能,監聽器必須實作以下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;  

public class OnlineUserListener implements HttpSessionListener,  

        ServletContextListener, ServletContextAttributeListener {  

    private long onlineUserCount = 0;  

    public long getOnlineUserCount() {  

        return onlineUserCount;  

     * @see javax.servlet.ServletContextAttributeListener#attributeAdded(javax.servlet.ServletContextAttributeEvent) 

    public void attributeAdded(ServletContextAttributeEvent arg0) {  

     * @see javax.servlet.ServletContextAttributeListener#attributeRemoved(javax.servlet.ServletContextAttributeEvent) 

    public void attributeRemoved(ServletContextAttributeEvent arg0) {  

     * @see javax.servlet.ServletContextAttributeListener#attributeReplaced(javax.servlet.ServletContextAttributeEvent) 

    public void attributeReplaced(ServletContextAttributeEvent attributeEvent) {  

        System.err.println("...attributeReplaced...");  

     * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) 

    public void contextDestroyed(ServletContextEvent arg0) {  

     * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) 

    public void contextInitialized(ServletContextEvent arg0) {  

     * @see javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent) 

    public void sessionCreated(HttpSessionEvent httpSessionEvent) {  

        onlineUserCount ++;  

        toUpdateCount(httpSessionEvent);  

     * @see javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent) 

    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {  

        onlineUserCount --;  

    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>  

    線上人數:<h1><%=request.getSession().getAttribute("onlineUserCount") %></h1>  

</body>  

</html>  

原文連結:[http://wely.iteye.com/blog/2360649]