Filter(過濾器)、Listener(監聽器)

一: 過濾器: 可以把”不和諧”的東西給過濾掉

01.過濾器概述

生活中的過濾器:帶有過濾功能的淨水器,濾紙,香菸的過濾嘴,測試,丈母孃.

程序中的過濾器:在JAVA中最小的程序單元是類,程序中的過濾器就是一個特殊的類

              Servelt/Filter是Web的一個組件.
Web中過濾器的作用(簡單理解爲:過濾器處在客戶端和服務端資源之間):

        過濾器可以對所有的請求或者響應做攔截操作.

        1:以常規的方式調用資源(Servelt/JSP);

        2:利用修改過的請求信息調用資源;

        3:調用資源之後,但在響應到客戶端之前,對響應做出修改;

        4:阻止當前資源調用,代之轉帶其他資源.

02.過濾器的應用

過濾器在開發中的應用:

    1):可以對請求中的字符做編碼.

    2):登錄驗證過濾器.

    3):敏感字(非法文字)過濾.

    4):做MVC框架中的前端控制器(處理所有請求共同操作,再分發)
在開發中兩個常用的思想:

    1):DRY原則: Don't Repeat Yourself.

        開發中拒絕代碼重複,(重複會帶來巨大的維護成本)

    2):責任分離原則:各自做各自最擅長的事情.

03:開發和使用Filter

Servlet開發:

        1:自定義一個類(XxxServlet),實現於javax.servlet.Servlet接口.

        2:實現Servelt接口中的方法(init(初始化方法),service(處理請求))

        3:告訴Tomcat來幫我們管理該Servlet程序(1:使用web.xml做配置,2:WebServlet("/資源名")).

        <servlet>
                <servlet-name>Servlet的別名</servlet-name>
                <servlet-class>自定義Servelt的全限定名</servlet-class>
        </servlet>
        <servlet-mapping>
                <servlet-name>Servlet的別名</servlet-name>
                <url-pattern>/資源名</url-pattern>
        </servlet-mapping>

        注意:此時的url-pattern的文本內容是外界訪問Servelt的資源名稱.
