监听器 (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. EPOLL AND Nonblocking I/O

    https://medium.com/@copyconstruct/nonblocking-i-o-99948ad7c957 https://idndx.com/2014/09/02/the-impl ...

  2. 2018年中国C++大会详细日程+报名

    http://purecpp.org/detail?id=2050  

  3. LoRa基础

    一.LoRa技术 LoRa 是LPWAN通信技术中的一种,是美国Semtech公司采用和推广的一种基于扩频技术的超远距离无线传输方案.这一方案改变了以往关于传输距离与功耗的折衷考虑方式,为用户提供一种 ...

  4. 在Java路上,我看过的一些书、源码和框架(转)

    原文地址:http://www.jianshu.com/p/4a41ee88bd82 物有本末,事有终始,知所先后,则近道矣 面试经历 关于Java面试,你应该准备这些知识点关于Java面试,你应该准 ...

  5. Android跳转到应用商店的APP详情页面,以及 Google GMS 各个apk的包

    转自:http://www.jianshu.com/p/a4a806567368 需求: 从App内部点击按钮或链接,跳转到应用商店的某个APP的详情页面.让用户 下载 或 评论. 实现: /** * ...

  6. Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:compile (default-compile) on project demo: Fatal error com piling: 无效的标记: -parameters

    背景:本项目使用JDK1.8 编译maven工程的时候出现如下错误: Failed to execute goal org.apache.maven.plugins:maven-compiler-pl ...

  7. css如何实现一个元素高度固定宽度按比例显示?

    用padding-top百分比可以实现宽度固定高度按比例展示,现在的需求是对一个video视频的盒子div高度是固定的,宽度如何按比例展示? 解决后效果如图: 红框标注的即是我在上面高度比例固定的范围 ...

  8. node常见操作命令

    进入REPL环境(READ  EVAL  PRINT  LOOP) 接收用户输入 执行用户输入 打印执行结果到控制台 循环到下一次 打开终端,键入node进入命令交互模式,可以输入一条代码语句后立即执 ...

  9. TortoiseGit功能介绍

    TortoiseGit功能介绍 使用方便 强大的提交对话框 每个项目设置 最小日志消息长度,以避免意外提交空日志消息 用于拼写检查的语言 与问题跟踪系统集成 有用的工具 有多种语言版本 Tortois ...

  10. Relation Extraction中SVM分类样例unbalance data问题解决 -松弛变量与惩罚因子

    转载自:http://blog.csdn.net/yangliuy/article/details/8152390 1.问题描述 做关系抽取就是要从产品评论中抽取出描述产品特征项的target短语以及 ...