監聽器(Listener)
**理解:**監聽器就是對項目起到監聽的作用,它能感知到包括request(請求域),session(會話域)和applicaiton(應用程序)的初始化和屬性的變化;
web監聽器是Servlet中一種特殊的類,能監聽web中的特定時間,比如ServletContext,HttpSession,ServletRequest的創建和銷燬;變量的創建、銷燬和修改等。可以在某些動作前後增加處理,實現監控。
監聽器就是一個實現特定接口的普通Java程序,這個程序專門用於監聽一個Java對象的方法調用或屬性改變,當被監聽對象發生上述事件後,監聽器某個方法將立即被執行。
1、 監聽器接口和註冊
監聽器接口主要在 javax.servlet 和 javax.servlet.http 的包中。對應上文的三類,有以下這些接口:
第一類:
名稱 | 作用 |
---|---|
javax.servlet.ServletContextListener | 它能響應Servlet生命週期事件,它提供了ServletContext創建之後和ServletContext關閉之前的會被調用的方法。 |
javax.servlet.http.HttpSessionListener | 它能響應HttpSession的創建、超時和失效事件。 |
javax.servlet.http.HttpActivationListener | 它在一個HttpSession激活或者失效時被調用。 |
javax.servlet.ServletRequestListener | 它能響應一個ServletRequest的創建或刪除。 |
第二類:
名稱 | 作用 |
---|---|
javax.servlet.ServletContextAttributeListener | 它能響應ServletContext範圍內的屬性添加、刪除、替換事件。 |
javax.servlet.http.HttpSessionAttributeListener | 它能響應HttpSession範圍內的屬性添加、刪除、替換事件。 |
javax.servlet.http.HttpSessionBindingListener | 可以實現這個接口來保存HttpSession範圍的屬性。當有屬性從HttpSession添加或者刪除時,它能做出響應。 |
javax.servlet.ServletRequestListener | 它能響應ServletRequest範圍的屬性添加、刪除、修改事件。 |
2、Listener部署
編寫一個監聽器,只需要寫一個Java類來實現對應的監聽器接口就可以了。在Servlet 3.0和Servlet 3.1中提供了兩種註冊監聽器的方法。一種是使用WebListener註解。例如:
@WebListener
public class ListenerClass implements ListenerInterface {
}
第二種是在部署描述文檔中增加一個listener元素。
<listener>
<listener-class>fully-qualified listener class</listener-class>
</listener>
3、listener實際應用
- 統計在線人數,利用HttpSessionLisener
- 加載初始化信息:利用ServletContextListener
- 統計網站訪問量、實現訪問監控等
獲取當前在線人數
package com.mycompany.mvc.listener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class myHttpSessionListener implements HttpSessionListener{
public static int peopleOnLine = 0;
@Override
public void sessionCreated(HttpSessionEvent hse) {
System.out.println("myHttpSessionListener.sessionCreated():"+hse);
peopleOnLine++;
hse.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
@Override
public void sessionDestroyed(HttpSessionEvent hse) {
System.out.println("myHttpSessionListener.sessionDestroyed():"+hse);
peopleOnLine--;
hse.getSession().setAttribute("peopleOnLine",peopleOnLine);
}
}
<%=session.getAttribute("peopleOnLine")%>
過濾器(Filters)
過濾器是Servlet的高級特性之一,也別把它想得那麼高深,只不過是實現Filter接口的Java類罷了!
當瀏覽器發送請求給服務器的時候,先執行過濾器,然後才訪問Web的資源。服務器響應Response,從Web資源抵達瀏覽器之前,也會途徑過濾器。。
過濾器可以比喻成一張濾網。我們想想現實中的濾網可以做什麼:在泡茶的時候,過濾掉茶葉。那濾網是怎麼過濾茶葉的呢?規定大小的網孔,只要網孔比茶葉小,就可以實現過濾了!
引申在Web容器中,過濾器可以做:過濾一些敏感的字符串【規定不能出現敏感字符串】、避免中文亂碼【規定Web資源都使用UTF-8編碼】、權限驗證【規定只有帶Session或Cookie的瀏覽器,才能訪問web資源】等等等,過濾器的作用非常大,只要發揮想象就可以有意想不到的效果
過濾器其實也是責任鏈模式的一種實現,FilterChain層層往下執行,直到最後沒有過濾器,就到了「目標資源」
**理解:**就是對請求起到過濾的作用,它在監聽器之後,作用在servlet之前,對請求進行過濾;
1、Filter API
Filter的實現必須繼承 javax.servlet.Filter 接口。這個接口包含了 Filter 的三個生命週期:init,doFilter,destroy。
Servlet容器初始化 Filter 時,會觸發 Filter 的 init 方法,一般在應用開始時,而不是在相關資源使用時才初始化,這個方法只調用一次。init 定義如下:
void init(FilterConfig filterConfig)
當Servlet 容器每次處理Filter相關資源時,都會調用該Filter實例的doFilter方法。doFilter包含三個參數,定義如下:
void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
在doFilter中可以訪問ServletRequest、ServletResponse。
在Filter的doFilter的實現中,最後一行需要調用FilterChain 中的 doFilter 方法。注意Filter的doFilter方法裏的第三個參數,就是filterChain的實例:
filterChain.doFilter(request, response)
2、Filter部署
第一種方式:在web.xml文件中配置
<filter>
//用於爲過濾器指定一個名字,該元素的內容不能爲空。
<filter-name>FilterDemo1</filter-name>
//元素用於指定過濾器的完整的限定類名。
<filter-class>FilterDemo1</filter-class>
</filter>
//<filter-mapping>元素用於設置一個Filter 所負責攔截的資源
<filter-mapping>
//用於設置filter的註冊名稱。該值必須是在元素中聲明過的過濾器的名字
<filter-name>FilterDemo1</filter-name>
//設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式)
<url-pattern>/*</url-pattern>
</filter-mapping>
第二種方式:通過註解配置
@WebFilter(urlPatterns = {"*.jsp","*.do"})
2.1 Filter的配置詳解
- 具體的資源路徑
/index.jsp
只有訪問index.jsp的時候,過濾器纔會被執行
- 攔截目錄
/user/*
訪問/user目錄下的所有資源的時候,過濾器纔會被執行
- 後綴名攔截
*.jsp
訪問所有jsp頁面都會被攔截
- 攔截所有資源
/*
3、Filter實際應用
一般用於完成通用的操作。如:登錄驗證、統一編碼處理、敏感字符過濾……
編碼過濾器(解決亂碼的問題)
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("-----filterEncoding dofillter----");
//將request和response強轉成http協議的
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
// 放行,轉到下一個過濾器
filterChain.doFilter(request, response);
}