JavaEE-过滤器和监听器 案例分析


过滤器和监听器

本文主要介绍过滤器和监听器的编程接口、基本结构、信息配置、部署和运行,最后通过案例说明过滤器和监听器的典型应用。

什么是过滤器

过滤器是web服务器上的组件,它们对客户和资源之间的请求和响应进行过滤。
过滤器的工作原理是:当servlet容器接收到对某个资源的请求,它要检查是否有过滤器与之关联。如果有过滤器与该资源关联,servlet容器将把该请求发送给过滤器。在过滤器处理完请求后,它将做下面3件事:
• 产生响应并将其返回给客户;
• 如果有过滤器链,它将把(修改过或没有修改过)请求传递给下一个过滤器;
• 将请求传递给不同的资源。
当请求返回到客户时,它是以相反的方向经过同一组过滤器返回。过滤器链中的每个过滤器够可能修改响应。
过滤器API主要包括:Filter、FilterConfig和FilterChain接口。

工作原理图:
工作原理

过滤器编程接口

进行过滤器编程用到javax.servlet.jar中的一组接口和类,下表只列出了与过滤器设计有关的三个重要接口,而与Servlet编程有关的接口、类未列。

功能 类和接口
Filter实现 javax.servlet.Filter
Filter配置 javax.servlet.FilterConfig
Filter链 javax.servlet.FilterChain

接口Filter的主要方法

  1. init()方法
    方法原型:
    public void init(FilterConfig filterConfig) throws ServletException{}
    该方法用于初始化过滤器,并获取web.xml文件中配置的过滤器初始化参数,默认情况下,服务器启动时就会加载过滤器,init方法就会执行。
    该方法有一个FilterConfig类型的参数,利用它可以获取在web.xml中设置的过滤器的初始化参数值。获取初始参数值的方法为:
    public String getInitParameter(String paraName)
    过滤器的信息配置将在稍后介绍。
  2. doFilter()方法
    方法原型:
    public void doFilter(ServletRequest request,  ServletResponse response,FilterChain filterChain) throws IOException,ServletException{}

当请求地址和过滤地址匹配时将进行过滤操作,该方法被执行。
第1个参数为ServletRequest对象,此对象给过滤器提供了对请求信息(包括表单数据、Cookie和HTTP请求头)的完全访问。
第2个参数为ServletResponse,用于响应请求。
第3个参数为FilterChain对象,使用该参数对象调用Servlet、JSP页面或者过滤器链中的下一个过滤器。
调用方法为:

public void doFilter(ServletRequest request, ServletResponse response)
  1. destroy()方法
    方法原型:
    public void destroy()
    Servlet容器在销毁过滤器实例前调用该方法,这个方法中可以释放Servlet过滤器占用的资源。
    性质等同于Servlet的destory()方法。这些方法构成了过滤器对象的生命周期:创建、执行过滤方法、销毁。

    设计过滤器

    过滤器的设计需要实现Filter接口,并要根据处理的功能需要,实现Filter接口中的上述3个方法。

在开发环境下创建过滤器是很方便的,其创建过程:

  • 创建实现Filter接口的类:在项目的src下,创建一个或多个过滤器,并采用“包”结构的方式组织所有的过滤器。
  • 实现init方法,读取过滤器的初始化函数。
  • 将过滤行为放入doFilter()方法中:实现doFilter(),完成该过滤器所需要过滤功能。
  • 调用filterchain对象的doFilter方法:filterChain对象是过滤器接口的doFilter方法的一个参数,调用Filterchain的doFilter方法时,下一个关联的过滤器将被调用,若没有其他与Servlet或JSP相关联的过滤器,就调用Servlet或JSP本身。
  • 将过滤器与特定的Servlet或JSP页面关联:使用部署配置文件(web.xml)中的filter元素和filter-mapping元素。
    实例1:编写一个过滤器审计用户对资源的访问
  1. 创建实现Filter接口的类AuditFilter:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    package filter;
    
    import java.io.IOException;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class AuditFilter implements Filter {
    
        protected FilterConfig config;
    
        public void init(FilterConfig filterConfig)
                throws ServletException {
            this.config = filterConfig;
        }
    
        public void doFilter(ServletRequest request,
                ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
    
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
    
            String addr = req.getRemoteAddr();
            String user = req.getRemoteHost();
            config.getServletContext().log("RemoteAddress:" + addr
                    + ",RemoteHost:" + user);
            chain.doFilter(req, res);
        }
    
        public void destroy() {
        }
    }
  2. 在web.xml中配置过滤器
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
        <filter>
            <filter-name>AuditFilter</filter-name>
            <filter-class>filter.AuditFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>AuditFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <session-config>
            <session-timeout>
                30
            </session-timeout>
        </session-config>
    </web-app>
    有的编译器会在创建过滤器的时候就把web.xml配置好了
  3. 运行项目,并查看日志文件
    访问该应用程序中的任何一个资源,如使用下面的URL访问index.html:
    http://localhost:8080/JavaEE-2-FilterListener/index.html
    然后打开\logs目录中的localhost.2019-04-13.log文件中有下面一行(访问多个资源就会有多行)
    CATALINA_HOME即tomcat的安装位置
    在这里插入图片描述

    什么是监听器

    监听器是Web应用开发的一个重要组成部分。通过它可以监听Web应用的上下文信息、Servlet请求信息、Servlet会话信息,并自动根据不同情况,在后台调用相应的处理程序。利用监听器来对Web应用进行监听和控制的,极大地增强了Web应用的事件处理能力。
    监听器运行机制:当服务器启动时,监听器自动加载(执行构造函数),特定事件发生时,容器自动调用相应监听器中对应的事件处理方法。

    监听器编程接口

    监听器编程要用到javax.servlet.jar中的一组监听接口和事件类。根据监听对象的不同,监听器划分为3种:
    (1)ServletContext事件监听器:用于监听应用程序环境对象。
    (2)HttpSession事件监听器:用于监听用户会话对象。
    (3)ServletRequest事件监听器:用于监听请求消息对象。
    在Servlet 2.4规范中共定义了6种事件类型和8个事件监听器接口,它们可以处理三种对象上的事件:
.
监听器接口与事件类
监听对象 监听器接口 监听事件
ServletContext ServletContextListener ServletContextEvent
ServletContextAttributeListener ServletContextAttributeEvent
HttpSession HttpSessionListener HttpSessionEvent
HttpSessionActivationListener
HttpSessionAttributeListener HttpSessionBindingEvent
HttpSessionBindingListener
ServletRequest ServletRequestListener ServletRequestEvent
ServletRequestAttributeListener ServletRequestAttributeEvent

设计监听器

  1. 实现合适的接口:监听器需要根据监听对象的不同,实现某个监听接口。
  2. 实现有关事件的方法:按所选择的监听器接口,实现该接口中的有关的方法。
  3. 获取对重要Web应用对象的访问:在事件处理方法中,可能会用到9个重要对象(分为3类):
    servlet上下文、变化后的servlet上下文属性的名称、变化后的servlet上下文属性的值。
    会话对象、变化后的会话属性的名称、变化后的会话属性的值。
    请求对象、变化后的请求对象属性的名称、变化后的请求对象属性的值。
  4. 使用这些对象:需要根据具体应用,选择有关的对象。例如,对于servlet上下文,可能会读取初始化参数(getInitParameter方法),存储数据供以后使用(setAttribute方法)和读取原先存储的数据(getAttribute方法)。
  5. 配置监听器:在web.xml中,利用listener元素和listener-class元素完成配置。
  6. 提供任何需要的初始化参数:servlet上下文监听器一般先读取servlet上下文的初始参数,并将这些参数作为所有servlet或JSP都可以使用的数据基础。在web.xml中使用context-param元素提供这些初始化参数的名称和值。

    实例:编写一个HttpSession事件监听器用来记录当前在线人数

【分析】 在网站中经常需要进行在线人数的统计。过去的一般做法是结合登录和退出功能,即当用户登录的时候计数器加1,当用户点击退出按钮时计数器减1。这种处理方式存在两个缺点:一是用户正常登录后,可能会忘记点击退出按钮,而直接关闭浏览器,导致计数器减1的操作不会执行;二是该方法无法统计非登录的在线人数。
可以利用监听器来解决这个问题,实现更准确的在线人数统计功能。当一个浏览器第一次访问网站的时候,服务器会新建一个HttpSession对象,并触发HttpSession创建事件,如果注册了HttpSessionListener事件监听器,则会调用HttpSessionListener事件监听器的sessionCreated方法。相反,当这个浏览器用户注销或访问结束超时的时候,服务器会销毁相应的HttpSession对象,触发HttpSession销毁事件,同时调用所注册HttpSessionListener事件监听器的sessionDestroyed方法。这样,我们只需要在HttpSessionListener实现类的sessionCreated方法中让计数器加1,在sessionDestroyed方法中让计数器减1,就可实现网站在线人数的统计功能。

  1. 设计监听器类:OnlineListener.java
    在这里插入图片描述
    在这里插入图片描述

    package listener;
    
    import javax.servlet.ServletContextListener;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    /**
     * Web application lifecycle listener.
     *
     * @author YU
     */
    public class OnlineListener implements ServletContextListener, HttpSessionListener {
    
        private static int count = 0;
    
        @Override
        public void sessionCreated(HttpSessionEvent se) {
            count++;
            se.getSession().getServletContext().setAttribute(
                    "onlineCount", new Integer(count));
    
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent se) {
            count--;
            se.getSession().getServletContext().setAttribute(
                    "onlineCount", new Integer(count));
    
        }
        
        public static int getOnlineCount(){
            return count;
        }
    }
    
    
  2. 注册事件监听器
    修改web.xml文件,添加以下配置代码 :

    <listener>
        <listener-class>listener.OnlineListener</listener-class>
    </listener>

有的编译器会在创建监听器的时候就把web.xml配置好了。

  1. 显示在线人数的页面OnlineCount.jsp
    <%-- 
        Document   : OnlineCount
        Created on : 2019-4-13, 10:27:24
        Author     : YU
    --%>
    
    <%@page import="listener.OnlineListener"%>
    <%@ page  pageEncoding="UTF-8" %>
    <html>
        <head><title>在线人数显示页面</title>  </head>
        <body> 
            <h2>当前的在线人数:<%=OnlineListener.getOnlineCount() %></h2>
        </body>
    </html>
    
  2. 运行结果:
    在这里插入图片描述

本文介绍了过滤器和监听器。过滤器主要用来拦截用户请求,实现如权限检查、编码转换、加密等通用的“横向”模块;监听器主要用来监听Web应用的上下文信息、Servlet请求信息、Servlet会话信息,并根据不同的情况,在后台调用相应处理程序。给出了过滤器和监听器的设计方法及其应用案例。
项目文件已上传百度云:https://pan.baidu.com/s/1lycQKh2ZQO0K2VAmf7J6vQ


文章作者: 小林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 小林 !
评论
  目录