监听器 (Listener)

介绍

监听器用于监听 web 应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。

监听器的作用实际上就是在特定的时间触发监听器提供给我们重写的钩子函数。

分类及使用

按监听对象可分为以下几类:

  • ServletContext

    ServletContextListener 监听 ServletContext 对象的创建和销毁:

    package com.zze.listener;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    
    public class MyServletContextListener implements ServletContextListener {
        @Override
        public void contextInitialized(ServletContextEvent servletContextEvent) {
            /*
             * 初始化时调用
             * */
            System.out.println("初始化");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent servletContextEvent) {
            /*
             * 销毁时调用(服务器正常关闭或从服务器移除项目时)
             * */
            System.out.println("销毁");
        }
    }

    com.zze.listener.MyServletContextListener

    <listener>
        <listener-class>com.zze.listener.MyServletContextListener</listener-class>
    </listener>

    web.xml

    ServletContextAttributeListener 监听对 ServletContext 属性操作:

    package com.zze.listener;
    
    import javax.servlet.ServletContextAttributeEvent;
    import javax.servlet.ServletContextAttributeListener;
    
    public class MyServletContextAttributeListener implements ServletContextAttributeListener {
        @Override
        public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
            System.out.println("添加属性时触发");
        }
    
        @Override
        public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
            System.out.println("移除属性时触发");
        }
    
        @Override
        public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
            System.out.println("修改属性时触发");
        }
    }

    com.zze.listener.MyServletContextAttributeListener

    <listener>
        <listener-class>com.zze.listener.MyServletContextAttributeListener</listener-class>
    </listener>

    web.xml

  • HttpSession

    HttpSessionListener 监听 Session 对象的创建和销毁:

    package com.zze.listener;
    
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    public class MyHttpSessionListener implements HttpSessionListener {
        @Override
        public void sessionCreated(HttpSessionEvent httpSessionEvent) {
            System.out.println("session 创建时调用");
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
            System.out.println("session 销毁时调用");
        }
    }

    com.zze.listener.MyHttpSessionListener

    <listener>
        <listener-class>com.zze.listener.MyHttpSessionListener</listener-class>
    </listener>

    web.xml

    HttpSessionAttributeListener 监听 Session 中的属性操作:

    package com.zze.listener;
    
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    
    public class MyHttpSessionAttributeListener implements HttpSessionAttributeListener {
    
        @Override
        public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("添加属性时触发");
        }
    
        @Override
        public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("移除属性时触发");
        }
    
        @Override
        public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("修改属性时触发");
        }
    }

    com.zze.listener.MyHttpSessionAttributeListener

    <listener>
        <listener-class>com.zze.listener.MyHttpSessionAttributeListener</listener-class>
    </listener>

    web.xml

    HttpSessionBindingListener 监听对象在 Session 中的绑定和解绑操作:

    package com.zze.com.zze.bean;
    
    import javax.servlet.http.HttpSessionBindingEvent;
    import javax.servlet.http.HttpSessionBindingListener;
    
    public class User implements HttpSessionBindingListener {
        private String name;
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public void valueBound(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("被绑定到 session");
        }
    
        @Override
        public void valueUnbound(HttpSessionBindingEvent httpSessionBindingEvent) {
            System.out.println("从 session 中解绑");
        }
    }

    com.zze.bean.User

    package com.zze.servlet;
    
    import com.zze.com.zze.bean.User;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    import java.io.IOException;
    
    @WebServlet("/test")
    public class TestServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            HttpSession session = req.getSession();
            session.setAttribute("user", new User()); // 绑定 触发 valueBound
            session.removeAttribute("user");// 解绑 触发 valueUnbound
        }
    }

    servlet

    HttpSessionActivationListener 监听对象在 Session 中的钝化与活化:

    package com.zze.bean;
    
    import javax.servlet.http.HttpSessionActivationListener;
    import javax.servlet.http.HttpSessionEvent;
    import java.io.Serializable;
    
    public class User implements HttpSessionActivationListener,Serializable {
        private String name;
        private Integer age;
    
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        @Override
        public void sessionWillPassivate(HttpSessionEvent httpSessionEvent) {
            System.out.println("钝化");
        }
    
        @Override
        public void sessionDidActivate(HttpSessionEvent httpSessionEvent) {
            System.out.println("活化");
        }
    }

    com.zze.bean.User

    package com.zze.servlet;
    
            import com.zze.com.zze.bean.User;
    
            import javax.servlet.annotation.WebServlet;
            import javax.servlet.http.HttpServlet;
            import javax.servlet.http.HttpServletRequest;
            import javax.servlet.http.HttpServletResponse;
            import javax.servlet.http.HttpSession;
    
    @WebServlet("/test")
    public class TestServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
            HttpSession session = req.getSession();
            session.setAttribute("user", new User("zhangsan",19)); // 存储到 session
        }
    }

    servlet

    钝化:将内存中的数据序列化保存到硬盘。

    活化:将硬盘中的数据反序列化加载到内存。

    session 的钝化和活化用意何在?

    session 中的值可能会很多,并且可能我们很长一段时间都不会使用这个值,那么可以考虑将 session 中的值存储到硬盘,等要使用的时候再从硬盘中提取,减轻内存压力。

    默认情况下,在服务器正常关闭时会钝化保存在 session 中的数据,而在服务器再次启动时会活化之前钝化的数据。

    配置钝化活化:
    <?xml version="1.0" encoding="UTF-8"?>
    
    <Context>
        <!--maxIdleSwap :设置间隔多久时间钝化,单位为分钟-->
        <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
            <!--directory:session 钝化保存的目录-->
            <Store className="org.apache.catalina.session.FileStore" directory="sessionDir"/>
        </Manager>
    </Context>

    context.xml

    在 tomcat 目录下 /conf/context.xml 中配置以上内容,对托管到当前服务器的所有程序生效。

    在 tomcat 目录下 /conf/Catalina/localhost/context.xml 中配置以上内容,对托管到当前服务器中使用 localhost 访问的程序生效。

    在项目目录下 /META-INF/context.xml 中配置以上内容,仅对当前项目生效。

    注意:因为钝化和活化实际上是序列化和反序列化的过程,所以要钝化的对象类必须实现 Serializable 接口。
  • HttpServletRequest

    ServletRequestListener 监听 Request 对象的创建和销毁:

    package com.zze.listener;
    
    import javax.servlet.ServletRequestEvent;
    import javax.servlet.ServletRequestListener;
    
    public class MyServletRequestListener implements ServletRequestListener {
    
        @Override
        public void requestInitialized(ServletRequestEvent servletRequestEvent) {
            System.out.println("初始化");
        }
    
        @Override
        public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
            System.out.println("销毁");
        }
    
    }

    com.zze.listener.MyServletRequestListener

    <listener>
        <listener-class>com.zze.listener.MyServletRequestListener</listener-class>
    </listener>

    web.xml

    ServletRequestAttributeListener 监听 Request 中的属性操作:

    package com.zze.listener;
    
    import javax.servlet.ServletRequestAttributeEvent;
    import javax.servlet.ServletRequestAttributeListener;
    
    public class MyServletRequestAttributeListener implements ServletRequestAttributeListener {
        @Override
        public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {
            System.out.println("添加属性时触发");
        }
    
        @Override
        public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
            System.out.println("移除属性时触发");
        }
    
        @Override
        public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
            System.out.println("修改属性时触发");
        }
    }

    com.zze.listener.MyServletRequestAttributeListener

    <listener>
        <listener-class>com.zze.listener.MyServletRequestAttributeListener</listener-class>
    </listener>

    web.xml

