Servlet過濾器和監聽器知識總結(轉) Servlet過濾器和監聽器知識總結(轉)

Servlet過濾器和監聽器知識總結(轉)

 

 Servlet過濾器是 Servlet 程序的一種特殊用法,主要用來完成一些通用的操做,如編碼的過濾、判斷用戶的登陸狀態。過濾器使得Servlet開發者可以在客戶端請求到達 Servlet資源以前被截獲,在處理以後再發送給被請求的Servlet資源,而且還能夠截獲響應,修改以後再發送給用戶。而Servlet監聽器能夠  監聽客戶端發出的請求、服務器端的操做,經過監聽器,能夠自動激發一些操做,如監聽在線人數。
  Servlet過濾器簡介紹
      Servlet過濾器是在Java Servlet 2.3 規範中定義的,它是一種能夠插入的Web組件,它可以對Servlet 容器的接收到的客戶端請求和向客戶端發出的響應對象進行截獲,過濾器支持對Servlet程序和JSP頁面的基本請求處理功能,如日誌、性能、安全、會話  處理、XSLT轉換等。
  
      Servlet過濾器自己不產生請求和響應,它只提供過濾做用,Servlet過濾器可以在Servlet程序(JSP頁面)被調用以前檢查  request對象,修改請求頭和請求內容,在Servlet程序(JSP頁面)被調用以後,檢查response對象,修改響應頭和響應內容。
html

Servlet過濾器的特色
      1.Servlet過濾器能夠檢查和修改request和response對象。 
  
      2.Servlet過濾器能夠被指定與特定的URL關聯,只有當客戶請求訪問該特定的URL時,纔會觸發過濾器。
  
      3.Servlet過濾器能夠被串聯成串,造成過濾鏈,協同修改請求和響應。
   Servlet過濾器的做用以下:
  
      1.查詢請求並做出相應的行動。
      2.阻塞請求--響應對,使其不能進一步傳遞。
      3.修改請求頭和內容,用戶能夠提供自定義的請求。
      4.修改響應頭和內容,用戶能夠經過提供定製的響應版本實現。
      5.與外部資源進行交互。
  2 Servlet過濾器的體系結構
      Servlet過濾器用於攔截傳入的請求和傳出的響應,並監視、修改或以某種方式處理 正在經過的數據流。Servlet過濾器是自包含、模塊化的組件,能夠將它們添加到請求/響應過濾鏈中,或者在不影響應用程序中其它Web組件的狀況下刪 除它們。Servlet過濾器只在改動請求和響應的運行時處理,於是不該該將它們之間嵌入到Web應用程序框架,除非是經過Servlet API中良好定義的標準接口來實現。
  
      Web資源能夠配置成爲沒有過濾器與之關聯(默認狀況)、與單個過濾器關聯(典型狀況),甚至是與一個過濾器鏈關聯。其功能與Servlet一 樣,主要是接收請求和響應對象,而後過濾器會檢查請求對象,並決定是將該請求轉發給鏈中的下一個過濾器,仍是終止該請求並直接向客戶端發會一個響應,若是  請求被轉發了,它將被傳遞給過濾鏈中的下一個過濾器,或者Servlet程序(JSP頁面),在這個請求經過過濾器鏈並被服務器處理後,一個響應將以相反 的順序經過該過濾鏈發送回去,這樣就給每一個Servlet過濾器提供了根據須要處理響應對象的機會。
  
      當過濾器在Servlet 2.3規範中首次引入時,只能過濾客戶端和客戶端所訪問的指定Web資源之間的內容(請求/響應),若是該Web資源將請求轉發給其它Web資源時,那就  不能向幕後委託的任何請求應用過濾器。Servlet 2.4 規範消除了這個限制,Servlet過濾器如今能夠應用於J2EE Web環境中存在請求和響應的任何地方。可見,Servlet過濾器能夠應用在客戶端和Servlet程序之間、Servlet程序和Servlet程序 之間、Servlet程序和JSP頁面之間、JSP頁面和JSP頁面之間,具備強大的能力和靈活性。
  
                                                                   
  
  2.1 Servlet過濾器對請求的過濾
      Servlet過濾器對請求的過濾過程以下:
  
      1.Servlet容器建立一個Servlet過濾器實例。
      2.Servlet過濾器實例調用init()方法獲得初始化參數。
      3.Servlet過濾器實例調用doFilter()方法,根據初始化參數的值判斷該請求是否合法,若是該請求不合法,則阻塞該請求,若是是合法請求,則調用chain.doFilter(request,response)方法將該請求向後轉發。
  
  13.2.2 Servlet過濾器對響應的過濾
      Servlet過濾器對響應的過濾過程以下:
      1.過濾器截獲客戶端的請求。
      2.從新封裝ServletResponse,在封裝後的ServletResponse中提供客戶端自定義的輸出流。
      3.將請求向後轉發。
      4.Web組件產生響應。
      5.過濾器從被封裝的ServletResponse中獲取客戶自定義的輸出流。
      6.將響應內容經過客戶自定義的輸出流寫入緩衝流。
      7.在緩衝流中修改響應內容後清空緩衝流,輸出響應內容。
  
  2.3 Servlet過濾器的發佈 
      Seevlet過濾器設計完畢以後,必須對該過濾器進行發佈(配置), 發佈一個Servlet過濾器時,必須在項目的web.xml文件中加入<filter>元素和<filter- mapping>元素,<filter>元素用來定義一個過濾器,該元素的屬性有:
java

屬性web

描述sql

filter-name數據庫

指定過濾器的名字編程

filter-class數組

指定過濾器類瀏覽器

init-param安全

指定過濾器的初始化參數服務器

    <filter-mapping>元素用於將過濾器與URL關聯,其屬性有:

屬性

描述

filter-name

指定過濾器的名字

url-pattern

指定與過濾器關聯的URL

3 實現一個Servlet過濾器
  3.1 Servlet過濾器接口的構成
      全部的Servlet過濾器都必須實現javax.servlet.filter接口,該接口中定義了3個過濾器必須實現的方法:
  
      1.
void  init(FilterConfig):過濾器的初始化方法,Servlet容器在建立過濾器實例時調用這個方法,在這個方法中能夠讀出在web.xml文件中爲該過濾器配置的初始化參數。
  
      2.
voiddoFilter(ServletRequest,ServletResponse,FilterChain):用於完成實際的過濾操做,當客戶請求訪問與過濾器相關聯的URL時,Servlet容器將先調用過濾器的這個方法,FilterChain參數用於訪問後續過濾器。
  
      3.
voiddestroy():過濾器在被取消前執行這個方法,釋放過濾器申請的資源。
  
  3.2 Servlet過濾器的建立步驟
      建立一個Servlet過濾器須要下面的步驟:
      
      1.建立一個實現了javax.servlet.Filter接口的類。
  
      2.重寫init(FilterConfig)方法,讀入爲過濾器配置的初始化參數,申請過濾器須要的資源。
  
      3.重寫方法doFilter(ServletRequest,ServletResponse,FilterChain),完成過濾操做,能夠  從ServletRequest參數中獲得所有的請求信息,從ServletResponse參數中獲得所有的響應信息。
  
      4.在doFilter()方法的最後,使用FilterChain參數的doFilter()方法將請求和響應後傳。
  
      5.對響應的Servlet程序和JSP頁面註冊過濾器,在部署描述文件(web.xml)中使用<filter-apping>和<filter>元素對過濾器進行配置。
  
  3.3 編寫過濾器類
      在過濾器中,須要使用3個簡單的接口,它們是:分別是Filter、FilterChain、FilterConfig,所有包含在
javax.servlet包中。從編程的角度看,過濾器類要實現Filter接口,而後使用實現了FilterChain和FilterConfig接口的對象來工做,FilterChain對象負責將請求和響應後傳,FilterConfig對象負責爲過濾器讀初始化參數。
  
      爲了與過濾器的三步模式(建立、工做、撤消)保持一致,過濾器必須重寫Filter接口中的三個方法:
  
      
init():在容器實例化過濾器市時被調用,主要爲過濾器作初始化,該方法有一個FilterConfig類型的形參。
  
      
doFilter():這個方法用來完成真正的過濾操做,它有3個形式參數:ServletRequest參數包含請求信息,ServletResponse參數包含響應信息,FilterChain參數用來將請求和響應向後傳遞。
  
      
destroy():過濾器被撤消時調用這個方法,釋放過濾器所 佔有的資源。
  
      在下面的例子中實現了一個簡單的Servlet過濾器(SessionFilter.java),它實現的功能是判斷客戶是否成功登陸,若是成功登陸,轉向正確頁面,不然返回一個錯誤頁面,提示客戶應該進行登陸。該過濾器代碼以下:
  
      //includeList:數組,受保護的資源。
      //logonList:數組,登陸頁面。
      package ch13;
      import javax.servlet.*;
      import javax.servlet.http.*;
      import java.io.*;
      public class SessionFilter implements 
