Filter,Listener

Filter简介

Filter,FilterConfig两个接口很重要。
------Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。
----它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理.


image.png

-----它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理。使用Filter的完整流程:
Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Servlet API提供了一个Filter接口,编写的过滤器必须实现该接口。Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,Web服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到过滤的目的.

Filter开发两步走

①编写java类实现Filter接口,并实现其doFilter方法。
②在web.xml文件中对编写的filter类进行注册,并设置它所能拦截的资源。

Filter的生命周期(Filter的创建和销毁由web服务器控制)

①服务器启动的时候,web服务器创建Filter的实例对象,并调用其init方法,完成对象的初始化功能。filter对象只会创建一次,init方法也只会执行一次。
②拦截到请求时,执行doFilter方法。可以执行多次。
③服务器关闭时,web服务器销毁Filter的实例对象。

web.xml配置常用的各节点介绍:

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

Filter对象——FilterConfig

用户在配置filter时,可以使用<init-param>为filter配置一些初始化参数,当web容器实例化Filter对象,调用其 init方法时,会把封装了filter初始化参数的filterConfig对象传递进来。
因此开发人员在编写filter时,通过 filterConfig对象的方法,就可获得:
①String getFilterName():得到filter的名称。
②String getInitParameter(String name):返回在部署描述中指定名称的初始化参数的值。如果不存在返回null.
③Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
④public ServletContext getServletContext():返回Servlet上下文对象的引用。

过滤器链——FilterChain

-----一个web应用中有很多个过滤器对某些web资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和<filter-mapping>有关(谁在前先执行谁)和过滤器在web.xml文件中的配置顺序无关。


image.png

image.png

设计一个中间过滤器类,因为Filter是一个接口,

在每次设计一个实现类时都要写上所有的方法,麻烦,有了该实现类后,我们只建一个子类,重写要用的方法即可,不重写的方法调用即可。如在学习Servlet中那样设计一个中间过渡类那样。见Servlet学习。

public class HttpFilter implements Filter{
   private FilterConfig filterConfig;
   public FilterConfig getFilterConfig() {
       return this.filterConfig;
   }
    @Override
    public void destroy() {
    }
     @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
            doFilter((HttpServletRequest) req, (HttpServletResponse) resp, chain);//request,response都要用到HTTP
        
    }
    /**
     * 这个doFilter方法,是提供给子类覆盖的方法
     * @param req
     * @param response
     * @param chain
     */
    protected  void doFilter(HttpServletRequest req,HttpServletResponse response,FilterChain chain) {
        
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
       this.filterConfig =config;
       init();
        
    }
    /**
     * 这个init方法,是提供给子类覆盖的方法
     */
   protected void init() {
    
        
    }
}

注意:子类创建对象时,系统也是先自动调用父类的无参构造函数和init()方法(Servlet只少这样),所以,当我们创建他的子类时,覆盖父类的init(FilterConfig config)throws ServletException方法时,可能会丢失config,所以我们要重写就写init()方法,这样保证出错的可能性减少许多,或者如果覆盖父类方法时,写上super.init(config);一般情况下我们不太管init。

public class DemoFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse response, FilterChain chain) {
        try {   //异常捕捉。
            chain.doFilter(req,resp);  //放行
        } catch (IOException e) {
        
            e.printStackTrace();
        } catch (ServletException e) {
            
            e.printStackTrace();
        }
    }
//public void init(FilterConfig config) throws ServletException {
    //      super.init(config);
 //   }
}

第一个Filter例子,了解过滤器执行顺序。

包:cn.ybzy.mvcproject.filter

import javax.servlet.Filter;
public class FirstFilter implements Filter {

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("doFilter");
        
    }
      @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("init");
        System.out.println(config.getInitParameter("username"));   //打印web.xml中配置的过滤器参数
        
    }
}

