监听器Listener
介绍
Listener是JavaEE的规范,就是接口
监听器的作用是,监听某种变化(一般就是对象创建/销毁, 属性变化), 触发对应方法完成相应的任务
ServletContextListener监听器(最常用)
作用:
         监听ServletContext创建或销毁(当我们Web应用启动时,就会创建ServletContext), 即生命周期监听
应用场景:
         (1)加载初始化的配置文件;比如spring的配置文件
         (2)任务调度(配合定时器Timer/TimerTask)
相关方法:
void contextInitialized(ServletContextEvent sce)        创建Servletcontext时触发
 void contextDestroyed(ServletContextEvent sce)       销毁Servletcontext时触发
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
//当一个类实现了ServletContextListener,该类就是一个监听器
//该类可以监听的事件由该类实现的监听接口决定,比如实现ServletContextListener,则该类就可以监听ServletContext对象的创建和销毁
//HspServletContext就是一个监听者
//当web应用启动时,就会产生ServletContextEvent事件,会调用监听器的对应事件处理方法contextInitialized,同时会传递事件对象
//程序员可以通过servletContextEvent事件对象,来获取需要的信息,然后再进行业务处理
public class HspServletContextListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        //获取到servletContext对象
        ServletContext servletContext = servletContextEvent.getServletContext();
        System.out.println("HspServletContextListener监听到" + servletContext + "被创建");
    }
    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        ServletContext servletContext = servletContextEvent.getServletContext();
        System.out.println("HspServletContextListener监听到" + servletContext + "被销毁");
    }
}
配置xml
    <listener>
        <listener-class>HspServletContextListener</listener-class>
    </listener>ServletContextAttributeListener监听器(最常用)
作用:
         监听ServletContext属性变化
相关方法:
void attributeAdded(ServletContextAttributeEventevent)          添加属性时调用
 void attributeReplaced(ServletContextAttributeEventevent)     替换属性时调用
 void attributeRemoved(ServletContextAttributeEventevent)     移除属性时调用
public class HspServletContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("监听到添加属性" + servletContextAttributeEvent.getName() + "=" + servletContextAttributeEvent.getValue());
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("监听到修改属性" + servletContextAttributeEvent.getName() + "=" + servletContextAttributeEvent.getValue());
    }
    @Override
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println("监听到删除属性" + servletContextAttributeEvent.getName() + "=" + servletContextAttributeEvent.getValue());
    }
}
/*
监听到添加属性name=abc
监听到修改属性name=abc    => 还是显示原来的value
监听到删除属性name=ddd
Hi处理完毕
*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext servletContext = request.getServletContext();
        servletContext.setAttribute("name","abc");
        servletContext.setAttribute("name","ddd");
        servletContext.removeAttribute("name");
        System.out.println("Hi处理完毕");
    }HttpSessionListener监听器(常用)
作用:
         监听Session创建或销毁,即生命周期监听,可以用于监控用户上线,离线
相关方法:
void sessionCreated(HttpSessionEvent se)        创建session时调用
 void sessionDestroyed(HttpSessionEvent se)    销毁session时调用
public class HspHttpSessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        //当session创建时,设置生命周期
        session.setMaxInactiveInterval(10);
        System.out.println("监听到session创建= " + session.getId());
    }
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
        HttpSession session = httpSessionEvent.getSession();
        System.out.println("监听到session销毁= " + session.getId());
    }
}protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
    }HttpSessionAttributeListener监听器
作用:
         监听Session属性的变化
相关方法:
void attributeAdded(ServletRequestAttributeEvent srae)             添加属性时
 void attributeReplaced(ServletRequestAttributeEvent srae)        替换属性时
 void attributeRemoved(ServletRequestAttributeEvent srae)        移除属性时
public class HspHttpSessionAttributeListener implements HttpSessionAttributeListener {
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        //HttpSession session = httpSessionBindingEvent.getSession();
        System.out.println("监听到session添加属性" + httpSessionBindingEvent.getName() + "=" +httpSessionBindingEvent.getValue());
    }
    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("监听到session删除属性" + httpSessionBindingEvent.getName());
    }
    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        System.out.println("监听到session修改属性" + httpSessionBindingEvent.getName() + "=" +httpSessionBindingEvent.getValue());
    }
}
/*
监听到session添加属性age=10
监听到session修改属性age=10
监听到session删除属性age
处理完毕
*/protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        session.setAttribute("age",10);
        session.setAttribute("age",20);
        session.removeAttribute("age");
        System.out.println("处理完毕");
    }ServletRequestListener监听器(常用)
作用:
         监听Request创建或销毁,即Request生命周期监听
         可以用来监控,某个IP访问我们网站的频率,日志记录,访问资源的情况
相关方法:
void requestInitialized(ServletRequestEvent sre)        创建request时
 void requestDestroyed(ServletRequestEvent sre)       销毁request时
public class HspRequestListener implements ServletRequestListener {
    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("监听到request对象被销毁");
    }
    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        System.out.println("监听到request对象创建");
        ServletRequest servletRequest = servletRequestEvent.getServletRequest();
        System.out.println("记录访问日志...");
        System.out.println("访问IP=" + servletRequest.getRemoteAddr());
        System.out.println("访问的资源=" + ((HttpServletRequest)servletRequest).getRequestURL());
    }
}ServletRequestAttributeListener监听器
作用:
         监听Request属性变化
相关方法:
void attributeAdded(ServletRequestAttributeEvent srae)             添加属性时
 void attributeReplaced(ServletRequestAttributeEvent srae)        替换属性时
 void attributeRemoved(ServletRequestAttributeEvent srae)        移除属性时
过滤器Filter
介绍
Filter 过滤器是 JavaEE 的规范,是接口

