過濾器和監聽器

過濾器和監聽器

主要內容

過濾器

介紹

​ 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>");    

}

}

相關文章
相關標籤/搜索