2010年7月20日 星期二

JSP & Servlet Listener 簡介

偵聽器(Listener)的設置能讓我們在 Web Application 有任何事件被觸發時,得以進行處理
本篇筆記提供一個利用Lsitener做到資源共享的範例
並使用DD來避免將參數寫死在程式中
藉此說明偵聽器的使用方法

DD的用途在筆記(1)寫過不只拿來描述Servlet的配置
首先就來個程式範例:
web.xml================

..............
<servlet>
    <servlet-name>demo</servlet-name>
    <servlet-class>tw.vencs.demo</servlet-class>

    <init-param>
      <param-name>test</param-name>
      <param-value>testString</param-value>
    </init-param>
</servlet>
..............


 demo.java===============

..........
    PrintWriter out = response.getWriter();
    out.println(getServletConfig().getInitParameter("testString"));
.......

demo.java正是這一次測試的Servlet檔案
每個Servlet都會繼承到getServletConfig(),可以利用它來獲得String類別的初始參數
然而呼叫的時機尚須注意,不能在建構式中使用這個method
container從DD取得該Servlet的初始參數,並將參數交給屬於該Servlet的ServletConfig物件
直到執行Servlet的 init() 時才把ServletConfig物件傳給這個Servlet
init(ServletConfig) 會呼叫 init() ,需要改寫時覆寫 init()即可

初始參數只會在 container 初始化Servlet的時候會被讀取
修改完後必須重新啟動Tomcat才能變更
所以如果需要使用經常變動的參數還是使用資料庫或是從檔案讀取的方式較為合宜
初始參數也沒有辦法像一般參數那樣使用 setAttribute() 改變值
因為初始參數本身的設置目的就是提供預設性質的參數以供使用

一個 Servlet會有一個ServletConfig物件,其初始參數也僅能供自身使用
接下來談到的是用Context來創造整個 Web Application 都能利用的初始參數
好處是整個應用程式裡的Servlet和JSP都可以使用
JSP能夠存取的原因是因為JSP最後也會被轉譯成Servlet 
因此也不需要在DD為每個Servlet作一樣的設定
範例:
web.xml================

..............
<servlet>............</servlet>

  <context-param>
    <param-name>email</param-name>
    <param-value>a@gmail.com</param-value>
  </context-param>
  
..............

context-param須放置於<web-app>宣告內,但不能放置於Servlet宣告內
呼叫時使用 getServletContext().getInitParameter("email")
呼叫變數的方法兩者都是getInitParameter()
ServletContext在整個Web Application裡只會有一個
當然前提是這支程式只在單一個JVM執行
如果是分散式系統還需要可量如果每個JVM裡的ServletContext不同所造成的後果

Servlet的ServletConfig 物件有指向ServletContext的參考
所以也可以寫出 getServletConfig().getServletContext().getInitParameter()來取得
這個寫法也等同於 this.getServletContext().getInitParameter()
當然這種寫法很少見的理由是,唯一需要透過ServletConfig取得ServletContext的情況很少見
只有在Servlet並非繼承HttpServlet時才必須這樣寫,所以幾乎沒有必要這樣寫就是了

注意一下,上面提到的初始參數都是String的名值配對
假使需要的是物件、又或許是資料庫連結的作法會有稍許不同
接下來我們會用到偵聽器(Listener)來偵聽Context初始化事件
並在程式開始進行服務前,取得Context參數來執行一些程式碼
程式範例:
demoListener.java======
package tw.vencs;

import javax.servlet.*;

public class demoListener implements ServletContextListener {

    public void contextInitialized(ServletContextEvent event) {
        ServletContext sc = event.getServletContext();
        String doBreed = sc.getInitParameter("kind");
        dog newDog = new dog(doBreed);
        sc.setAttribute("dog", newDog);
    }

    public void contextDestroyed(ServletContextEvent event) {
        //Context結束時,表示整個應用程式都結束
    }
}

web.xml==============

............
  <context-param>
    <param-name>kind</param-name>
    <param-value>yuki</param-value>
  </context-param>

  <listener>
    <listener-class>tw.vencs.demoListener</listener-class>
  </listener>
..........

dog只是普通的測試用類別,就不描述了
Listener只是個單獨運作的Java應用程式,功用就只是初始化類別物件
實作時需要實作 ServletContextListener 介面
contextInitialized() 當然就是在context 建立時被呼叫的method
在開始和結束時都會傳入ServletContextEvent
demoListener只是簡單的從Context裡獲得Context初始參數
並以它建立物件後,使用 setAttribute() 將物件以屬性 "dog" 的方式儲存在Context裡
寫完Listener後,接著在DD裡設定  <listener>
部署方式與<context-param>相同

之後只要用Context取得屬性即可取得物件
如下程式碼:
dog Dog = (dog)getServletContext().getAttribute("dog");

從 getAttribute() 取得的物件會是 Object 類別,所以取出後要記得轉型

這次的偵聽器類別使用的是ServletContextListener,偵聽器總計有 8 種
整理如下:
1.ServletContextAttributeListener
功能:偵聽Context裡的屬性是否有被新增、移除、取代
事件類別:ServletContextAttributeEvent

2.HttpSessionListener
功能:檢查正在活動的 session,可以藉此得知有多少人在線上
事件類別:HttpSessionEvent

3.ServletRequestListener
功能:當有請求進來時都會發出通知事件
事件類別:ServletRequestEvent

4.ServletRequestAttributeListener
功能:偵聽Request裡的屬性是否有被新增、移除、取代
事件類別:ServletRequestAttributeEvent

5.HttpSessionBindingListener
功能:偵聽屬性類別與 session 之間的聯繫關係(被新增或移除至session)
事件類別:HttpSessionBindingEvent

6.HttpSessionAttributeListener
功能:偵聽 session 裡的屬性是否有被新增、移除、取代
事件類別:HttpSessionBindingEvent

7.ServletContextListener
功能:偵聽Context是否被建立或銷毀
事件類別:ServletContextEvent

8.HttpSessionActivationListener
功能:以物件角度偵聽所聯繫的 session 被移到另外一個JVM,或者是移過來時發出通知
事件類別:HttpSessionEvent

HttpSessionBindingListener 與 HttpSessionAttributeListener 的不同點在被偵聽的對象不同
前者是偵聽屬性物件"被"聯繫到 session 裡,後者則是偵聽 session 的狀態
前者可以做到的事,舉例來說:購物車
連接了顧客的session,當顧客購買後,以被連結的物件來對資料庫作更新

HttpSessionAttributeListe 和 HttpSessionActivationListene不需要在DD裡組態
其應用方式會在session篇筆記說明

沒有留言:

張貼留言