監聽器Listener
- web監聽器是Servlet中一種特殊的類,能監聽web中的特定時間,比如ServletContext,HttpSession,ServletRequest的創建和銷燬;變量的創建、銷燬和修改等。可以在某些動作前後增加處理,實現監控。
- 監聽事件自身的創建和銷燬
- ServletContext監控:對應監控application內置對象的創建和銷燬。當web容器開啓時,執行contextInitialized方法;當容器關閉或重啓時,執行contextDestroyed方法。
實現方式:直接實現ServletContextListener接口
- HttpSession監控:對應監控session內置對象的創建和銷燬。當打開一個新的頁面時,開啓一個session會話,執行sessionCreated方法;當頁面關閉session過期時,或者容器關閉銷燬時,執行sessionDestroyed方法。
實現方式:直接實現HttpSessionListener接口
- ServletRequest監控:對應監控request內置對象的創建和銷燬。當訪問某個頁面時,出發一個request請求,執行requestInitialized方法;當頁面關閉時,執行requestDestroyed方法。
實現方式,直接實現ServletRequestListener接口
- 監聽對象屬性的新增、刪除和修改
- 實現ServletContextAttributeListener接口:通過調用ServletContextAttribtueEvent的getName方法可以得到屬性的名稱。
- 實現HttpSessionAttributeListener接口
- 實現ServletRequestAttributeListener接口
- 監聽對象的狀態
- 針對某些POJO類,可以通過實現HttpSessionBindingListener接口,監聽POJO類對象的事件。
HttpSessionBindingListener雖然叫做監聽器,但使用方法與HttpSessionListener完全不同。我們實際看一下它是如何使用的。
新建類OnlineUserBindingListener,實現HttpSessionBindingListener接口,HttpSessionBindingListener內有兩個方法valueBound(HttpSessionBindingEvent event)和valueUnbound(HttpSessionBindingEvent event),前者爲數據綁定,後者爲取消綁定
所謂對session進行數據綁定,就是調用session.setAttribute()把HttpSessionBindingListener保存進session中。
HttpSessionListener只需要設置到web.xml中就可以監聽整個應用中的所有session。HttpSessionBindingListener必須實例化後放入某一個session中,纔可以進行監聽
- 監聽Session數據的鈍化與活化
- 由於session中保存大量訪問網站相關的重要信息,因此過多的session數據就會服務器性能的下降,佔用過多的內存。因此類似數據庫對象的持久化,web容器也會把不常使用的session數據持久化到本地文件或者數據中。這些都是有web容器自己完成,不需要用戶設定。
不用的session數據序列化到本地文件中的過程,就是鈍化;
當再次訪問需要到該session的內容時,就會讀取本地文件,再次放入內存中,這個過程就是活化。
類似的,只要實現HttpSeesionActivationListener接口就是實現鈍化與活化事件的監聽
- 代碼實現
- 自定義監聽器類
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class MyServletContextListener implements ServletContextListener{
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println(sce.getServletContext().getContextPath() + " " + "ServletContext對象創建");
sce.getServletContext().setAttribute("path", sce.getServletContext().getContextPath());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext對象銷燬");
}
}
- web.xml配置
<!-- 自定義servletContext監聽器 -->
<listener>
<listener-class>zjq.listener.MyServletContextListener</listener-class>
</listener>
參考文章1 參考文章2
過濾器Filter
- 過濾器是一個服務器端的組件,它可以攔截客戶端的請求和響應信息,並對這些信息進行過濾。
Servlet API中提供了一個Filter接口,如果編寫類實現了這個接口,則稱這個類爲過濾器。
- 定義一個Filter類,需要繼承javax.servlet.Filter類,重寫其init、doFilter、destroy方法。init()方法會在Filter初始化後進行調用,在init()方法裏面我們可以通過FilterConfig訪問到初始化參數( getInitParameter()或getInitParameters() )、ServletContext (getServletContext)和當前Filter部署的名稱( getFilterName() )等信息。destroy()方法將在Filter被銷燬之前調用。而doFilter()方法則是真正進行過濾處理的方法,在doFilter()方法內部,我們可以過濾請求的request和返回的response,同時我們還可以利用FilterChain把當前的request和response傳遞給下一個過濾器或Servlet進行處理。
- 代碼實現
- 自定義過濾器類
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;
public class FirstFilter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//做相應操作
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
- web.xml
<!-- 自定義過濾器1 -->
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>zjq.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
參考文章1 參考文章2
攔截器Interceptor
- SpringMVC 中的Interceptor 攔截器也是相當重要和相當有用的,它的主要作用是攔截用戶的請求並進行相應的處理。比如通過它來進行權限驗證,或者是來判斷用戶是否登陸,或者是像12306 那樣子判斷當前時間是否是購票時間。
- SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現的。在SpringMVC 中定義一個Interceptor 非常簡單,主要有兩種方式:
- 第一種方式是要定義的Interceptor類要實現了Spring 的HandlerInterceptor 接口,或者是這個類繼承實現了HandlerInterceptor 接口的類,比如Spring 已經提供的實現了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ;
- 第二種方式是實現Spring的WebRequestInterceptor接口,或者是繼承實現了WebRequestInterceptor的類。
- 代碼實現
- 自定義攔截器類
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class FirstInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//請求處理之前進行調用
HttpSession session = request.getSession();
String userName = (String) session.getAttribute("userName");
if (userName == null) {
response.sendRedirect("/ssm_demo/welcome.html");
//當它返回爲false 時,表示請求結束,後續的Interceptor 和Controller 都不會再執行
return false;
} else {
//當返回值爲true 時就會繼續調用下一個Interceptor 的preHandle 方法
return true;
}
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
//在當前請求進行處理之後,也就是Controller 方法調用之後執行
//但是它會在DispatcherServlet 進行視圖返回渲染之前被調用
//可以在這個方法中對Controller 處理之後的ModelAndView 對象進行操作
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//該方法將在整個請求結束之後,也就是在DispatcherServlet 渲染了對應的視圖之後執行
//這個方法的主要作用是用於進行資源清理工作的
}
}
- spring.xml配置文件
<!-- 配置攔截器1 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/testController/toTest"/>
<mvc:exclude-mapping path="/welcome.html"/>
<bean id="firstInterceptor" class="zjq.interceptor.FirstInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
過濾器和攔截器的區別
- 攔截器是基於java的反射機制的,而過濾器是基於函數回調
- 攔截器不依賴與servlet容器,過濾器依賴與servlet容器
- 攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用
- 攔截器可以訪問action上下文、值棧裏的對象,而過濾器不能訪問
- 在action的生命週期中,攔截器可以多次被調用,而過濾器只能在容器初始化時被調用一次
- 攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裏注入一個service,可以調用業務邏輯。
過濾器和攔截器的順序
- 先過濾再做實際的攔截操作
- 過濾器是JavaEE標準,採用函數回調的方式進行。是在請求進入容器之後,還未進入Servlet之前進行預處理,並且在請求結束返回給前端這之間進行後期處理
- 攔截器是被包裹在過濾器之中的
參考文章1 參考文章2 參考文章3