web.xml: 配置了一个参数

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
 
  <welcome-file-list>

    <welcome-file>default.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 <filter>
    <filter-name>FirstFilter</filter-name>
    <filter-class>cn.ybzy.mvcproject.filter.FirstFilter</filter-class>

 <init-param>
    <param-name>username</param-name>
    <param-value>xiongshaowen</param-value>   <!--初始后的config获取它-->
 </init-param>
  </filter>
  <filter-mapping>
     <filter-name>FirstFilter</filter-name>
     <url-pattern>/*</url-pattern>                      <!-- 指定(应用过滤器的页面)拉截的页面 ,拦截所有网页面,可以定义只拉某一个页面,例:/index.jsp-->
     <dispatcher>REQUEST</dispatcher>   <!--指定拦堆的请求类型  -->
  </filter-mapping>
</web-app>

测试:只要TOMCAT启动项目即可在控制台中看到打印的顺序。且默认情况下,拉截所有网页,servlet,静态网页等,当http://localhost:8080/mvcproject/index.jsp是空白页面(原本是登陆网页)
想要放行,必须在doFilter()方法中加:
chain.doFilter(req,resp); //没这句话,过滤器不放行,实际应用中肯定是放行的,因为大多应用不是为了拦截一个页面,而是过滤一些内容如:字符编码,权限控制。

例2:禁用浏览器缓存。

浏览器缓存是浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这就是浏览器缓存。缓存对我们来说又爱又恨。因为实时更新不友好。如我们浏览股票信息时,股票价格是实时更新,有缓存的话,我们看到股票价格不是新的。

1.web.xml
<filter>
    <filter-name>ForbidCacheFilter</filter-name>
    <filter-class>cn.ybzy.mvcproject.filter.ForbidCacheFilter</filter-class>

  </filter>
  <filter-mapping>
     <filter-name>ForbidCacheFilter</filter-name>
     <url-pattern>/*</url-pattern>
     
  </filter-mapping>
2.ForbidCacheFilter.java
package cn.ybzy.mvcproject.filter;
/**
 * 此过滤器是用来禁上浏览器的缓存
 * @author Administrator
 *
 */
public class ForbidCacheFilter extends HttpFilter{
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {
        
         resp.setHeader("Cache-Control", "no-cache");
         resp.setHeader("Pragma", "no-cache");
         resp.setDateHeader("Expires", -1);
         try {
            chain.doFilter(req, resp);
        } catch (IOException e) {
            
            e.printStackTrace();
        } catch (ServletException e) {
            
            e.printStackTrace();
        }
    }

}

例3 改造mvc,自动登录功能。

AutoLoginFilter.java

public class AutoLoginFilter extends HttpFilter {
    @Override
    protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) {

        Cookie[] cookies = req.getCookies();
        String username = null;
        String ssid = null;
        if (cookies != null && cookies.length > 0) { // 如果cookie不存,没必要去做下面的事
            for (Cookie c : cookies) {
                if (c.getName().equals("userKey")) {
                    username = c.getValue();
                }
                if (c.getName().equals("ssid")) {
                    ssid = c.getValue();
                }
            }
            if(username!=null && ssid!=null && ssid.equals(CookieUtils.md5Encrypt(username))) {
                HttpSession session =req.getSession();
                session.setAttribute("user", username);
                try {
                    resp.sendRedirect(req.getContextPath()+"/main.jsp");
                } catch (IOException e) {
                    
                    e.printStackTrace();
                }
            }else {
                try {
                    chain.doFilter(req, resp);
                } catch (IOException e) {
                    
                    e.printStackTrace();
                } catch (ServletException e) {
                    
                    e.printStackTrace();
                }
            }
        } else {
            try {
                chain.doFilter(req, resp); // 记住,放行这句话,要先写,免得忘记了。
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ServletException e) {

                e.printStackTrace();
            }
        }
    }
}
web.xml:
<!-- mvc自动登录过滤器 -->
   <filter>
    <filter-name>AutoLoginFilter</filter-name>
    <filter-class>cn.ybzy.mvcproject.filter.AutoLoginFilter</filter-class>

  </filter>
  <filter-mapping>
     <filter-name>AutoLoginFilter</filter-name>
     <url-pattern>/index.jsp</url-pattern>    <!-- 过滤器应用index.jsp -->
     
  </filter-mapping>

本过滤器对index.jsp起作用。
思路:判断,请求中有没有cookie,有的话,userKey,ssid,是不是对的,对的跳转到main.jsp!同时把userKey值放到session,没有cookie特别是userKey关键cookie,转发它的请求,让页面执行登录页面。
以前是JS代码实现,很low.

