# 过滤器和监听器

Servlet,Filter和Listener是JavaWeb的三大组件:

  • servlet扮演了重要的角色,作为一个中转处理的容器,他连接了客户端和服务器端的信息交互和处理。客户端发送请求,传递到servlet容器,而servlet将数据转换成服务器端可以处理的数据再发送给服务器端,再数据处理之后,再传递到servlet容器,servlet再转译到客户端,完成了一次客户端和服务器端的信息交互。
  • filter用于拦截用户请求,在服务器作出响应前,可以在拦截后修改request和response。
  • listener通常可以统计在线人数(HttpSessionLisener),加载初始化信息(ServletContextListener),统计网站访问量和实现访问监控。

# 过滤器

Filter(过滤器)用于拦截用户请求,在服务器作出响应前,可以在拦截后修改request和response,一般完成登录验证、统一编码处理、敏感字符过滤等操作。使用过滤器步骤为:

  1. 定义一个类,实现接口Filter
  2. 复写方法
  3. 配置拦截路径:
    1. web.xml:

      <filter>
          <filter-name>filter1</filter-name>
          <filter-class>SimpleLogin.service.FilterTest</filter-class>
      </filter>
      <filter-mapping>
          <filter-name>filter1</filter-name>
          <!-- 拦截路径 -->
          <url-pattern>/*</url-pattern>
      </filter-mapping>
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
    2. 注解:@WebFilter("/*")

# 生命周期

过滤器执行过程为:

  1. 执行过滤器
  2. 执行放行后的资源
  3. 回来执行过滤器放行代码下边的代码

当有多个过滤器时,比如有两个过滤器:过滤器1和过滤器2,它们的执行过程如下:

  1. 过滤器1
  2. 过滤器2
  3. 资源执行
  4. 过滤器2放行后代码
  5. 过滤器1放行后代码

那么如何确定过滤器执行先后顺序问题呢?

  1. 注解配置:按照类名的字符串比较规则比较,值小的先执行,比如AFilter 和 BFilter,就先执行AFilter了。
  2. web.xml配置: <filter-mapping>谁定义在上边,谁先执行。

Filter类中的方法的声明周期为:

  1. init:在服务器启动时,会创建Filter对象,然后调用init方法,只执行一次,常用于加载资源。
  2. doFilter:每一次请求被拦截资源时,就会执行,它能执行多次。
  3. destroy:如果服务器是正常关闭,则会执行destroy方法,只执行一次,常用于释放资源。

# 拦截配置

关于拦截路径的配置,有四种情况:

  1. 具体资源路径:/index.jsp 。访问index.jsp资源时,过滤器才会被执行
  2. 拦截目录: /user/* 。访问/user下的所有资源时,过滤器都会被执行
  3. 后缀名拦截: *.jsp 。访问所有后缀名为jsp资源时,过滤器都会被执行
  4. 拦截所有资源:/* 。访问所有资源时,过滤器都会被执行

关于拦截方式的配置,有五种情况:

  1. REQUEST:默认值。浏览器直接请求资源
  2. FORWARD:转发访问资源
  3. INCLUDE:包含访问资源
  4. ERROR:错误跳转资源
  5. ASYNC:异步访问资源

有两种方式配置拦截方式:

  • 在注解中需要设置dispatcherTypes属性:

    @WebFilter(value="/*",dispatcherTypes ={ DispatcherType.FORWARD,DispatcherType.REQUEST})

  • 在web.xml中设置<dispatcher></dispatcher>标签即可。

示例为:

package SimpleLogin.service;

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.http.HttpServletRequest;

/**
 * Servlet Filter implementation class FilterTest
 */
//访问所有资源前访问该过滤器
@WebFilter("/*")
public class FilterTest implements Filter {

    /**
     * Default constructor.
     */
    public FilterTest() {
        // 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
        HttpServletRequest request2 = (HttpServletRequest)request;
        System.out.println("filterTest被执行了....访问URL为:"+request2.getRequestURL());
        // 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
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# Listener

# 基本概念

监听器实现事件监听机制,监听机制相关概念为:

  • 事件:一件事情
  • 事件源:事件发生的源头
  • 监听器:对事件进行监听的一个对象
  • 注册监听:将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码

它的作用为:

  1. 监听web对象创建与销毁
  2. 监听web对象的属性变化
  3. 监听session绑定javaBean操作

监听器的创建步骤如下:

  1. 创建监听器接口
  2. 重写接口方法
  3. 配置web.xml
  4. 测试监听器

# 监听类

Javaweb中常见的监听web对象为HttpServletRequest,HttpSession,ServletContext。

  1. 监听web对象的创建于销毁

    监听器 监听对象
    ServletContextListener ServletContext
    HttpSessionListener Httpsession
    ServletRequestListener HttpServletRequest
  2. 监听web对象属性的变化

    监听器 监听对象
    ServletContextAttributeListener ServletContex
    HttpSessionAttributeListener Httpsession
    ServletRequestAttributeListener HttpServletRequest
  3. 监听session绑定javaBean(向session中set对象的时候触发)

    • HttpSessionBindingListener
    • HttpSessionActivationListener

# 示例

下面以ServletContextListener为例,来说明监听器的使用,它是用来监听ServletContext对象的创建和销毁。它有两个方法:

  • void contextInitialized(ServletContextEvent sce) :ServletContext对象创建后会调用该方法
  • void contextDestroyed(ServletContextEvent sce) :ServletContext对象被销毁之前会调用该方法

使用步骤:

  1. 定义一个类,实现ServletContextListener接口
  2. 复写方法
  3. 配置:
    1. web.xml

      <listener>
        <listener-class>cn.itcast.web.listener.ContextLoaderListener</listener-class>
      </listener>
      
      1
      2
      3
    2. 注解:

      • @WebListener

示例如下:

  1. 在src目录下需要有一个applicationContext文件作为全局配置文件。

  2. 配置文件中需要指定初始化参数:

    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/classes/applicationContext.xml</param-value>
    </context-param>
    
    1
    2
    3
    4
  3. ListenerTest.java文件内容为:

    package SimpleLogin.service;
    import java.io.FileInputStream;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * Application Lifecycle Listener implementation class ListenerTest
     *
     */
    @WebListener
    public class ListenerTest implements ServletContextListener {
    
        /**
         * Default constructor.
         */
        public ListenerTest() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see ServletContextListener#contextDestroyed(ServletContextEvent)
         *      在服务器关闭后,ServletContext对象被销毁。当服务器正常关闭后该方法被调用
         */
        public void contextDestroyed(ServletContextEvent sce) {
            // TODO Auto-generated method stub
            System.out.println("ServletContext对象被销毁了。。。");
        }
    
        /**
         * @see ServletContextListener#contextInitialized(ServletContextEvent)
         *      监听ServletContext对象创建的。ServletContext对象服务器启动后自动创建。
         */
        public void contextInitialized(ServletContextEvent sce) {
            // TODO Auto-generated method stub
            // 加载资源文件
            // 1.获取ServletContext对象
            ServletContext servletContext = sce.getServletContext();
    
            // 2.加载资源文件
            String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
    
            // 3.获取真实路径
            String realPath = servletContext.getRealPath(contextConfigLocation);
    
            // 4.加载进内存
            try {
                FileInputStream fis = new FileInputStream(realPath);
                System.out.println(fis);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("ServletContext对象被创建了。。。");
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57