第6章 filter(4课时)过滤器和监听器

课程目标

掌握过滤器概念及两种编写方法

过滤器Filter

过滤器也叫拦截器,在一个层面上解决问题。
应用:用来做统一编码解码、用来做权限验证、做网站计数等等
特殊说明:过滤器可以是一个链。也就是说可以配置多个过滤器,我们也可以通过配置来控制顺序

怎么建filter

servlet3.0以后。可以用向导建
例如:我建一个统一做编码处理的

我们之前在每个servlet里要写

request.setChararcterEncoding("utf-8");
response.setChararcterEncoding("utf-8");

file-new -Filter-按向导一步步配置。
step1 为filter起个文件名CharacterFilter
step2 设置初始化参数 encoding:UTF-8
step3 mapping 配置过滤对象(1--可以对指定的servlet进行过滤 2--可以配置过滤规则)

配置完成后生成如下代码:

package com.neuedu.utils;

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;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;


@WebFilter(
        urlPatterns = { "/*" }, 
        initParams = { 
                @WebInitParam(name = "encoding", value = "UTF-8")
        })
public class CharacterFilter implements Filter {


public CharacterFilter() {
// TODO Auto-generated constructor stub
}

    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        // TODO Auto-generated method stub
    }

    /**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        // place your code here

        // pass the request along the filter chain
        chain.doFilter(request, response);
    }

    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

}

我们看到有三个主要方法

init() 初始化方法:做准备工作

doFilter() 业务方法
需要注意的是:j里面有一个
chain.doFilter(request, response);这句话的意思是执行完该过滤器后去执行下一个过滤器
用@WebFilter方式配置的过滤器执行顺序是按filterName首字母的先后顺序执行。

destroy() 销毁方法:做清理工作

完整代码如下:

package com.neuedu.utils;

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;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

/**
 * Servlet Filter implementation class CharacterFilter
 */
@WebFilter(
        filterName="MyFilter",
        urlPatterns = { "/*" }, 
        initParams = { 
                @WebInitParam(name = "encoding", value = "UTF-8")
        })
public class CharacterFilter implements Filter {
    String encode="";
     /**
 * Default constructor. 
 */
public CharacterFilter() {
// TODO Auto-generated constructor stub
}
    
    /**
     * @see Filter#init(FilterConfig)
     */
    public void init(FilterConfig fConfig) throws ServletException {
        //在初始化时准备好编码方式
        encode=fConfig.getInitParameter("encoding");
    }
   
/**
     * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
     */
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding(encode);
        response.setCharacterEncoding(encode);
        //执行下一个过滤器
        chain.doFilter(request, response);
    }
    /**
     * @see Filter#destroy()
     */
    public void destroy() {
        encode="";
    }
}

filter另外一种创建方式

servlet3.0之前

简化版

java类

public class TestFilter implements Filter {
    @Override
    public void destroy() {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO Auto-generated method stub
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig fconfig) throws ServletException {
    }

}

配置:

<filter>
        <filter-name>TestFilter</filter-name>
        <filter-class>com.neuedu.utils.TestFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>TestFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

分两步
step1 写一个类实现filter接口

package com.neuedu.utils;

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 MyFilter implements Filter {
    FilterConfig fconfig=null;
    @Override
    public void destroy() {
        fconfig=null;
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        String encode=fconfig.getInitParameter("encode");
        request.setCharacterEncoding(encode);
        response.setCharacterEncoding(encode);
        //执行下一个过滤器
        chain.doFilter(request, response);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        fconfig=config;
    }

}

step2 在WEB-INF\web.xml里配置
配置分两步
第一步filter 第二步配置filter-mapping

 <filter>
  <filter-name>MyFilter</filter-name>
  <filter-class>com.neuedu.utils.MyFilter</filter-class>
  <init-param>
  <param-name>encode</param-name>
  <param-value>utf-8</param-value>
  </init-param>
  </filter>
  
  <filter-mapping>
   <filter-name>MyFilter</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping>

过滤器使用

日志记录
登录验证
编码处理

后台登录拦截

可以定个规则,比如所有需要登录才能访问的jsp和servlet都加上/admin前缀

    @WebFilter("/admin/*")
    public class LoginFilter implements Filter {
    
        /**
         * Default constructor. 
         */
        public LoginFilter() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see Filter#destroy()
         */
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
         */
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            // place your code here
            System.out.println("进入拦截器");
            //在此处做用户是否登录的验证
            //判断session里是否存在loginUser
            HttpServletRequest httprequest=(HttpServletRequest)request;
            HttpSession session=httprequest.getSession();
            Object obj=session.getAttribute("loginUser");
            if(obj!=null){
                //如果有就放行
                chain.doFilter(request, response);
                return ;
            }else{
                //如果没有,就回登录页
                HttpServletResponse httpresponse=(HttpServletResponse)response;
                httpresponse.sendRedirect(httprequest.getContextPath()+"/login.jsp");
            }
        }
    
        /**
         * @see Filter#init(FilterConfig)
         */
        public void init(FilterConfig fConfig) throws ServletException {
            // TODO Auto-generated method stub
        }
    
    }

监听器

监听事件,比如session建立,系统启动,请求到达
本质也是java类。
建立方式
file-new listener-输入名称-选择监听器种类

比如我选择了以下三个 ServletContextListener, HttpSessionListener, ServletRequestListener
系统会自动生成如下类

package com.neuedu.utils;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