Filter 过滤器作用是:拦截请求,过滤响应
应用场景:权限检查、日记操作、事务管理
为什么需要过滤器

基本原理

在web.xml中,filter一般写在其他servlet的前面
应用
web.xml
    <filter>
        <filter-name>ManageFilter</filter-name>
        <filter-class>ManageFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>ManageFilter</filter-name>
        <!--
        /manage/*   第一个/解析成http://ip:port/工程路径
        当请求的资源url满足该条件时,就会调用该filter
        -->
        <url-pattern>/manage/*</url-pattern>
    </filter-mapping>登录
public class logincheck extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request,response);
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String pwd = request.getParameter("pwd");
        if("123456".equals(pwd)) {
            request.getSession().setAttribute("username",username);
            //请求转发不会经过 过滤器
            request.getRequestDispatcher("/manage/admin.jsp").forward(request,response);
        } else {
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }
}admin.jsp
浏览器第一次请求结束,发送第二次请求<img>,会调用dofilter()
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>hi</title>
    <base href="<%=request.getContextPath()%>/manage/">
</head>
<body>
<h1>admin目录下的 hi.jsp</h1>
<h1>后台管理</h1>
<a href="#">用户列表</a>||<a href="#">添加用户</a>||<a href="#">删除用户</a>
<hr/>
<img src="abc.png" height="400px"/>
</body>
</html>过滤器
public class ManageFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //当Tomcat创建Filter后,就会调用该方法,进行初始化
        System.out.println("init被调用");
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //到每次调用该filter时,doFilter就会被调用
        //如果这里,没有调用继续请求的方法,则就停止
        //如果继续访问目标资源-> 等价于放行
        //老师说明:在调用过滤器前,servletRequest对象=request已经被创建并封装
        //所以:我们这里就可以通过servletRequest获取很多信息, 比如访问url , session
        //比如访问的参数 ... 就可以做事务管理,数据获取,日志管理等
        //获取到session
        //可以继续使用 httpServletRequest 方法.
        System.out.println("doFiter被调用");
        HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest;
        HttpSession session = httpServletRequest.getSession();
        Object username = session.getAttribute("username");
        if(username != null) {
            //filterChain.doFilter(servletRequest, servletResponse)
            //1. 继续访问目标资源url
            //2. servletRequest 和 servletResponse 对象会传递给目标资源/文件
            //3. 一定要理解filter传递的两个对象,再后面的servlet/jsp 是同一个对象(指的是在一次http请求)
            System.out.println("servletRequest=" + servletRequest);
            System.out.println("日志信息==");
            System.out.println("访问的用户名=" + username.toString());
            System.out.println("访问的url=" + httpServletRequest.getRequestURL());
            System.out.println("访问的IP=" + httpServletRequest.getRemoteAddr());
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            //说明没有登录过,回到登录页面
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
        }
    }
    @Override
    public void destroy() {
        //当filter被销毁时,会调用该方法
        System.out.println("destroy被调用");
    }
}过滤器url-pattern

Filter生命周期

- 1. filter在web项目启动时, 由tomcat 来创建filter实例, 只会创建一个,换个浏览器也是同一个
- 2. 会调用filter默认的无参构造器, 同时会调用 init方法, 只会调用一次
- 3. 在创建filter实例时,同时会创建一个FilterConfig对象,并通过init方法传入
- 4. 通过FilterConfig对象,程序员可以获取该filter的相关配置信息
- 5. 当一个http请求和该filter的的url-patter匹配时,就会调用doFilter方法
- 6. 在调用doFilter方法时,tomcat会同时创建ServletRequest 和 ServletResponse 和 FilterChain对象, 并通过doFilter传入.
- 7. 如果后面的请求目标资源(jsp,servlet..) 会使用到request,和 response,那么会继续传递
FilterConfig

<filter>
        <filter-name>HspFilterConfig</filter-name>
        <filter-class>com.hspedu.filter.HspFilterConfig</filter-class>
        <!--这里就是给该filter配置的参数-有程序员根据业务逻辑来设置-->
        <init-param>
            <param-name>ip</param-name>
            <param-value>127.0</param-value>
        </init-param>
        <init-param>
            <param-name>port</param-name>
            <param-value>8888</param-value>
        </init-param>
        <init-param>
            <param-name>email</param-name>
            <param-value>hsp@sohu.com</param-value>
        </init-param>
</filter>
<filter-mapping>
        <filter-name>HspFilterConfig</filter-name>
        <url-pattern>/abc/*</url-pattern>
</filter-mapping>public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("HspFilterConfig init() 被调用..");
        //通过filterConfig 获取相关的参数
        String filterName = filterConfig.getFilterName();
        ip = filterConfig.getInitParameter("ip");
        ServletContext servletContext = filterConfig.getServletContext();
        //可以获取到该filter所有的配置参数名
        Enumeration<String> initParameterNames =
                filterConfig.getInitParameterNames();
        //遍历枚举
        while (initParameterNames.hasMoreElements()) {
            System.out.println("名字=" + initParameterNames.nextElement());
        }
        System.out.println("filterName= " + filterName);
        System.out.println("ip= " + ip);
        System.out.println("servletContext= " + servletContext);
    }FilterChain过滤器链

 
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("AFilter---> 线程id=" +
                Thread.currentThread().getId());
        System.out.println("AFilter doFilter 的前置代码...");
        System.out.println("执行 AFilter doFilter()");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("AFilter doFilter 的后置代码...");
    }
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("BFilter---> 线程id=" +
                Thread.currentThread().getId());
        System.out.println("BFilter doFilter 的前置代码...");
        System.out.println("执行 BFilter doFilter()");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("BFilter doFilter 的后置代码...");
    }执行顺序取决于web.xml的配置顺序
注意事项和细节





