-----main.jsp,add.jsp,update.jsp中 获取session的对象,空的话,就跑到index.jsp重新登录,不允许到这儿来

<body>
    <c:if test="${empty sessionScope.user }">
       <c:redirect url="/index.jsp" context="${pageContext.request.contextPath}"/>
</c:if>
............................................
</body>

例4: 对页面进行权限管理过滤器。

上面在每个jsp页面和servlet页面中进行页面权限设置,会相当麻烦,如:main.jsp中的删除功能,其实可在浏览器输入:http://localhost/mvcproject/delete.udo?id=24可直接删除记录 ,这样显然是不允许的,若网页多,servlet更是多得不得了,每一个都进行<c:if>的判断显然是不现实的。这里我们专门设置一个过滤器来过滤之。
----思路:
IsLoginFilter.java
专门其获取web.xml配置的参数,两个参数,分别为:要权限的,不要权限的。不要权限的,对比后直接放行。权限的判断是,京是获取session会话空间里是否有username,有的话,说明已登录,系统给了权限,就要放行。

protected void doFilter(HttpServletRequest req, HttpServletResponse resp, FilterChain chain) throws IOException, ServletException {
        String path = req.getServletPath().substring(1);  //获取Servlet名称如main.jsp,add.udo
       String autho = getFilterConfig().getInitParameter("authority");
       String noautho = getFilterConfig().getInitParameter("noautho");
       String[] strArr = autho.split(",");   //web.xml中Filter的authority参数值为ain.jsp,update.jsp,add.jsp,add.udo,query.udo,delete.udo,update.udo
       String[] noauthoArr = noautho.split(",");
      for(String str:noauthoArr) {
           if(path.equals(str)) {   //如果该问页(index.jsp,index.html,loguout.udo....)是不需要权限的放行。
               chain.doFilter(req, resp);
           }
       }
        HttpSession session = req.getSession();  //获取用户名,如果用户名存在说明有权限
        for(String str:strArr) {
            if(str.equals(path)) {
                String username=(String) session.getAttribute("user");
                if(username!=null) {
                    chain.doFilter(req, resp);
                }else {
                    resp.sendRedirect(req.getContextPath()+"/index.jsp");
                }
            }
        }
      
    }

}