过滤器 (filter)

介绍

Filter 也称之为过滤器,它是 Servlet 技术中最实用的技术,Web 开发人员通过 Filter 技术,对 web 服务器管理的所有 web 资源:例如 Jsp , Servlet ,  静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现 URL 级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

它主要用于对用户请求进行预处理,也可以对 HttpServletResponse 进行后处理。使用 Filter 的完整流程:Filter 对用户请求进行预处理,接着将请求交给 Servlet 进行处理并生成响应,最后 Filter 再对服务器响应进行后处理。

使用

package com.zze.filter;

import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("前处理");
        filterChain.doFilter(servletRequest, servletResponse); // 如果不调用 后续的过滤器及 servlet 都不会执行
        System.out.println("后处理");
    }

    @Override
    public void destroy() {
        System.out.println("销毁");
    }
}

com.zze.filter.MyFilter

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>com.zze.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!--
    <filter>:指定一个过滤器。
    <filter-name>:用于为过滤器指定一个名字,该元素的内容不能为空。
    <filter-class>:用于指定过滤器的完整的限定类名。
    <init-param>:用于为过滤器指定初始化参数,它的子元素 <param-name> 指定参数的名字,<param-value> 指定参数的值。在过滤器中,可以使用 FilterConfig 接口对象来访问初始化参数。
    <filter-mapping>:用于设置一个 Filter 所负责拦截的资源。一个 Filter 拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
    <filter-name>子元素用于设置 filter 的注册名称。该值必须是在 <filter> 元素中声明过的过滤器的名字
    <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
    <servlet-name>指定过滤器所拦截的 Servlet 名称。
    <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是 REQUEST , INCLUDE , FORWARD 和 ERROR 之一,默认REQUEST。用户可以设置多个 <dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
        REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
        INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
        FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
        ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
