監聽器用於監聽 web 應用中某些對象、信息的建立、銷燬、增長,修改,刪除等動做的發生,而後做出相應的響應處理。當範圍對象的狀態發生變化的時候,服務器自動調用監聽器對象中的方法。經常使用於統計在線人數和在線用戶,系統加載時進行信息初始化,統計網站的訪問量等等。html
按監聽對象可分爲如下幾類:java
package com.zze.listener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { /* * 初始化時調用 * */ System.out.println("初始化"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { /* * 銷燬時調用(服務器正常關閉或從服務器移除項目時) * */ System.out.println("銷燬"); } }
<listener> <listener-class>com.zze.listener.MyServletContextListener</listener-class> </listener>
package com.zze.listener; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; public class MyServletContextAttributeListener implements ServletContextAttributeListener { @Override public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("添加屬性時觸發"); } @Override public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("移除屬性時觸發"); } @Override public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("修改屬性時觸發"); } }
<listener> <listener-class>com.zze.listener.MyServletContextAttributeListener</listener-class> </listener>
HttpSessionListener 監聽 Session 對象的建立和銷燬:web
package com.zze.listener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; public class MyHttpSessionListener implements HttpSessionListener { @Override public void sessionCreated(HttpSessionEvent httpSessionEvent) { System.out.println("session 建立時調用"); } @Override public void sessionDestroyed(HttpSessionEvent httpSessionEvent) { System.out.println("session 銷燬時調用"); } }
<listener> <listener-class>com.zze.listener.MyHttpSessionListener</listener-class> </listener>
HttpSessionAttributeListener 監聽 Session 中的屬性操做:apache
package com.zze.listener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener { @Override public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("添加屬性時觸發"); } @Override public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("移除屬性時觸發"); } @Override public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("修改屬性時觸發"); } }
<listener> <listener-class>com.zze.listener.MyHttpSessionAttributeListener</listener-class> </listener>
package com.zze.com.zze.bean; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionBindingListener; public class User implements HttpSessionBindingListener { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("被綁定到 session"); } @Override public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) { System.out.println("從 session 中解綁"); } }
package com.zze.servlet; import com.zze.com.zze.bean.User; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; @WebServlet("/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); session.setAttribute("user", new User()); // 綁定 觸發 valueBound session.removeAttribute("user");// 解綁 觸發 valueUnbound } }
HttpSessionActivationListener 監聽對象在 Session 中的鈍化與活化:數組
package com.zze.bean; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionEvent; import java.io.Serializable; public class User implements HttpSessionActivationListener,Serializable { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) { System.out.println("鈍化"); } @Override public void sessionDidActivate(HttpSessionEvent httpSessionEvent) { System.out.println("活化"); } }
package com.zze.servlet; import com.zze.com.zze.bean.User; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/test") public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) { HttpSession session = req.getSession(); session.setAttribute("user", new User("zhangsan",19)); // 存儲到 session } }
鈍化:將內存中的數據序列化保存到硬盤。tomcat
活化:將硬盤中的數據反序列化加載到內存。服務器
session 中的值可能會不少,而且可能咱們很長一段時間都不會使用這個值,那麼能夠考慮將 session 中的值存儲到硬盤,等要使用的時候再從硬盤中提取,減輕內存壓力。session
默認狀況下,在服務器正常關閉時會鈍化保存在 session 中的數據,而在服務器再次啓動時會活化以前鈍化的數據。app
<?xml version="1.0" encoding="UTF-8"?> <Context> <!--maxIdleSwap :設置間隔多久時間鈍化,單位爲分鐘--> <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1"> <!--directory:session 鈍化保存的目錄--> <Store className="org.apache.catalina.session.FileStore" directory="sessionDir"/> </Manager> </Context>
在 tomcat 目錄下 /conf/context.xml 中配置以上內容,對託管到當前服務器的全部程序生效。ide
在 tomcat 目錄下 /conf/Catalina/localhost/context.xml 中配置以上內容,對託管到當前服務器中使用 localhost 訪問的程序生效。
在項目目錄下 /META-INF/context.xml 中配置以上內容,僅對當前項目生效。
package com.zze.listener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; public class MyServletRequestListener implements ServletRequestListener { @Override public void requestInitialized(ServletRequestEvent servletRequestEvent) { System.out.println("初始化"); } @Override public void requestDestroyed(ServletRequestEvent servletRequestEvent) { System.out.println("銷燬"); } }
<listener> <listener-class>com.zze.listener.MyServletRequestListener</listener-class> </listener>
ServletRequestAttributeListener 監聽 Request 中的屬性操做:
package com.zze.listener; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; public class MyServletRequestAttributeListener implements ServletRequestAttributeListener { @Override public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) { System.out.println("添加屬性時觸發"); } @Override public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) { System.out.println("移除屬性時觸發"); } @Override public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) { System.out.println("修改屬性時觸發"); } }
<listener> <listener-class>com.zze.listener.MyServletRequestAttributeListener</listener-class> </listener>
Filter 也稱之爲過濾器,它是 Servlet 技術中最實用的技術,Web 開發人員經過 Filter 技術,對 web 服務器管理的全部 web 資源:例如 Jsp , Servlet , 靜態圖片文件或靜態 html 文件等進行攔截,從而實現一些特殊的功能。例如實現 URL 級別的權限訪問控制、過濾敏感詞彙、壓縮響應信息等一些高級功能。
它主要用於對用戶請求進行預處理,也能夠對 HttpServletResponse 進行後處理。使用 Filter 的完整流程:Filter 對用戶請求進行預處理,接着將請求交給 Servlet 進行處理並生成響應,最後 Filter 再對服務器響應進行後處理。
package com.zze.filter; import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("前處理"); filterChain.doFilter(servletRequest, servletResponse); // 若是不調用 後續的過濾器及 servlet 都不會執行 System.out.println("後處理"); } @Override public void destroy() { System.out.println("銷燬"); } }
<filter> <filter-name>myFilter</filter-name> <filter-class>com.zze.filter.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- <filter>:指定一個過濾器。 <filter-name>:用於爲過濾器指定一個名字,該元素的內容不能爲空。 <filter-class>:用於指定過濾器的完整的限定類名。 <init-param>:用於爲過濾器指定初始化參數,它的子元素 <param-name> 指定參數的名字,<param-value> 指定參數的值。在過濾器中,可使用 FilterConfig 接口對象來訪問初始化參數。 <filter-mapping>:用於設置一個 Filter 所負責攔截的資源。一個 Filter 攔截的資源可經過兩種方式來指定:Servlet 名稱和資源訪問的請求路徑 <filter-name>子元素用於設置 filter 的註冊名稱。該值必須是在 <filter> 元素中聲明過的過濾器的名字 <url-pattern>設置 filter 所攔截的請求路徑(過濾器關聯的URL樣式) <servlet-name>指定過濾器所攔截的 Servlet 名稱。 <dispatcher>指定過濾器所攔截的資源被 Servlet 容器調用的方式,能夠是 REQUEST , INCLUDE , FORWARD 和 ERROR 之一,默認REQUEST。用戶能夠設置多個 <dispatcher> 子元素用來指定 Filter 對資源的多種調用方式進行攔截。 REQUEST:當用戶直接訪問頁面時,Web容器將會調用過濾器。若是目標資源是經過RequestDispatcher的include()或forward()方法訪問時,那麼該過濾器就不會被調用。 INCLUDE:若是目標資源是經過RequestDispatcher的include()方法訪問時,那麼該過濾器將被調用。除此以外,該過濾器不會被調用。 FORWARD:若是目標資源是經過RequestDispatcher的forward()方法訪問時,那麼該過濾器將被調用,除此以外,該過濾器不會被調用。 ERROR:若是目標資源是經過聲明式異常處理機制調用時,那麼該過濾器將被調用。除此以外,過濾器不會被調用。 -->
在一個web應用中,能夠開發編寫多個 Filter ,這些 Filter 組合起來稱之爲一個 Filter 鏈。
web 服務器根據 Filter 在 web.xml 文件中的註冊順序,決定先調用哪一個 Filter,當第一個 Filter 的 doFilter 方法被調用時,web 服務器會建立一個表明 Filter 鏈的 FilterChain 對象傳遞給該方法。在 doFilter 方法中,開發人員若是調用了 FilterChain 對象的 doFilter 方法,則 web 服務器會檢查 FilterChain 對象中是否還有 filter,若是有,則調用第2個 filter ,若是沒有,則調用目標資源。
public void init(FilterConfig filterConfig) throws ServletException;// 初始化 /* 和咱們編寫的 Servlet 程序同樣,Filter 的建立和銷燬由 WEB 服務器負責。 web 應用程序啓動時,web 服務器將建立 Filter 的實例對象,並調用其 init 方法,讀取 web.xml 配置,完成對象的初始化功能,從而爲後續的用戶請求做好攔截的準備工做(filter 對象只會建立一次,init 方法也只會執行一次)。 開發人員經過 init 方法的參數,可得到表明當前 filter 配置信息的 FilterConfig 對象。 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;// 攔截請求 /* 這個方法完成實際的過濾操做。當客戶請求訪問與過濾器關聯的URL的時候,Servlet 過濾器將先執行 doFilter 方法。FilterChain 參數用於訪問後續過濾器。 */ public void destroy();//銷燬 /* Filter 對象建立後會駐留在內存,當 web 應用移除或服務器中止時才銷燬。 在Web容器卸載 Filter 對象以前被調用。該方法在 Filter 的生命週期中僅執行一次。 在這個方法中,能夠釋放過濾器使用的資源。 */
package com.zze.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; /** * 統一編碼 */ public class EncodingFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) req; HttpServletResponse response=(HttpServletResponse) resp; chain.doFilter(new MyRequest(request), response); } @Override public void destroy() { } } class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; private boolean flag=true; public MyRequest(HttpServletRequest request) { super(request); this.request=request; } @Override public String getParameter(String name) { if(name==null || name.trim().length()==0){ return null; } String[] values = getParameterValues(name); if(values==null || values.length==0){ return null; } return values[0]; } @Override public String[] getParameterValues(String name) { if(name==null || name.trim().length()==0){ return null; } Map<String, String[]> map = getParameterMap(); if(map==null || map.size()==0){ return null; } return map.get(name); } @Override public Map<String,String[]> getParameterMap() { String method = request.getMethod(); if("post".equalsIgnoreCase(method)){ try { request.setCharacterEncoding("utf-8"); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } }else if("get".equalsIgnoreCase(method)){ Map<String,String[]> map = request.getParameterMap(); if(flag){ for (String key:map.keySet()) { String[] arr = map.get(key); //繼續遍歷數組 for(int i=0;i<arr.length;i++){ //編碼 try { arr[i]=new String(arr[i].getBytes("iso8859-1"),"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } flag=false; } return map; } return super.getParameterMap(); } }