web.xml:
<filter>
    <filter-name>IsLoginFilter</filter-name>
    <filter-class>cn.ybzy.mvcproject.filter.IsLoginFilter</filter-class>
     <init-param>
        <param-name>authority</param-name>  <!--要用户登录后(有权限)的-->
        <param-value>main.jsp,update.jsp,add.jsp,add.udo,query.udo,delete.udo,update.udo,updatedo.udo</param-value>
     </init-param>
     <init-param>
        <param-name>noautho</param-name><!--不要限限的-->
        <param-value>index.jsp,login.udo,logout.udo,drawCheckCode.udo,index.html,error.jsp</param-value>
     </init-param>
  </filter>
  <filter-mapping>
     <filter-name>IsLoginFilter</filter-name>
     <url-pattern>/*</url-pattern>    <!-- 过滤器应用到所有资源中 -->
     
  </filter-mapping>

Listener简介

----------监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生时,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。
使用Listener步骤
①通过实现具体接口创建实现类(可实现多个监听器接口)
②配置实现类成为监听器,或者将注册监听器,有两种配置方式:
通过web.xml方式配置,代码演示如下:
<listener>
<listener-class>com.zrgk.listener.MyListener</lisener-class>**
</listener>
直接用@WebListener注解修饰实现类
常用的Web事件的监听接口如下:
ServletContextListener:用于监听Web的启动及关闭
ServletContextAttributeListener:用于监听ServletContext范围内属性的改变
ServletRequestListener:用于监听用户请求
ServletRequestAttributeListener:用于监听ServletRequest范围属性的改变
HttpSessionListener:用于监听用户session的开始及结束
HttpSessionAttributeListener:用于监听HttpSession范围内的属性改变

1.ServletContextListener 该接口用于监听Web应用的启动与关闭

该接口的两个方法:
contextInitialized(ServletContextEvent event); //启动web应用时调用
contextDestroyed(ServletContextEvent event); //关闭web应用时调用
如何获得application对象:
ServletContext application = event.getServletContext();
代码片段:

@WebListener
public class MyServetContextListener implements ServletContextListener{
//web应用关闭时调用该方法
public void contextDestroyed(ServletContextEvent event){
    ServletContext application = event.getServletContext();
   System.out.println("服务器关闭了");
   String userName = application.getInitParameter("userName");
   System.out.println("关闭web应用的用户名字为:"+userName);
}
//web应用启动时调用该方法
public void contextInitialized(ServletContextEvent event) {
    ServletContext application = event.getServletContext();
  System.out.println("服务器启动了");
   String userName = application.getInitParameter("userName");
   System.out.println("启动web应用的用户名字:"+userName);
  }
}
web.xml:
<listener>
    <listener-class>cn.ybzy.listener.ServletContextListenerImpl</lisener-class>**
</listener>
或:
@WebListener
  测试:只要启动了tomcat服务,就可在控制台上看到找印了
            服务器启动了
            服务器关闭了

2. ServletContextAttributeListener(application)

①该接口 用于监听ServletContext范围(application)内属性的改变.
②该接口的三个方法:
1.attributeAdded(ServletContextAttributeEvent event); //当把一个属性存进application时触发
2.attributeRemoved(ServletContextAttributeEvent event); //当把一个属性从application删除时触发
3.attributeReplaced(ServletContextAttributeEvent event); // 当替换application内的某个属性值时触发
③如何获得application对象:ServletContext application = event.getServletContext();
示例代码:
ServletContextAttributeListenerImpl.java

public class ServletContenxtAttributeListener implements ServletContextAttributeListener{
 /**
     * 在ServletContext范围内--任何网页或Httpservlet中(request,session,application等),添加里属性的时刻,触发该方法
     */
    @Override
    public void attributeAdded(ServletContextAttributeEvent event) {
        System.out.println("ServletContext里添加了属性");
        System.out.println("新添加进来的属性名:"+event.getName());
        System.out.println("新添加进和的属性值:"+event.getValue());
        
    }
    /**
     * 当我们从ServletContext范围内--任何网页或Httpservlet中属性空间里移除属性时触发。
     */
    @Override
    public void attributeRemoved(ServletContextAttributeEvent event) {
        System.out.println("域对象空间里有属性删除了!");
        System.out.println("删除的属性名为:"+event.getName());
        System.out.println("删除的属性值为: "+event.getValue());
    }
    /**
     * ServeltContext域对象里的属性值,被替换的时刻,触发该方法
     */
    @Override
    public void attributeReplaced(ServletContextAttributeEvent event) {
        System.out.println("域对象空间里有属性值,被替换了!");
        System.out.println("被替换的属性名为:"+event.getName());
        System.out.println("被替换的的属性值为: "+event.getValue());
        
    }
}

index.jsp

<body>
<%
   application.setAttribute("name","熊少文");
   application.removeAttribute("name");
%>

</body>

注册监听器:
1.web.xml (或:2)

<listener>
    <listener-class>cn.ybzy.listener.ServletContextAttributeListenerImpl</listener-class>
  </listener>
@WebListener

测试:http://localhost:8080/ListenerWeb/index.jsp
注意:每刷一次网页,是重新添加属性和删除属性,若没有删除属性这一代码,再次刷新网页,是替换属性值。

3.ServletRequestListener与ServletRequestAttributeListener

ervletRequestListener用于监听用户请求。
ServletRequestAttributeListener用于监听request范围内属性的变化。
一。ServletRequestListener两个需要实现的方法
1.requestInitialized(ServletRequestEvent event); //用户请求到达、被初始化时触发
2.requestDestroyed(ServletRequestEvent event); //用户请求结束、被销毁时触发
二。ServletRequestAttributeListener三个需要实现的方法
1.attributeAdded(ServletRequestAttributeEvent event); //向request范围内添加属性时触发
2.attributeRemoved(ServletRequestAttributeEvent event); //从request范围内删除某个属性时触发
3.attributeReplaced(ServletRequestAttributeEvent event); //替换request范围内某个属性值时触发
三。获取reqeust对象
HttpServletRequest req = (HttpServletRequest)event.getServletRequest();

示例:测试请求转发与属性状态改变的情况。

注意:转发也是request的一个属性,不要死板。这里建一个类执行两个接口,不要死板了。
监听器:

//该类执行了两个request监听器
@WebListener
public class ServletRequestListenerImpl implements ServletRequestListener,ServletRequestAttributeListener{
       @Override
    public void requestDestroyed(ServletRequestEvent arg0) {
        System.out.println("一个请求结束时触发!");
    }
       @Override
    public void requestInitialized(ServletRequestEvent arg0) {
        System.out.println("一个新的请求初始时触发!");
        
    }
     @Override
    public void attributeAdded(ServletRequestAttributeEvent event) {
        System.out.println("属性添加时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }
       @Override
    public void attributeRemoved(ServletRequestAttributeEvent event) {
        System.out.println("属性删除时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }

    @Override
    public void attributeReplaced(ServletRequestAttributeEvent event) {
        System.out.println("属性替换时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }
}

转发,index.jsp-->index2.jsp


index.jsp:


<%
   /* application.setAttribute("name","熊少文");
   application.removeAttribute("name"); */
    //request测试,上面是ServletContext的application测试用例:
   request.getRequestDispatcher("/index2.jsp").forward(request,response);
%>


index2.jsp:

<body>
index2.jsp
</body>

测试1:
http://localhost:8080/ListenerWeb/index.jsp 没有加空间变量时结果:

一个新的请求初始时触发!
属性替换时触发:org.apache.catalina.ASYNC_SUPPORTED  ;  true
一个请求结束时触发!

测试2:

index.jsp:


<%
   request.setAttribute("name","cexoit");
   request.getRequestDispatcher("/index2.jsp").forward(request,response);
%>


index2.jsp:


<body>
index2.jsp<br/>
<%
   out.println(request.getAttribute("name"));
%>
</body>

http://localhost:8080/ListenerWeb/index.jsp 加空间变量name转发后时结果:

一个新的请求初始时触发!
属性替换时触发:org.apache.catalina.ASYNC_SUPPORTED  ;  true
属性添加时触发:name  ;  cexoit
一个请求结束时触发!

测试3:

index.jsp:


<%
   request.setAttribute("name","cexoit");
   request.getRequestDispatcher("/index2.jsp").forward(request,response);
%>


index2.jsp:


<body>
index2.jsp<br/>
<%
   request.setAttribute("name", "熊少文");  
   request.setAttribute("name1", "徐会凤");
   out.println(request.getAttribute("name"));
   request.removeAttribute("name");
%>
</body>

http://localhost:8080/ListenerWeb/index.jsp 空间变量添加,删除转发后时结果:

一个新的请求初始时触发!
属性替换时触发:org.apache.catalina.ASYNC_SUPPORTED  ;  true
属性添加时触发:name  ;  cexoit
属性替换时触发:name  ;  cexoit
属性添加时触发:name1  ;  徐会凤
属性删除时触发:name  ;  熊少文
一个请求结束时触发!

4. HttpSessionListener与HttpSessionAttributeListener

一。HttpSessionListener监听用户session的开始与结束。
1.HttpSessionListener监听用户session的开始与结束。
2.HttpSessionAttributeListener****监听HttpSession范围(session)内的属性的改变。
二。HttpSessionAttributeListener****监听HttpSession范围(session)内的属性的改变。
HttpSessionAttributeListener要实现的方法:
1.attributeAdded(HttpSessionBindingEvent event) ; //向session范围内添加属性时触发
2.attributeRemoved(HttpSessionBindingEvent event); //删除session范围内某个属性时触发
3.attributeReplaced(HttpSessionBindingEvent event); //替换session范围内某个属性值时触发**
如何得到session对象
HttpSession session = event.getSession();
该监听器与request监听器的用法差不多,但要注意会话有自已的ID

@WebListener
public class HttpSessionLinstenerImpl implements HttpSessionListener,HttpSessionAttributeListener {

    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        System.out.println("属性添加时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
        System.out.println("属性删除时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
        System.out.println("属性替换时触发:"+event.getName()+ "  ;  "+event.getValue());
        
    }

    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        System.out.println("一个会话开始了!");
        System.out.println(arg0.getSession().getId()); //打印会话id
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent arg0) {
        System.out.println("一个会话结束了!");
        
    }

}

测试:
http://localhost:8080/ListenerWeb/index.jsp
若想短时间内看到结束效果,要设置会话生命周期为几秒钟,因为默认为20分钟,等死人了,但又不能设太短,用户登陆成功后,稍微等一下又要重新登陆,这是不可能做的,除非自已原意这样折磨,受孽狂吧。
在那设置都行,不一定是jsp页面中。

<%
   /* application.setAttribute("name","熊少文");
   application.removeAttribute("name"); */
   
   
   //request测试:
   /* request.setAttribute("name","cexoit");
   request.getRequestDispatcher("/index2.jsp").forward(request,response); */
   
   session.setMaxInactiveInterval(1);// 设置会话生命周期为1秒。
%>

综合举例1:监听器实现显示在线用户状态。session监听器实现

mvcproject项目中:
思路:1.从登陆页面登入成功后,UserController--login会注入一个用户信息进到session空间里,

req.getSession().setAttribute("user", user.getUsername()); // 登 陆成功,把用户信息放到session空间里
req.getRequestDispatcher("/main.jsp").forward(req, resp);

2.OnlineListener实现HttpSessionAttributeListener,HttpSessionListener接口,首先执行sessionCreated()方法,说明会话建立,但此时没有添加属性,application是空的。当1.的session属性添加时触了attributeAdded()方法会被触发,执行,产生一个online对象(Map键值对集合),键为session id有唯一性,如果不用到sessionID ,会产生很多相同的记录数据。

public class OnlineListener implements HttpSessionAttributeListener,HttpSessionListener{
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        HttpSession session = event.getSession();
        ServletContext application =session.getServletContext();//因为session会话空间会随时清空,所以用到application
        @SuppressWarnings("unchecked")
        Map<String,String> online =(Map<String, String>)application.getAttribute("online");
        if(online == null) {
            online = new HashMap<>();
        }
        //UserController.java中login()方法中,登 陆成功注入了用户信息进session空间里了,只要有session添加就会触发该方法
        online.put(session.getId(), session.getAttribute("user").toString());
        application.setAttribute("online", online);
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
        // TODO Auto-generated method stub
        
    }
    
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        HttpSession session =event.getSession();
        ServletContext application = session.getServletContext();
        @SuppressWarnings("unchecked")
        Map<String,String> online =(Map<String, String>)application.getAttribute("online");
        if(online == null) {
            online = new HashMap<>();
        }
        String username=(String) session.getAttribute("user");
        username = username==null?"访客":username;
        online.put(session.getId(), username);
        application.setAttribute("online", online);
    }
    /**
     * 会话结束后,清理
     */
    @SuppressWarnings({ "unchecked", "null" })
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        
        HttpSession session =event.getSession();
        ServletContext application = session.getServletContext();
        Map<String,String> online =(Map<String, String>)application.getAttribute("online");
        if(online != null) {
            online.remove(session.getId());
        }
        application.setAttribute("online", online);  //重新设置全局空间,清除用户
    }

}

3.由UserController转送到main.jsp显示用户状态。

<table border="1" cellpadding="0" cellspacing="0" style="width:80%;margin:0 auto;">
    <tr>
        <td>在线用户的ssid</td>
        <td>在线用户的用户名</td>
    </tr>
    <%
       Map<String,String> online =(Map<String,String>)application.getAttribute("online");
       for(String str:online.keySet()){
      %>
    <tr>
    <td><%=str%></td>
    <td><%=online.get(str)%></td>
    </tr>
    <%
       }
    %>
    </table>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Filter和Listener 1. Filter 概念:Filter(过滤器),当访问服务器资源时,过滤器可以将...
    青丶空阅读 1,535评论 2 0
  • 1. Filter Filter功能:在HttpServletRequest到达Servlet之前,拦截客户的Ht...
    皇天阅读 1,297评论 0 0
  • 一、Filter 过滤器简介 过滤器也称之为拦截器,是Servlet 2.3规范新增的功能。Filter是Serv...
    辽A丶孙悟空阅读 4,729评论 0 16
  • Servlet进阶 1.过滤器-Filter 1.1.什么过滤器? 过滤器,即具有拦截过滤的作用的器具。例如:筛子...
    艾特小师叔阅读 1,450评论 0 0
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 128,054评论 2 7

友情链接更多精彩内容