-->

web.xml

Filter链:

在一个web应用中,可以开发编写多个 Filter ,这些 Filter 组合起来称之为一个 Filter 链。

web 服务器根据 Filter 在 web.xml 文件中的注册顺序,决定先调用哪个 Filter,当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法。在 doFilter 方法中,开发人员如果调用了 FilterChain 对象的 doFilter 方法,则 web 服务器会检查 FilterChain 对象中是否还有 filter,如果有,则调用第2个 filter ,如果没有,则调用目标资源。

生命周期:
public void init(FilterConfig filterConfig) throws ServletException;// 初始化
/*
和我们编写的 Servlet 程序一样,Filter 的创建和销毁由 WEB 服务器负责。
web 应用程序启动时,web 服务器将创建 Filter 的实例对象,并调用其 init 方法,读取 web.xml 配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter 对象只会创建一次,init 方法也只会执行一次)。
开发人员通过 init 方法的参数,可获得代表当前 filter 配置信息的 FilterConfig 对象。
*/

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException;// 拦截请求
/*
这个方法完成实际的过滤操作。当客户请求访问与过滤器关联的URL的时候,Servlet 过滤器将先执行 doFilter 方法。FilterChain 参数用于访问后续过滤器。
*/

public void destroy();//销毁
/*
Filter 对象创建后会驻留在内存,当 web 应用移除或服务器停止时才销毁。
在Web容器卸载 Filter 对象之前被调用。该方法在 Filter 的生命周期中仅执行一次。
在这个方法中,可以释放过滤器使用的资源。
*/

补充

记住密码自动登录示例

点击下载

过滤器解决乱码

package com.zze.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
/**
 * 统一编码
 */
public class EncodingFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request=(HttpServletRequest) req;
        HttpServletResponse response=(HttpServletResponse) resp;

        chain.doFilter(new MyRequest(request), response);
    }

    @Override
    public void destroy() {

    }

}
class MyRequest extends HttpServletRequestWrapper{
    private HttpServletRequest request;
    private boolean flag=true;

    public MyRequest(HttpServletRequest request) {
        super(request);
        this.request=request;
    }
    @Override
    public String getParameter(String name) {
        if(name==null || name.trim().length()==0){
            return null;
        }
        String[] values = getParameterValues(name);
        if(values==null || values.length==0){
            return null;
        }
        return values[0];
    }

    @Override
    public String[] getParameterValues(String name) {
        if(name==null || name.trim().length()==0){
            return null;
        }
        Map<String, String[]> map = getParameterMap();
        if(map==null || map.size()==0){
            return null;
        }
        return map.get(name);
    }

    @Override
    public Map<String,String[]> getParameterMap() {
        String method = request.getMethod();
        if("post".equalsIgnoreCase(method)){
            try {
                request.setCharacterEncoding("utf-8");
                return request.getParameterMap();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }else if("get".equalsIgnoreCase(method)){
            Map<String,String[]> map = request.getParameterMap();
            if(flag){
                for (String key:map.keySet()) {
                    String[] arr = map.get(key);
                    //继续遍历数组
                    for(int i=0;i<arr.length;i++){
                        //编码
                        try {
                            arr[i]=new String(arr[i].getBytes("iso8859-1"),"utf-8");
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                    }
                }
                flag=false;
            }
            return map;
        }
        return super.getParameterMap();
    }
}

EncodingFilter

javaweb(4)之Listener&Filter的更多相关文章

  1. JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下)

    JavaWeb三大组件(Servlet,Filter,Listener 自己整理,初学者可以借鉴一下) Reference

  2. JavaWeb 三大器--Listener、Filter 和Interceptor 总结

    说明:web.xml的加载顺序是:[Context-Param]->[Listener]->[Filter]->[Servlet],而同个类型之间的实际程序调用的时候的顺序是根据对应 ...

  3. JavaWeb三大组件之一Filter知识总结