Filter{
          String  logonStrings,includeStrings,redirectPath,disabletestfilter;
          String[]  logonList,includeList;
  
          private boolean  isContains(String containers,String[] regx) {
              boolean  result=false;
              for(int  i=0;i<regx.length;i++) {
                  if  (containers.indexOf(regx[i])!=-1)
                      return  true;
              }
              return  result;
          }
  
          public FilterConfig config;
          private void  setFilterConfig(FilterConfig config) {
              this.config=config;
          }
  
          private FilterConfig  getFilterConfig(){
              return  config;
          }
  
          //必須重寫
          public void init(
FilterConfig filterConfig) throws ServletException{
              this.config=filterConfig;
              logonStrings=config.getInitParameter("logonStrings");
               includeStrings=config.getInitParameter("includeStrings");
               redirectPath=config.getInitParameter("redirectPath");
               disabletestfilter=config.getInitParameter("disabletestfilter");
              logonList=logonStrings.split(";");//分割爲數組
               includeList=includeStrings.split(";");//分割爲數組
          }
          //必須重寫
          public void  doFilter(ServletRequest request,ServletResponse response,
FilterChain 
                                      chain)  throws ServletException, IOException {
              HttpServletRequest  httpreq=(HttpServletRequest)request;
              HttpServletResponse  httpres=(HttpServletResponse)response;
              HttpServletResponseWrapper  wrapper=new HttpServletResponseWrapper(
  (HttpServletResponse)response);
              if  (disabletestfilter.toUpperCase().equals("Y")){
                  chain.doFilter(request,response);//若是不過濾
                  return;
              }
              Object  user=httpreq.getSession().getAttribute("
userinfo");
              if  (user==null){//該用戶沒有登陸
                  if  (!isContains(httpreq.getRequestURI(),includeList)){
                      chain.doFilter(request,response);
                      return;//訪問的是不受保護的頁面,能夠
                  }
                  if  (isContains(httpreq.getRequestURI(),logonList)){
                      chain.doFilter(request,response);
                      return;  //訪問的是登陸頁面,能夠
                  }
                  wrapper.sendRedirect(redirectPath);  //轉向登頁面 
              }else  {//該用戶已經登陸
                  chain.doFilter(request,response);
              }
          }
          //必須重寫
          public void destroy() {
              config=null;
          }
      }
  
      在上面的這個Servlet過濾器程序中,根據用戶session對象中有無
userinfo這個屬性來肯定該用戶是否已經登陸。
  
  3.4 配置部署過濾器
      在WEB-INF/web.xml文件中用如下代碼配置過濾器:
  
      <filter>
          <filter-name>SessionFilter</filter-name>
              <filter-class>ch13.SessionFilter</filter-class>  
          <init-param>
              <param-name>logonStrings</param-name>
              <param-value>Login.jsp</param-value>  
          </init-param> 
          <init-param>
              <param-name>includeStrings</param-name>
              <param-value>.jsp
;.html;.htm</param-value> 
          </init-param> 
          <init-param>
              <param-name>redirectPath</param-name>
              <param-value>./Login.jsp</param-value>  
          </init-param> 
          <init-param>
              <param-name>disabletestfilter</param-name>
              <param-value>n</param-value>  
          </init-param> 
      </filter> 
      <filter-mapping>
          <filter-name>SessionFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
  
      在上面的配置中,參數logonStrings指定能夠訪問的登陸頁面,參數includeStrings指定受保護的資源的後綴,參數redirectPath表示沒有登陸時轉向的登陸頁面,參數disabletestfilter表示過濾器是否有效。而 /* 表示過濾器與全部的URL都關聯(對全部的訪問請求都進行過濾)。在瀏覽器中訪問任意的資源時,都要經過這個過濾器的過濾。
  
  4 過濾器的應用案例.4.1 版權過濾器的應用案例
      在一個Web應用中的全部頁面的下面添加上版權信息,一般的作法是採用<%@ include>指令或<c:import> 標籤,使用過濾器也是一個好辦法。
  
      
1.編寫過濾器類CopyrightFilter.java
      package ch13;
      import javax.servlet.*;
      import javax.servlet.http.*;
      import java.io.*;
      public class CopyrightFilter implements 
Filter{
          private String date;
          public FilterConfig config;
          //必須重寫
          public void init(
FilterConfig filterConfig) throws ServletException{
              this.config=filterConfig;
              date=config.getInitParameter("date");
          }
          //必須重寫
          public void 
doFilter(ServletRequest request,ServletResponse response,FilterChain 
                                              chain)  throws ServletException, IOException {
              chain.doFilter(request,response);
              PrintWriter  out=response.getWriter();
              out.print("<br><center><font  size='3' color='red'>版權全部:北京工業大學
                                                              </center></font>");
              if  (date!=null) 
                  out.print("<br><center><font  color='blue'>"+date+"</center></font>");
              out.flush();
          }
          //必須重寫
          public void 
destroy() {
              config=null;
          }
      }
  
      在這個過濾器中,在doFilter()方法的最後,經過response對象獲得一個輸出流out,而後經過輸出流向客戶端輸出版權信息,這樣,每一個頁面的最後都會出現過濾器添加的版權信息。
  
      
2.修改web.xml,配置該過濾器
      <filter>
          <filter-name>CopyrightFilter</filter-name>
              <filter-class>ch13.CopyrightFilter</filter-class>  
          <init-param>
              <param-name>date</param-name>
              <param-value>2010-9</param-value>  
          </init-param> 
      </filter> 
      <filter-mapping>
          <filter-name>CopyrightFilter</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
  
      
3.測試
      在瀏覽器中任意訪問一個頁面,均可以在看到在頁面的下部出現過濾器添加的版權信息。
  
  4.2 禁止未受權的IP訪問站點過濾器的應用案例
      使用過濾器禁止未受權的IP訪問站點是過濾器常見的應用,本例演示瞭如何利用過濾器實現禁止未受權的IP訪問站點。
  
      
1.編寫過濾器類FilterIP.java
      package ch13;
      import javax.servlet.*;
      import javax.servlet.http.*;
      import java.io.*;
      public class FilterIP implements 
Filter{
          private String  filterIP,error;
          public FilterConfig config;
          //必須重寫
          public void 
init(FilterConfig filterConfig) throws  ServletException{
              this.config=filterConfig;
              filterIP=config.getInitParameter("FilterIP");
              if  (filterIP==null) filterIP="";
              error=config.getInitParameter("ERROR");
              if  (error==null) error="error.jsp";
          }
          //必須重寫
          public void 
doFilter(ServletRequest request,ServletResponse response,FilterChain 
                                              chain)  throws ServletException, IOException {
              RequestDispatcher  dispatcher=request.getRequestDispatcher("ErrorInfo.jsp");
              
String remoteIP=request.getRemoteAddr();//獲得客戶的IP地址
              if  (remoteIP.equals(filterIP)) {
                  dispatcher.forward(request,response);
                  return;
              }  else
                  chain.doFilter(request,response);
          }
          //必須重寫
          public void 
destroy() {
              config=null;
          }
      }
  
      在這個過濾器中,在doFilter()方法內,經過request對象獲得客戶端的IP地址,若是客戶端的IP是被禁止的IP,則使用request對象將請求轉發給一個出錯頁面。
  
      
2.修改web.xml,配置過濾器
  <filter>
          <filter-name>FilterIP</filter-name>
              <filter-class>ch13.FilterIP</filter-class>  
          <init-param>
              <param-name>FilterIP</param-name>
              <param-value>192.168.1.1</param-value>  
          </init-param> 
          <init-param>
              <param-name>ERROR</param-name>
              <param-value>error.jsp</param-value>  
          </init-param>
      </filter> 
      <filter-mapping>
          <filter-name>FilterIP</filter-name>
          <url-pattern>/*</url-pattern>
      </filter-mapping>
  
      對來自192.168.1.1的客戶的全部請求(/*)都進行過濾,轉移到error.jsp頁面。
  
      
3.編寫出錯頁面error.jsp
      <%@  page contentType="text/html;charset=gb2312" %>
      網站不容許IP地址爲192.168.1.1的計算機訪問。
  
      在IP地址爲  192.168.1.1 的計算機上訪問網站的任何一個資源,都會轉移到error.jsp頁面。

  
  4.3 過濾頁面內容(響應內容)
      本過濾器使用HttpServletResponseWrapper類  來實現頁面內容的過濾,它的原理是讓Web資源先將頁面內容(響應內容)寫入到HttpServletResponseWrapper對象中,而後再在過  濾器中處理HttpServletResponseWrapper對象中的頁面內容(響應內容),最後再將處理好的頁面內容(響應內容)發送給客戶。
  
      
1.編寫HttpServletResponseWrapper類的子類.java
      package ch13;
      import java.io.ByteArrayOutputStream; 
      import java.io.OutputStreamWriter; 
      import java.io.IOException; 
      import java.io.PrintWriter; 
      import java.io.UnsupportedEncodingException; 
      import javax.servlet.http.HttpServletResponse; 
      import javax.servlet.http.HttpServletResponseWrapper;
      import javax.servlet.ServletOutputStream;
      public class 
WrapperResponse extends  HttpServletResponseWrapper { 
          public static final int  OT_NONE = 0, OT_WRITER = 1, OT_STREAM = 2; 
          private int outputType =  OT_NONE; 
          private ServletOutputStream  output = null; 
          private PrintWriter writer =  null; 
          private ByteArrayOutputStream  buffer = null; 
  
          //構造函數 
          public  WrapperResponse(HttpServletResponse resp) throws IOException { 
              super(resp);  
              buffer  = new ByteArrayOutputStream(); 
          } 
  
          //獲得字符輸出流
          public PrintWriter 
getWriter() throws IOException { 
              if  (outputType == OT_STREAM) 
                  throw  new IllegalStateException(); //已經用了OutputStream流
              else  if (outputType == OT_WRITER) 
                  return  writer; 
              else  { 
                  outputType  = OT_WRITER; 
                  writer  = new PrintWriter(new  OutputStreamWriter(buffer, getCharacterEncoding())); 
                  return  writer; 
              } 
          }
  
          //獲得字節輸出流
          public ServletOutputStream 
getOutputStream() throws IOException { 
              if  (outputType == OT_WRITER) 
                  throw  new IllegalStateException(); //已經用了Writer流
              else  if (outputType == OT_STREAM) 
                  return  output; 
              else  { 
                  outputType  = OT_STREAM; 
                  output  = new 
WrappedOutputStream(buffer); 
                  return  output; 
              } 
          } 
  
          //刷新輸出內容
          public void 
flushBuffer() throws IOException { 
              if  (outputType == OT_WRITER) 
                  writer.flush();  
              if  (outputType == OT_STREAM) 
                  output.flush();  
          } 
  
          //輸出緩衝區復位
          public void 
reset() { 
              outputType  = OT_NONE; 
              buffer.reset();  
          } 
          public String  getResponseData() throws IOException { 
              flushBuffer();  
              return  new String(buffer.toByteArray()); 
          } 
  
          //內部類,將數據寫入本身的定義的緩衝區
          class 
WrappedOutputStream extends ServletOutputStream { 
                  private  ByteArrayOutputStream buffer; 
                  public  WrappedOutputStream(ByteArrayOutputStream buffer) { 
                      this.buffer  = buffer; 
                  }  
                  public  void write(int b) throws IOException { 
                      buffer.write(b);  
                  }  
                  public  byte[] toByteArray() { 
                      return  buffer.toByteArray(); 
                  }  
          } 
      } 
  
      在這個類中,必定要重寫response對象的關於輸出流(outputStream、writer)操做的方法:getOutputStream()、getWriter()、flushBuffer()、reset()。
  
      
2.編寫過濾器GavinFilter.java
      package ch13;
      import java.io.IOException; 
      import javax.servlet.*; 
      import javax.servlet.http.HttpServletRequest; 
      import javax.servlet.http.HttpServletResponse; 
      public class 
GavinFilter implements Filter { 
          private String  oldword="%" , newword="百分號"; 
          public void destroy(){}
          public void  doFilter(ServletRequest request, ServletResponse response, 
FilterChain
                                                  chain)  throws IOException, ServletException { 
              HttpServletResponse  oldresponse = (HttpServletResponse)response; 
              WrapperResponse  
wrapperResponse = new WrapperResponse(oldresponse); 
              chain.doFilter(request,  
wrapperResponse); //讓服務器將響應內容寫到Wrapper中
              String  html = wrapperResponse.getResponseData(); //取出響應內容
              oldresponse.getWriter().print(html.replaceAll(oldword,  newword)); //替換頁面中的文字,而後發送給客戶
          } 
          public void init(
FilterConfig config) throws ServletException {
              oldword=config.getInitParameter("oldword");
              newword=config.getInitParameter("newword");
          } 
      }
  
      該過濾器將頁面內容(響應內容)中的字符 
% 替換爲百分號三個漢字,因而可知,實現了對響應內容的過濾。 
  
      
3.對該過濾器的配置
      <filter> 
          <filter-name>gavinFilter</filter-name>  
          <filter-class>ch13.GavinFilter</filter-class>  
          <init-param> 
              <param-name>oldword</param-name>  
              <param-value>
%</param-value> 
          </init-param> 
          <init-param> 
              <param-name>newword</param-name>  
              <param-value>
百分號</param-value> 
          </init-param> 
      </filter>
      <filter-mapping> 
          <filter-name>gavinFilter</filter-name>  
          <url-pattern>/*</url-pattern>  
      </filter-mapping> 
  
  5 Servlet監聽器
      Servlet監聽器也叫作 listener,經過它能夠監聽Web應用的上下文(環境)信息、Servlet請求信息、Servlet會話信息,並自動根據不一樣狀況,在後臺調用相  應的處理程序。經過監聽器,能夠自動激發一些操做,好比監聽在線人數,當增長一個HttpSession時就激發 sessionCreated(HttpSessionEvent)方法,這樣就能夠給在線人數加1。
  
  13.5.1 監聽器的原理
      Servlet監聽器是Web應用開發的一個重要組成部  分,Servlet監聽器是在Servlet2.3規範中和Servlet過濾器一塊兒引入的。在 Servlet2.4 規範中對其進行了比較大的改進。主要就是用來對Web應用進行監督和控制,極大地加強了Web應用的事件處理能力。
  
      Servlet監聽器的功能比較相似於Java中的GUI程序的監聽器,能夠監聽因爲Web應用中的狀態改變而引發的Servlet容器產生的相應事件,而後接收並處理這些事件。
  
  5.2 監聽器的類型
      在 Servlet 2.4 規範中,根據監聽對象的類型和範圍,將監聽器分爲3類:
ServletRequest監聽器(請求監聽器)、HttpSession監聽器(會話監聽器)、ServletContext監聽器(上下文監聽器),其中請求監聽器(ServletRequest監聽器)是  Servlet 2.4 規範中新增長的監聽器,能夠用來監聽客戶的端請求,在Servlet 2.4 規範中包含了8個監聽器接口和6個監聽器事件類,具體的監聽器接口和事件以下表:

監聽對象

監聽接口

監聽事件

ServletRequest

ServletRequestListener    (2個方法)

ServletRequestEvent

ServletRequestAttributeListener    (3個方法)

ServletRequestAttributeEvent

HttpSession

HttpSessionListener    (2個方法)

HttpSessionEvent

HttpSessionActivationListener    (2個方法)

HttpSessionAttributeListener    (3個方法)

HttpSessionBindingEvent

HttpSessionBindingListener    (2個方法)

ServletContext

ServletContextListener    (2個方法)

ServletContextEvent

ServletContextAttributeListener    (3個方法)

ServletContextAttributeEvent

    1.被監聽對象ServletContext
      對ServletContext對象(JSP頁面中稱爲application對象)實現監聽涉及2個接口:
  
      (1)
ServletContextListener接口:用於監聽ServletContext對象的建立和刪除:接口中定義的回調方法有:
  
          當建立一個ServletContext對象時,激發  
contextInitialzed(ServletContextEvent)方法。
          當撤消一個ServletContext對象時,激發  
contextDestroyed(ServletContextEvent)方法。
  
      (2)
ServletContextAttributeListener接口:用於監聽ServletContext對象的屬性操做。接口中定義的回調方法有:
  
          增長屬性時,激發 
attributeAdded(ServletContextAttributeEvent)
          刪除屬性時,激發 attributeRemoved(ServletContextAttributeEvent) 
          修改屬性時,激發 
attributeReplaced(ServletContextAttributeEvent) 
  
      
2.被監聽對象HttpSession
      對HttpSession對象(session)實現監聽涉及4個接口:
  
      (1)
HttpSessionListener接口:這個接口監聽Http會話的建立和撤消,並在某個session對象創建和銷燬以前調用某個方法。接口中定義的回調方法有:
  
          建立一個session對象時,激發  
sessionCreated(HttpSessionEvent)
          刪除一個session對象時,激發 sessionDestroyed(HttpSessionEvent)
  
      (2)
HttpSessionActivationListener接口:監聽Http會話的active和passivate狀態。接口中定義的回調方法有:
  
          session對象被保存到磁盤時,激發 
sessionWillPassivate(HttpSessionEvent)
          session對象被調入內存時,激發 sessionDidActivate(HttpSessionEvent)
  
      Activate與Passivate是用於置換session對象的動做,當Web服務器由於資源利用或負載平衡等緣由要將內存中的 session對象暫時儲存至硬盤或其它儲存器時(經過對象序列化),所做的動做稱之爲Passivate,而硬盤或儲存器上的session對象從新加 載到JVM中時所採的動做稱之爲Activate。sessionDidActivate()方法與 sessionWillPassivate()方法分別於Activeate後與Passivate前被調用。 
  
      (3)
HttpSessionAttributeListener接口:監聽Http會話中屬性的設置信息。接口中定義的回調方法有:
  
          向某個session對象中增長新屬性時,激發  
attributeAdded(HttpSessionBindingEvent)
          刪除某個session對象中的屬性時,激發 attributeRemoved(HttpSessionBindingEvent)
          修改某個session對象中的屬性時,激發 attributeReplaced(HttpSessionBindingEvent)
  
      使用HttpSessionBindingEvent事件類對象的getSession()方法能夠獲得這個session對象,使用 HttpSessionBindingEvent對象的getName()方法獲得屬性的名字,使用getValue()方法獲得屬性的值。
  
      如有屬性加入到某個會話(HttpSession)對象,則會調用attributeAdded(),同理在替換屬性與移除屬性時,會分別調用attributeReplaced()、attributeRemoved()。

    (4)HttpSessionBindingListener接口:這是惟一一個不須要在web.xml中進行配置的監聽器接口,監聽Http會話中屬性的變化狀況。接口中定義的回調方法有:
  
          屬性被加入到session中時,激發屬性的 
valueBound(HttpSessionBindingEvent)
          屬性被從session中刪除時,激發屬性的 valueUnbound(HttpSessionBindingEvent)
  
      使用HttpSessionBindingEvent事件類對象的getSession()方法能夠獲得這個session對象,使用 HttpSessionBindingEvent對象的getName()方法獲得屬性的名字,使用getValue()方法獲得屬性的值。
  
      若是一個對象object實現了HttpSessionBindingListener接口時,當把object對象保存到session中時, 就會自動調用object對象的valueBound()方法,若是對象object被從session(HttpSession)移除時,則會調用 object對象的valueUnbound()方法。使用這個接口,可讓一個對象本身知道它本身是被保存到了session中,仍是從session 中被刪除了。     
      
      
3.被監聽對象ServletRequest
      對ServletRequest對象(request)實現監聽涉及2個接口:
  
      (1)
ServletRequestListener接口:監聽請求的建立和撤消,該接口用來監聽請求到達和結束,所以能夠在請求達到前和請求結束前執行一些用戶行爲。  接口中定義的回調方法有: 
  
      請求對象初始化時,激發 
requestInitialized(ServletRequestEvent)
      請求對象被撤消時,激發  requestDestroyed(ServletRequestEvent)
  
      在request(HttpServletRequest)對象創建或被消滅時,會分別調用requestInitialized()和requestDestroyed()方法。
  
      (2)
ServletRequestAttributeListener接口:監聽請求中(request對象中)的屬性變化。接口中定義的回調方法有:
  
      向某個request對象中增長屬性時被調用attributeAdded(ServletRequestAttributeEvent)方法。
      從某個request對象中刪除屬性時被調用attributeRemoved(ServletRequestAttributeEvent)方法。
      修改某個request中的屬性時被調用attributeReplaced(ServletRequestAttributeEvent)方法。
  
      使用ServletRequestEvent類的getServletRequest()方法能夠獲得這個被監聽的請求對象,使用  ServletRequestAttributeEvent類的getName()方法能夠獲得屬性名,getValue()方法能夠獲得屬性的值。
  
      如有屬性加入到某個request對象中時則會調用attributeAdded(),同理在替換屬性與刪除屬性時,會分別調用attributeReplaced()、 attributeRemoved()。 
  
      當Web應用程序啓動後,在處理任何請求以前,調用contextInitialzed()方法和getInitParamter()方法,返回  在配置文件中爲定義的環境初始化信息。不一樣的組件,如Servlet、JSP、監聽器和過濾器等,經過ServletRequest、 HttpSession 和 ServletContext達到數據共享,這些類都提供了下面的一組方法,可使用這組方法來設置、獲取、刪除屬性:
  
          public void  setAttribute("屬性名",屬性值);
          public Object  getAttribute("屬性名");
          public void  removeAttribute("屬性名");
       
  5.3 監聽器管理共享數據庫鏈接
      在web.xml中,使用<listener>來配置監聽器,語法是:
  
          <listener>
              <listener-class>包名.類名</listener-class>
          </listener>
  
      好比:建立一個ServletContext對象監聽器,在一個Web項目一啓動就建立一個與數據庫的鏈接,保存在application對象中,這個鏈接一直保存到Web項目關閉時爲止。程序代碼以下:
  
      package ch13;
      import javax.servlet.ServletContextEvent;
      import javax.servlet.ServletContextListener;
      import java.sql.*;
      //import ch7.db.*; 
      public final class MyConnectionManager implements 
ServletContextListener {
          Connection con=null;
          public void  contextInitialized(ServletContextEvent e) {//重寫接口定義的方法,項目啓動是調用該方法
              
ConnectDB db=new ConnectDB();
              con=db.getConnection();  //使用對象db建立數據庫鏈接
              e.getServletContext().setAttribute("con",con);//與數據庫的鏈接保存入application對象中
          }
          public void contextDestroyed(ServletContextEvent  e) {//重寫接口定義的方法,項目關閉時調用該方法
              try {
                  con.close();
              }
              catch(Exception  e1){}
          }
      }
  
      在web.xml文件對這個ServletContext類型的監聽器進行配置:
  
          <listener>
              <listener-class>
ch13.MyConnectionManager</listener-class>
          </listener> 
  
      這個監聽器能保證每新建立一個ServletContext對象時(一個Web項目只有一個 ServletContext對象),該Web項目都會有一個可使用的數據庫鏈接,而且這個數據庫鏈接會在該ServletContext對象關閉(結 束)的時候隨之關閉。
  
      測試頁面testcon.jsp:
      <%@ page contentType="text/html" pageEncoding="GB18030"%>
      <br><%= "獲得的數據庫鏈接:"+application.getAttribute("con") %>
      <br><h1>請注意安裝數據庫的驅動程序</h1>
  
  
  5.4 監聽器的應用案例
      下面是一個在線用戶數量監聽器,這個監聽器能夠實時統計在線人數,在 ServletContext初始化和撤消時,在服務器控制檯打印出對應信息,當ServletContext對象裏的屬性增長、修改、刪除時,在服務器  控制檯打印相應的信息。要完成上面的監聽功能,須要使用3個接口:
  
      HttpSessionListener:監督HttpSession對象的建立和撤消,統計人數。
      ServletContextListener:監督ServletContext對象的建立和撤消。
      ServletContextAttributeListener:監督ServletContext的屬性變化。
  
      
1.監聽器程序代碼OnLineCountListener.java
      package ch13;
      import javax.servlet.*;
      import javax.servlet.http.*;
      public final class 
OnLineCountListener implements  HttpSessionListener,
                                  ServletContextAttributeListener,  ServletContextListener {
          private int count;
          private ServletContext  context=null;
  
          //構造函數 
          public OnLineCountListener()  {
              count=0;//人數
          }
  
          //重寫HttpSessionListener接口中的2個方法,完成對session對象建立和撤消的監視
          public void  sessionCreated(HttpSessionEvent se) {//建立了一個session對象
              count++;//人數加1
              setContext(se);
          }
          public void  sessionDestroyed(HttpSessionEvent se){//撤消了一個session對象
              count--;//人數減1
              setContext(se);
          }
  
          private void  setContext(HttpSessionEvent se){
              se.getSession().getServletContext().setAttribute("onLine",new  Integer(count));
          }
  
          //重寫ServletContextAttributeListener接口中的3個方法
          public void  attributeAdded(ServletContextAttributeEvent event) {//添加了屬性
              log("attributeAdded("+event.getName()+","+event.getValue()+")");
          }
          public void  attributeRemoved(ServletContextAttributeEvent event) {//刪除了屬性
              log("attributeRemove("+event.getName()+","+event.getValue()+")");
          }
          public void attributeReplaced(ServletContextAttributeEvent  event) {//替換了原有的屬性
              log("attributeReplaced("+event.getName()+","+event.getValue()+")");
          }
  
          //重寫ServletContextListener接口中的2個方法
          public void  contextDestroyed(ServletContextEvent event) {//Web項目關閉
              log("contextDestroyed()");
              context=null;
          }
          public void  contextInitialized(ServletContextEvent event) {//Web項目啓動
              this.context=event.getServletContext();
              log("contextInitialized()");
          }
  
          //顯示信息
          private void log(String  message){
              System.out.println("ContextListener:"+message);
          }
      }
  
      在OnLineCountListener類中,用count保存目前在線人數,每增長一個session對象,人數加1,每撤消一個session對象,人數減1。人數保存在ServletContext對象中,使得任何頁面均可以使用。
  
      
2.在web.xml文件中配置監聽器
  
          <listener>
              <listener-class>
ch13.OnLineCountListener</listener-class>
          </listener> 
  
      
3.編寫測試頁面(2個)
                              listener.jsp------>exit.jsp
  
                              listener.jsp頁面內容 
      <%@ page  contentType="text/html;charset=gb2312" %>
      目前在線人數:<font  color="red"><%=application.getAttribute("onLine")%></font><br>
      退出會話:
      <form action="exit.jsp"  method="post">
      <input type="submit"  value="exit">
      </form> 
  
                              exit.jsp頁面內容
      <%@ page  contentType="text/html;charset=gb2312" %>
      你已經退出會話<%  session.invalidate(); %> 
  
      能夠單獨啓動5個瀏覽器窗口,每一個窗口表明一個客戶,所以在線人數是5。 
  
  5.5 HttpSessionBindingListener 接口的使用
      設計一個學生對象Student,當將該學生對象存入 session中時,他的年齡增長10歲,當將這個學生對象從session中刪除時,他的年齡減小5歲。
  
      學生類Student.java
      package ch13;
      import javax.servlet.*;
      import javax.servlet.http.*;
      public class 
Student implements  HttpSessionBindingListener {          private int age=30;          public void valueBound(HttpSessionBindingEvent  arg0) {//存入session時自動調用              age+=10;          }          public void  valueUnbound(HttpSessionBindingEvent arg0) {//從session中刪除時自動調用              age-=5;          }          public int getAge() {return  age;}      }         測試頁面bind.jsp      <%@ page  contentType="text/html;charset=gb2312"  import="ch13.Student"%>      <%          Student student=new  Student();          out.println("學生年齡:"+student.getAge()+"<br>");           session.setAttribute("st",student);          out.println("存入session後,該學生年齡:"+student.getAge()+"<br>");          session.removeAttribute("st");            out.println("從session刪除,該學生年齡:"+student.getAge()+"<br>");        %> 

相關文章
相關標籤/搜索