Filter開發:

        1:自定義一個類(XxxFilter),實現於javax.servlet.Filter接口.

        2:實現Filter接口中的方法(init(初始化方法),doFilter(處理請求))

        3:告訴Tomcat來幫我們管理該Filter程序(1:使用web.xml做配置,2:WebFilter("/資源名")).

        <filter>
                <filter-name>Filter的別名</filter-name>
                <filter-class>自定義Filter的全限定名</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>Filter的別名</filter-name>
                <url-pattern>/資源名</url-pattern>
        </filter-mapping>

        注意:此時的url-pattern的文本內容是Filter對哪一些資源做過濾操作.

            如:   /hello.jsp           :說明當前Filter只會對/hello.jsp做攔截/過濾.
                  /employee            :說明當前Filter只會對/enployee資源做過濾.
                  /system/*            :說明當前Filter只會對以/system/作爲前綴的資源路徑做攔截.
filterChain(過濾器鏈):多個過濾器按照一定的順序,排列起來.

攔截器棧:
--------------------------------------------------------
程序中存在多個過濾器的時候,過濾器的先後執行順序由誰來決定.      

    在WEB.xml中:配置的<fiter-mapping>的先後順序來決定.

    ![過濾器的的先後執行順序示意圖](https://img-blog.csdn.net/20180310104230663?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VpeGluXzQwMTYxNzA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

04.Filter的細節

過濾器的映射細節:

1):filter中的url-pattern的文本內容是Filter對哪一些資源做過濾操作.

        如:     /hello.jsp           :說明當前Filter只會對/hello.jsp做攔截/過濾.
                /employee            :說明當前Filter只會對/enployee資源做過濾.
                /system/*            :說明當前Filter只會對以/system/作爲前綴的資源路徑做攔截.
                /*                   :說明對所有的資源做過濾.
                /*.do                :對所有以 .do 結尾的資源做攔截

2):Filter的dispatcher(表示對哪些動作作過濾).

        <filter-mapping>
            <filter-name>FilterDemo1</filter-name>
            <url-pattern>/*</url-pattern>
            <url-pattern>/x1</url-pattern>
            <!-- 只對請求做攔截(默認) -->
            <dispatcher>REQUEST</dispatcher>
            <!-- 增加對請求轉發做攔截 -->
            <dispatcher>FORWARD</dispatcher>
            <!-- 增加請求包含做攔截 -->
            <dispatcher>INCLUDE</dispatcher>
            <!-- 增加跳轉到錯誤頁面做攔截 -->
            <dispatcher>ERROR</dispatcher>
    </filter-mapping>

    <error-page>
            <error-code>404</error-code>
            <location>/404.jsp</location>
    </error-page>           

05.請求編碼過濾器CharacterEncodingFilter

Servelt只管 1:獲取 2:調用 3:跳轉 就行,設置編碼交給Filter就行, DRY原則 跟 責任分離原則!
    //字符編碼過濾器
    public class CharacterEncodingFilter implements Filter{

        private String encoding;    

        private Boolean forceEncoding = false;

        public void init(FilterConfig config) throws ServletException {
            this.encoding = config.getInitParameter("encoding");
            forceEncoding = Boolean.valueOf(config.getInitParameter("force"));
        }

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            //類型
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            //設置編碼
            //1:應用中沒有編碼,並且我自己設置了編碼.
            //2:應用中已經存在編碼了但是依然要使用我自己設置的編碼:強制使用
            if(haslength(encoding) && (req.getCharacterEncoding() == null || forceEncoding)){
                req.setCharacterEncoding(encoding);
            }
            chain.doFilter(req, resp);
        }

        public void destroy() {

        }

        private boolean haslength(String str){
            return str!=null && !"".equals(str.trim());
        }
    }

XML配置文件

    <filter>
            <filter-name>CharacterEncodingFilter</filter-name>
            <filter-class>com._520it._02_characterencoding.CharacterEncodingFilter</filter-class>
            <!-- 設置編碼 -->
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
            <!-- 是否強制使用該編碼  -->
            <init-param>
                <param-name>force</param-name>
                <param-value>true</param-value>
            </init-param>
    </filter>
    <filter-mapping>
            <filter-name>CharacterEncodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping>

06.登陸檢查過濾器

        ![登錄檢查的流程圖](http://img.blog.csdn.net/20180310170822918?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VpeGluXzQwMTYxNzA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

檢查登錄過濾器

    //登錄檢查過濾器
    public class CheckLoginFilter implements Filter{

        private String[] unCheckUris = {"/login.jsp","/login"};

        public void init(FilterConfig filterConfig) throws ServletException {
        }
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse resp = (HttpServletResponse) response;
            Object user = req.getSession().getAttribute("USER_IN_SESSION");
            //當前正在過濾的資源
            String requestURI = req.getRequestURI();
            if(!Arrays.asList(unCheckUris).contains(requestURI)){
                if(user == null){//沒有登錄
                    resp.sendRedirect("login.jsp");
                    return ;
                }
            }
            chain.doFilter(req, resp);
        }
        public void destroy() {
        }
    }

從登錄界面跳轉到的Servlet中

    @WebServlet("/login")
    public class LoginServelt extends HttpServlet{

        private static final long serialVersionUID = 1L;

        protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String username = req.getParameter("username");
            //把登錄信息存儲到session中
            req.getSession().setAttribute("USER_IN_SESSION",username);
            resp.sendRedirect("/welcome.jsp");
        }
    }

login.jsp登錄界面

    <form action="/login" method="post">
        賬號:<input type="text" name="username" required/><br/>
        密碼:<input type="text" name="password"/><br/>
            <input type="submit" value="登錄"/>
    </form>

welcom.jsp

    ${sessionScope.USER_IN_SESSION}
    <hr/>
    <a href="function1.jsp">功能1</a><br/>
    <a href="function2.jsp">功能2</a><br/>
    <a href="function3.jsp">功能3</a><br/>

Filter的配置文件

    <filter>
        <filter-name>CheckLoginFilter</filter-name>
        <filter-class>com._520it.checklogin.CheckLoginFilter</filter-class>
        <init-param>
                <param-name>unCheckUris</param-name>
                <!-- 以後這樣做 對需要檢查的放到/system/中來 -->
                <param-value>/system/*</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CheckLoginFilter</filter-name>
        <url-pattern>/*</url-pattern>   
    </filter-mapping>

07.敏感字過濾

        利用裝飾設計模式,給Request.getParameter賦予敏感字過濾功能

        ![流程示意圖](http://img.blog.csdn.net/20180310212548133?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2VpeGluXzQwMTYxNzA4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

給Filter中的request賦予過濾字符的功能

    public class MessageRequestWapper extends HttpServletRequestWrapper{
        public MessageRequestWapper(HttpServletRequest request) {
            super(request);
        }
        //覆蓋getParameter方法,使之支持敏感字過濾
        public String getParameter(String name){
            //如果參數名爲title或content
            if("title".equals(name) || "content".equals(name)){
                //返回過濾之後的title和content
                FilterUtil.filter(super.getParameter(name)); //FilterUtils就是過濾的代碼,現在先知道就行
            }
            return super.getParameter(name);
        }
    }

過濾器(filter)使用

    @WebFilter("/*")
    public class MessageFilter implements Filter{
        public void init(FilterConfig filterConfig) throws ServletException {
        }
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            //把不具有處理敏感字的請求對象換成可以處理敏感字的請求對象.
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletRequest requestWapper = new MessageRequestWapper(req);
            //放行
            chain.doFilter(requestWapper, response);
        }
        public void destroy() {
        }
    }

二: Listener(監聽器)

Web的另一大組件:Listener(監聽器).

Web中的監聽器,主要用於監聽作用域對象的創建,監聽作用域對象屬性的添加/刪除/替換:

        1):監聽作用域對象的創建和銷燬.

            ServletRequestListener:監聽請求對象的創建和銷燬.

            HttpSessionListener:監聽會話對象(session) 的創建和銷燬

            ServletContextListener:監聽應用的創建和銷燬.

        2):監聽作用域對象的屬性的添加/刪除/替換.

            ServletRequestAttributeListener: 監聽request作用域中屬性的添加/刪除/替換.

            HttpSessionAttributeListener: 監聽session作用域中屬性的添加/刪除/替換.

            ServletContextAttributeListener: 監聽application作用域中屬性的添加/刪除/替換.

        Web中的監聽器組件,沒有初始化參數配置如果要解決監聽器中的硬編碼,只能使用全局的初始化參數.
    //監聽系統(應用)的啓動和銷燬
    public class ContextLoaderListener implements ServletContextListener{

        public void contextInitialized(ServletContextEvent sce) {
            System.out.println("Web系統啓動了.....");
        }

        public void contextDestroyed(ServletContextEvent sce) {
            System.out.println("Web系統銷燬了.....");
        }
    }
    @WebListener
    public class HttpSessionListenerDemo implements HttpSessionListener{

        public void sessionCreated(HttpSessionEvent se) {
            System.out.println("會話開始了");
        }

        public void sessionDestroyed(HttpSessionEvent se) {
            System.out.println("會話結束了");
        }
    }
    @WebListener
    public class HttpSessionAttributeListenerDemo implements HttpSessionAttributeListener{

        public void attributeAdded(HttpSessionBindingEvent se) {
            System.out.println("屬性添加"+se.getName()+","+se.getValue());
        }
        public void attributeRemoved(HttpSessionBindingEvent se) {
            System.out.println("屬性刪除"+se.getName()+","+se.getValue());
        }
        public void attributeReplaced(HttpSessionBindingEvent se) {
            System.out.println("屬性替換"+se.getName()+","+se.getValue()+","+se.getSession().getAttribute(se.getName()));
        }
    }
預習,精通Struts2的hello開發:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章