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

Filter对象——FilterConfig

用户在配置filter时,可以使用为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资源进行拦截,那么这组过滤器就称为过滤器链。过滤器的执行顺序和有关(谁在前先执行谁)和过滤器在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: 配置了一个参数



 
  

    default.htm
    index.jsp
  
 
    FirstFilter
    cn.ybzy.mvcproject.filter.FirstFilter

 
    username
    xiongshaowen   
 
  
  
     FirstFilter
     /*                      
     REQUEST   
  


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

例2:禁用浏览器缓存。

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

1.web.xml

    ForbidCacheFilter
    cn.ybzy.mvcproject.filter.ForbidCacheFilter

  
  
     ForbidCacheFilter
     /*
     
  
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:

   
    AutoLoginFilter
    cn.ybzy.mvcproject.filter.AutoLoginFilter

  
  
     AutoLoginFilter
     /index.jsp    
     
  

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

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


    
       

............................................

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

上面在每个jsp页面和servlet页面中进行页面权限设置,会相当麻烦,如:main.jsp中的删除功能,其实可在浏览器输入:http://localhost/mvcproject/delete.udo?id=24可直接删除记录 ,这样显然是不允许的,若网页多,servlet更是多得不得了,每一个都进行的判断显然是不现实的。这里我们专门设置一个过滤器来过滤之。
----思路:
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:

    IsLoginFilter
    cn.ybzy.mvcproject.filter.IsLoginFilter
     
        authority  
        main.jsp,update.jsp,add.jsp,add.udo,query.udo,delete.udo,update.udo,updatedo.udo
     
     
        noautho
        index.jsp,login.udo,logout.udo,drawCheckCode.udo,index.html,error.jsp
     
  
  
     IsLoginFilter
     /*    
     
  

Listener简介

----------监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生时,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。
使用Listener步骤
①通过实现具体接口创建实现类(可实现多个监听器接口)
②配置实现类成为监听器,或者将注册监听器,有两种配置方式:
通过web.xml方式配置,代码演示如下:

com.zrgk.listener.MyListener**

直接用@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:

    cn.ybzy.listener.ServletContextListenerImpl**

或:
@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


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


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


    cn.ybzy.listener.ServletContextAttributeListenerImpl
  
@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:


index2.jsp

测试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:



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

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:



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

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 online =(Map)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 online =(Map)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 online =(Map)application.getAttribute("online");
        if(online != null) {
            online.remove(session.getId());
        }
        application.setAttribute("online", online);  //重新设置全局空间,清除用户
    }

}

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


    <%
       Map online =(Map)application.getAttribute("online");
       for(String str:online.keySet()){
      %>
    
    <%
       }
    %>
    
在线用户的ssid 在线用户的用户名
<%=str%> <%=online.get(str)%>

你可能感兴趣的:(Filter,Listener)