/**
 * Application Lifecycle Listener implementation class TestLisenter
 *
 */
@WebListener
public class TestLisenter implements ServletContextListener, HttpSessionListener, ServletRequestListener {

/**
 * Default constructor. 
 */
public TestLisenter() {
// TODO Auto-generated constructor stub
}

    /**
 * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
 */
public void sessionCreated(HttpSessionEvent arg0)  { 
 // TODO Auto-generated method stub
}

    /**
 * @see ServletRequestListener#requestDestroyed(ServletRequestEvent)
 */
public void requestDestroyed(ServletRequestEvent arg0)  { 
 // TODO Auto-generated method stub
}

    /**
 * @see ServletRequestListener#requestInitialized(ServletRequestEvent)
 */
public void requestInitialized(ServletRequestEvent arg0)  { 
 // TODO Auto-generated method stub
}

    /**
 * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
 */
public void sessionDestroyed(HttpSessionEvent arg0)  { 
 // TODO Auto-generated method stub
}

    /**
 * @see ServletContextListener#contextDestroyed(ServletContextEvent)
 */
public void contextDestroyed(ServletContextEvent arg0)  { 
 // TODO Auto-generated method stub
}

    /**
 * @see ServletContextListener#contextInitialized(ServletContextEvent)
 */
public void contextInitialized(ServletContextEvent arg0)  { 
 // TODO Auto-generated method stub
}

}

仿照下面程序做一个在线人数统计计数器

https://blog.csdn.net/troubleshooter/article/details/78416857

注意:
1、application 的类型为ServletContext
2、可使用哪些方法取得Web容器环境ServletContext对象?
request.getServletContext 、 sessoin.getServletContext 、 servletConfig.getServletContext
在编写Servlet时,需要继承HttpServlet类,在Servlet中声明doGet()和doPost()需要HttpServletRequest和HttpServletResponse类型的两个参数。
ServletContextListener:服务启动和停止时触发期初始化和销毁(生命周期最长)
HttpSessionListener:session的建立和销毁(session超时或调用invalidate()方法)时触发期初始化和销毁(其次)
ServletRequestListener:一次请求和响应有效(最短)

如果同时存在监听器和过滤器,先走监听器再走过滤器.

在线人数统计

    package com.neuedu.utils;
    
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextAttributeEvent;
    import javax.servlet.ServletContextAttributeListener;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * Application Lifecycle Listener implementation class MyFilter
     *
     */
    @WebListener
    public class MyListener implements ServletContextListener {
    
        /**
         * Default constructor. 
         */
        public MyListener() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see ServletContextListener#contextDestroyed(ServletContextEvent)
         */
        public void contextDestroyed(ServletContextEvent arg0)  { 
            System.out.println("上下文销毁");
        }
    
        /**
         * @see ServletContextListener#contextInitialized(ServletContextEvent)
         * ServletContext---application
         */
        public void contextInitialized(ServletContextEvent applicationEvent)  { 
            ServletContext application=applicationEvent.getServletContext();
            //在线人数,初始化为0
            application.setAttribute("onlinenumber", 0);
             System.out.println("上下文创建");
        }
        
    }


    package com.neuedu.utils;
    
    import javax.servlet.ServletContext;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * Application Lifecycle Listener implementation class MySessionListenter
     *
     */
    @WebListener
    public class MySessionListenter implements HttpSessionListener {
    
        /**
         * Default constructor. 
         */
        public MySessionListenter() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see HttpSessionListener#sessionCreated(HttpSessionEvent)
         */
        public void sessionCreated(HttpSessionEvent sessionEvent)  { 
             System.out.println("sessionCreated建立");
             //从session/request里都可以得到ServletContext--->sessionEvent.getSession可以获取
             HttpSession session=sessionEvent.getSession();
             ServletContext application= session.getServletContext();
             int old_online=(Integer)application.getAttribute("onlinenumber");
             //如果有用户访问,我们就把计数器加1
             int new_online=old_online+1;
             application.setAttribute("onlinenumber", new_online);
             System.out.println("新的在线人数"+new_online);
        }
    
        /**
         * @see HttpSessionListener#sessionDestroyed(HttpSessionEvent)
         */
        public void sessionDestroyed(HttpSessionEvent sessionEvent)  { 
             System.out.println("sessionDestroyed");
             //从session/request里都可以得到ServletContext--->sessionEvent.getSession可以获取
             HttpSession session=sessionEvent.getSession();
             ServletContext application= session.getServletContext();
             int old_online=(Integer)application.getAttribute("onlinenumber");
             //如果有用户访问,我们就把计数器加1
             int new_online=old_online-1;
             application.setAttribute("onlinenumber", new_online);
             System.out.println("新的在线人数"+new_online);
            //如果有用户退出或超时,我们就把计数器-1
        }
        
    }

前台页面

    在线人数:${onlinenumber}

如果登录成功才认为是在线

@Override
public void attributeAdded(HttpSessionBindingEvent sessionEvent) {
    // TODO Auto-generated method stub
    User user=(User)sessionEvent.getSession().getAttribute("loginUser");
    HttpSession session=sessionEvent.getSession();
    ServletContext application= session.getServletContext();
    int old_online=(Integer)application.getAttribute("onlinenumber");
    //如果有用户访问,我们就把计数器加1
    if(user!=null){
    int new_online=old_online+1;
    application.setAttribute("onlinenumber", new_online);
    System.out.println("新的在线人数"+new_online);
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341

推荐阅读更多精彩内容