Filter 即爲過濾,用於在 Servlet 以外對 Request 或者 Response 進行修改。它主要用於對用戶請求進行預處理,也能夠對 HttpServletResponse 進行後處理。使用 Filter 的完整流程: Filter 對用戶請求進行預處理,接着將請求交給 Servlet 進行處理並生成響應,最後 Filter 再 對服務器響應進行後處理。在一個 web 應用中,能夠開發編寫多個 Filter,這些 Filter 組合 起來稱之爲一個 Filter 鏈。css
單個過濾器html
多個過濾器java
如果一個過濾器鏈:先配置先執行(請求時的執行順序);響應時: 以相反的順序執行。web
在 HttpServletRequest 到達 Servlet 以前,攔截客戶的 HttpServletRequest 。根據須要檢查HttpServletRequest,也能夠修改 HttpServletRequest 頭和數據。服務器
在HttpServletResponse 到達客戶端以前,攔截 HttpServletResponse。根據須要檢查 HttpServletResponse,也能夠修改 HttpServletResponse頭和數據。session
能夠經過實現一個叫作javax.servlet.Fileter的接口來實現一個過濾器,其中定義了 三個方法,init(), doFilter(), destroy()分別在相應的時機執行。後期觀察生命週期。app
Filter 的實現只須要兩步:jsp
Step1: 編寫 java 類實現 Filter 接口,並實現其 doFilter 方法。ide
Step2: 經過@WebFilter註解設置它所能攔截的資源。測試
@WebFilter("/*") public class Filter01 implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { } @Override public void destroy() { } }
Filter 接口中有一個 doFilter 方法,當開發人員編寫好 Filter,並配置對哪一個 web 資源進行攔截後,Web 服務器每次在調用 web 資源的 service 方法以前,都會先調用一下 filter 的 doFilter 方法。所以能夠達到以下效果:
調用目標資源以前,讓一段代碼執行。
是否調用目標資源(便是否讓用戶訪問 web 資源)。
web 服務器在調用 doFilter 方法時,會傳遞一個 filterChain 對象進來,filterChain 對象是 filter 接口中最重要的一個對象,它提供了一個 doFilter 方法,開發人員能夠根據需求決定 是否調用此方法,調用該方法,則 web 服務器就會調用 web 資源的 service 方法,即 web 資源就會被訪問,不然 web 資源不會被訪問。(本質是放行,調用doFilter方法後,即請求能夠到達資源)
/** * 字符亂碼處理 * 亂碼狀況: Tomcat8及以上版本 Tomcat7及如下版本 POST請求 亂碼,須要處理 亂碼,須要處理 request.setCharacterEncoding("UTF-8"); GET請求 不會亂碼,不須要處理 亂碼,須要處理 new String(request.getParameter("參數名").getBytes("ISO-8859-1"),"UTF-8"); 如何處理: 一、處理POST請求 request.setCharacterEncoding("UTF-8"); 二、處理GET請求且服務器版本在Tomcat8如下的 1> 獲得請求類型 (GET請求) 2> 獲得服務器的版本的信息 3> 判斷是GET請求且Tomcat版本小於8 4> 處理亂碼 new String(request.getParameter("參數名").getBytes("ISO-8859-1"),"UTF-8"); */ @WebFilter("/*") public class AEncodingFilter implements Filter { public AEncodingFilter() { } public void destroy() { } public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException { // 基於HTTP HttpServletRequest request = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; // 處理請求亂碼亂碼 (處理POST請求) request.setCharacterEncoding("UTF-8"); // 處理GET請求且服務器版本在Tomcat8如下的 String method = request.getMethod(); // 若是是GET請求 if ("GET".equalsIgnoreCase(method)) { // 服務器版本在Tomcat8如下的 Apache Tomcat/8.0.45 String serverInfo = request.getServletContext().getServerInfo(); // 獲得具體的版本號 String versionStr = serverInfo.substring(serverInfo.indexOf("/")+1, serverInfo.indexOf(".")); // 判斷服務器版本是否小於8 if (Integer.parseInt(versionStr) < 8) { // 獲得自定義內部類 (MyWapper繼承了HttpServletRequestWapper對象,而HttpServletRequestWapper對象實現了HttpServletRequest接口,因此MyWapper的本質也是request對象) HttpServletRequest myRequest = new MyWapper(request); // 放行資源 chain.doFilter(myRequest, response); return; } } // 放行資源 chain.doFilter(request, response); } public void init(FilterConfig fConfig) throws ServletException { } /** * 定義內部類,繼承HttpServletRequestWrapper包裝類對象,重寫getParameter()方法 */ class MyWapper extends HttpServletRequestWrapper { // 定義成員變量,提高構造器 中的request對象的範圍 private HttpServletRequest request; public MyWapper(HttpServletRequest request) { super(request); this.request = request; } /** * 重寫getParameter()方法 */ @Override public String getParameter(String name) { String value = request.getParameter(name); if (value != null && !"".equals(value.trim())) { try { // 將默認ISO-8859-1編碼的字符轉換成UTF-8 value = new String(value.getBytes("ISO-8859-1"),"UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return value; } } }
/** * 非法訪問攔截(當用戶未登陸時,攔截請求到登陸頁面) * 攔截的資源: * 攔截全部資源 /* * 須要被放行的資源: * 不須要登陸便可訪問的資源 * 一、放行指定頁面,不須要登陸能夠訪問的頁面 (例如:登陸頁面、註冊頁面等) * 二、放行靜態資源(例如:css、js、image等資源) * 三、放行指定操做,不須要登陸便可執行的操做(例如:登陸操做、註冊操做等) * 四、登陸狀態放行 (若是存在指定sessuin對象,則爲登陸狀態) */ @WebFilter("/*") public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException { // 基於HTTP HttpServletRequest request = (HttpServletRequest) arg0; HttpServletResponse response = (HttpServletResponse) arg1; // 獲得請求的路徑 String path = request.getRequestURI(); // 站點名/資源路徑 // 一、放行指定頁面,不須要登陸能夠訪問的頁面 (例如:登陸頁面、註冊頁面等) if (path.contains("/login.jsp") || path.contains("/register.jsp")) { chain.doFilter(request, response); return; } // 二、放行靜態資源(例如:css、js、image等資源) if (path.contains("/js")) { chain.doFilter(request, response); return; } // 三、放行指定操做,不須要登陸便可執行的操做(例如:登陸操做、註冊操做等) if (path.contains("/loginServlet")) { chain.doFilter(request, response); return; } // 四、登陸狀態放行 (若是存在指定sessuin對象,則爲登陸狀態) // 獲得session域對象 String uname = (String) request.getSession().getAttribute("user"); // 若是session域對象不爲空,則爲登陸狀態,放行資源 if (uname != null && !"".equals(uname.trim())) { chain.doFilter(request, response); return; } // 若以上條件均不知足,攔截跳轉到登陸頁面 response.sendRedirect("login.jsp"); return; }
web 監聽器是Servlet 中一種的特殊的類,能幫助開發者監聽 web 中的特定事件, 好比 ServletContext,HttpSession,ServletRequest 的建立和銷燬;變量的建立、銷燬和修改等。 能夠在某些動做先後增長處理,實現監控。例如能夠用來統計在線人數等。
監聽器有三類8種:
⑴ 監聽生命週期:
ServletRequestListener
HttpSessionListener
ServletContextListener
⑵ 監聽值的變化:
ServletRequestAttributeListener
HttpSessionAttributeListener
ServletContextAttributeListener
⑶ 針對 session 中的對象:
監聽 session 中的 java 對象(javaBean) ,是 javaBean 直接實現監聽器 的接口。
作一個對在線人數的監控。
實現步驟:
Step1:建立一個監聽器,須要實現某種接口,根據需求選取 HttpSessionListener
Step2:經過@WebListener註解配置該監聽器
建立一個類,並實現 HttpSessionListener 接口,用來檢測 Session 的建立和銷燬。
1.在類中定義一個成員變量用來存儲當前的 session 個數。(OnlineListener.java)
/** * 在線人數統計 * 當有新的session對象被建立,則在線人數+1; * 有session對象被銷燬,在線人數-1; * @author Lisa Li * */ @WebListener public class OnlineListener implements HttpSessionListener { // 默認在線人數 private Integer onlineNumber = 0; /** * 當有新的session對象被建立,則在線人數+1; */ @Override public void sessionCreated(HttpSessionEvent se) { // 人數+1 onlineNumber++; // 將人數存到session做用域中 // se.getSession().setAttribute("onlineNumber", onlineNumber); // 將人數存到application做用域中 se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber); } /** * 有session對象被銷燬,在線人數-1; */ @Override public void sessionDestroyed(HttpSessionEvent se) { // 人數-1 onlineNumber--; // 將人數存到session做用域中 // se.getSession().setAttribute("onlineNumber", onlineNumber); // 將人數存到application做用域中 se.getSession().getServletContext().setAttribute("onlineNumber", onlineNumber); } }
2.作一個測試的 Servlet 用來登陸,和顯示當前在線人數。(OnlineServlet.java)
/** * 在線人數統計 */ public class OnlineServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 獲得參數 String key = request.getParameter("key"); // 判斷是否爲空 (不爲空,且值爲logout則爲退出操做) if (key != null && "logout".equals(key)) { // 傳遞了參數,表示要作用戶退出操做 request.getSession().invalidate(); return; } // 建立session對象 HttpSession session = request.getSession(); // 獲取sessio做用域中的在線人數 Integer onlineNumber = (Integer) session.getServletContext().getAttribute("onlineNumber"); // 輸出 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<h2>在線人數:"+onlineNumber+"</h2><h4><a href='online?key=logout'>退出</a><h4>"); } }
equest.getSession();
// 獲取sessio做用域中的在線人數
Integer onlineNumber = (Integer) session.getServletContext().getAttribute(「onlineNumber」);
// 輸出 response.setContentType("text/html;charset=UTF-8"); response.getWriter().write("<h2>在線人數:"+onlineNumber+"</h2><h4><a href='online?key=logout'>退出</a><h4>"); }
}