    [1] Filter简介    > Filter翻译为中文是过滤器的意思.    > Filter是JavaWeb的三大web组件之一Servlet.Filter.Listener    ...

  4. web.xml中的主要元素说明(listener, filter, servlet)

    web.xml中加载的顺序为:context-param ---> listener ---> filter ---> servlet. listener:主要针对的是对象的操作,如 ...

  5. javaWeb学习之Listener监听

    ] 一.监听器Listener javaEE包括13门规范 在课程中主要学习 servlet技术 和 jsp技术 其中 servlet规范包括三个技术点:servlet  listener  filt ...

  6. web.xml之context-param,listener,filter,servlet加载顺序及其周边

    先以加载spring为例子看看加载顺序的作用: Spring加载可以利用ServletContextListener 实现,也可以采用load-on-startup Servlet 实现,但比如fil ...

  7. servlet,listener,filter,interceptor的关系

    1.servlet:servlet是一种运行服务器端的java应用程序,具有独立于平台和协议的特性,并且可以动态的生成web页面,它工作在客户端请求与服务器响应的中间层.最早支持 Servlet 技术 ...

  8. Introduction of Servlet Filter(介绍javaweb组件之一过滤器filter)

    javaweb的三大组件都需要交给web服务器运行,都需要在web.xml文件中配置. ①Servlet:javax.servlet.Servlet通过http协议接受客户端的请求,并作出响应的Jav ...

  9. JavaWeb基础—监听器Listener

    javaWeb三大组件: servlet listener(用的不多) filter 什么叫监听器: 初次相见:AWT 二次相见:SAX(XML解析时)Bundle 绑定 监听器是一个接口,内容由我们 ...

随机推荐

  1. .NET HttpGet 获取服务器文件下的图片信息 同步和异步方式处理

    /// <summary> /// 项目文件夹下路径 返回流类型数据,如:图片类型 /// </summary> /// <returns></returns ...

  2. MySQL数据库的安装教程及相关问题

    MySQL数据库的安装教程及相关问题 2018-07-13 MySQL数据库的下载及安装教程 问题1:Authentication plugin 'caching_sha2_password' can ...

  3. plsql 通过修改配置文件的方式实现数据库的连接

    查看oracle的安装位置: XP系统: 开始>>所有程序>>>Oracle-OraDb10g_home1>>>配置和移植工具>>>右 ...

  4. 【Qt】信号和槽对值传递参数和引用传递参数的总结

    在同一个线程中 当信号和槽都在同一个线程中时,值传递参数和引用传递参数有区别: 值传递会复制对象:(测试时,打印传递前后的地址不同) 引用传递不会复制对象:(测试时,打印传递前后的地址相同) 不在同一 ...

  5. USB2.0学习笔记连载(一):CY7C68013特性简介

    上一篇博客已经给出了整个视频板卡架构,那么对于USB接口部分需要着重理解和学习. 对于目前来说,若是利用FPGA去模拟USB2.0内核,难度还是挺大的,整个状态的收发都不好控制.现在目前都在使用桥接芯 ...

  6. Direct3D 11 Tutorial 1: Basics_Direct3D 11 教程1:基础

    Github-LearnDirectX-DX3D11 tutorial01 概述 在这第一篇教程中,我们将通过介绍创建最小Direct3D应用程序所必需的元素.每一个Direct3D应用程序必需拥有这 ...

  7. 大华等其他NVR接入海康IPC H.264方法

    有一次遇到这个问题,因为时间急,没有注意,这次一个朋友也遇到这个问题,各种百度,也没有看到答案 只好自己研究了一下,最终发现以下方式来解决 下面办法可以解决海康IPC不能能过ONVIF连接到大华等其他 ...

  8. iOS 库操作

    目录 库操作 主工程和子工程的引用关系 库之间的引用关系 ar命令 nm命令 库操作 主工程和子工程的引用关系 子工程引用主工程中的文件需要在子工程的search path中加入头文件的目录 子工程引 ...

  9. 自己动手为Spark 2.x添加ALTER TABLE ADD COLUMNS语法支持

    SparkSQL从2.0开始已经不再支持ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment], .. ...

  10. 《转载》强大全面的C++框架和库推荐!

    C++ 资源大全 关于 C++ 框架.库和资源的一些汇总列表,内容包括:标准库.Web应用框架.人工智能.数据库.图片处理.机器学习.日志.代码分析等. 标准库 C++标准库,包括了STL容器,算法和 ...