JavaEE--监听器(九)

一、监听器简介

监听器就是一个Java程序,功能是监听另一个java对象变化(方法调用、属性变更)。

二、实现:

写一个类实现响应的接口
  注册监听器利用web.xml或注解
8个监听器,分为了3种:

  1. 用来监听三大作用域的创建和销毁的监听器(除了page域)
    A. ServletContextListener 用来监听ServletContext对象创建和销毁的监听器
    创建:服务器启动,web应用加载后立即创建代表当前web应用的ServletContext对象
    销毁:服务器关闭或web应用被移除出容器时,随着web应用的销毁而销毁
    实现接口:
/**
 *使用注解配置监听
 *用来监听 servletCcontext创建和销毁
 */
@WebListener
public class TestListener implements ServletContextListener {
    public TestListener() {
    }
    /**
     * 销毁
     */
    public void contextDestroyed(ServletContextEvent arg0)  { 
         System.out.println("servletContext 被销毁了"+arg0.getServletContext());
    }
    /**
     * 初始化
     */
    public void contextInitialized(ServletContextEvent arg0)  { 
        System.out.println("servletContext 被创建出来了"+arg0.getServletContext().getContextPath());
    }
}

注册 在web.xml 配置

<listener>
        <listener-class> com.neuedu.Listener.TestListener</listener-class>
</listener>

B. HttpSessionListener 用来监听HttpSession对象创建和销毁的监听器
创建:第一次调用request.getSession方法时创建代表当前会话的session对象 。
销毁:超过30分钟没人用销毁(可以在web.xml通过session-timeout标签修改时间)/调用invalidate方法自杀/服务器非正常关闭时随着web应用的销毁而销毁,如果服务器是正常关闭会被钝化起来。
示例:

@WebListener
public class Test implements HttpSessionListener {
    public Test() {
    }
    public void sessionCreated(HttpSessionEvent arg0)  { 
        System.out.println("Session创建");
    }
    public void sessionDestroyed(HttpSessionEvent arg0)  { 
         System.out.println("Session销毁");
    }
}

当服务器正常关闭时,还存活着的session会随着服务器的关闭被以文件的形式存储在tomcat的work目录下,这个过程叫做session的钝化 。
当服务器再次正常开启时,服务器会找到之前的SESSIONS.ser文件从中恢复之前保存起来的session对象这个过程叫做session的活化 。
想要随着Session被钝化活化的对象(一般是bean)它的类必须实现Serializable接口。
示例:
编写实体类:

/**
 * 
 * @类名: Users
 * @描述: 必须实现序列化接口
 */
public class Users implements HttpSessionActivationListener, Serializable {
    private String name;
    private int age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Users() {

    }
    @Override
    public void sessionDidActivate(HttpSessionEvent arg0) {
         System.out.println(arg0.getSession().getId()+"被活化");  

    }
    @Override
    public void sessionWillPassivate(HttpSessionEvent arg0) {
         System.out.println(arg0.getSession().getId()+"被钝化");  
    }
}

在Server.xml中配置:

<Context docBase="webweb" path="/webweb" reloadable="true"
    source="org.eclipse.jst.jee.server:webweb">
    <Manager className="org.apache.catalina.session.PersistentManager"
        saveOnRestart="true" maxActiveSessions="1">
        <Store className="org.apache.catalina.session.FileStore"
            directory="d:/a">
        </Store>
    </Manager>
</Context>
 className   不能变   
 saveOnRestart ="true"  能够进行存储  
 maxActiveSessions="n"  n为最大的session数量  
directory为存储路径

测试:

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         Users users = new Users(); 
         HttpSession session=request.getSession();
         session.setAttribute("users",users);   
    }
测试结果
测试结果

C. ServletRequestListener 用来监听ServletRequest对象创建和销毁的监听
创建:请求开始创建代表请求的request对象
销毁:请求结束时代表请求的request对象销毁

1) 用来监听三大作用域中属性变化的监听器
ServletContextAttributeListener
/**
 * 
 *ServletContext属性监听
 */
@WebListener
public class TestAttrListener implements ServletContextAttributeListener {
    public TestAttrListener() {

    }
    /**
     * 添加属性
     */
    public void attributeAdded(ServletContextAttributeEvent arg0) {
        System.out.println("属性被加入到了域中" + arg0.getName() + ":" + arg0.getValue());
    }
    /**
     * 移除属性
     */
    public void attributeRemoved(ServletContextAttributeEvent arg0) {
        System.out.println("属性被移除出了域中" + arg0.getName() + ":" + arg0.getValue());
    }

    /**
     * 替换属性
     */
    public void attributeReplaced(ServletContextAttributeEvent arg0) {
        System.out.println("属性被替换在域中" + arg0.getName() + ":" + arg0.getValue() + ":"
                + arg0.getServletContext().getAttribute(arg0.getName()));
    }
} 

其中setvlet中代码核心为:
设置与改变属性

this.getServletContext().setAttribute("age", 23);
this.getServletContext().setAttribute("age", 24);
this.getServletContext().removeAttribute("age");
 
//下面这两个方法 和上面的类似 
HttpSessionAttributeListener 
ServletRequestAttributeListener
2) 使javabean自己感知自己在Session中状态变化的监听器,这两个监听器很特殊,不需要自己去写类实现也不需要在web.xml中注册,只要使javabean实现这个接口就能起作用

javabean 在session有下面这四种状态变化,两个监听器
1.HttpSessionBindingListener
javabean被绑定到session中

sessionDidActive(HttpSessionBindingEvent event)

javabean被移除绑定从session中

valueUnbound(HttpSessionBindingEvent event)方法

2.HttpSessionActivationListener
javabean随着session被钝化

sessionWillPassivate(HttpSessionBindingEvent event)

javabean随着session被活化

sessionDidActive(HttpSessionBindingEvent event)

三、在线人数统计

管理session,如果session销毁了就减少,如果登陆用户了就新增一个,但是如果是用户非法退出,如:未注销,关闭浏览器等,这个用户的session是管理不到的,可以使用HttpSessionListener接口或HttpSessionBindingListener接口来实现,通过监听session的新建和销毁来控制

  1. 登陆页面login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>登录</title>
</head>
<body>
    <form action="LoginServlet" method="post">
        用户名:
        <input type="text" name="username" /> <br /> 
        <input type="submit" value="登录" />
    </form>
</body>
</html> 
  1. 点击登陆后跳转的LoginServlet.java
/**
 * 登录与注销Servlet
 */
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    public LoginServlet() {
        super();
    }
    /**
     * 注销
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();
        // 取得登录的用户名
        String username = (String) session.getAttribute("username");
        // 销毁session
        session.invalidate();
        ServletContext application = request.getServletContext();
        // 从在线列表中删除用户名
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        onlineUserList.remove(username);
        // 成功
        response.sendRedirect("index.jsp");
    }

    /**
     * 登录
     * 
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         request.setCharacterEncoding("UTF-8");
         // 取得登录的用户名
         String username = request.getParameter("username");
         // 把用户名保存进session
         HttpSession session = request.getSession();
         session.setAttribute("username", username);
         //把用户名放入在线列表
         ServletContext application = request.getServletContext();
         List onlineUserList = (List)
         application.getAttribute("onlineUserList");
         // 第一次使用前,需要初始化
         if (onlineUserList == null) {
         onlineUserList = new ArrayList();
         application.setAttribute("onlineUserList", onlineUserList);
         }
         onlineUserList.add(username);
        
        // 成功
        response.sendRedirect("index.jsp");
    }
}
  1. 登录成功页面
<%@ page language="java" import="java.util.List" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>在线用户</title>
</head>
<body>
    <h3>
        您好:${username} [<a href="LoginServlet">注销</a>]
    </h3>
    当前在线用户:
    <table>
        <%
            List onlineUserList = (List) application.getAttribute("onlineUserList");
            for (int i = 0; i < onlineUserList.size(); i++) {
                String onlineUsername = (String) onlineUserList.get(i);
        %>
        <tr>
            <td><%=onlineUsername%></td>
        </tr>
        <%
            }
        %>
    </table>
</body>
</html>

登陆成功跳转到显示页面result.jsp
点击注销页面logout.jsp页面

  1. 开始新建监听器
    1、HttpSessionListener
    添加类OnlineUserListener,继承HttpSessionListener,HttpSessionListener中有两个方法
sessionCreated(HttpSessionEvent event)与sessionDestroyed

(HttpSessionEvent event),前者是监听session的新建,后者是监听session的销毁。

/**
* 注解配置监听器
*/
@WebListener
public class OnlineUserListener implements HttpSessionListener {

   public OnlineUserListener() {

   }
public void sessionCreated(HttpSessionEvent arg0) {
       System.out.println("新建session:" + arg0.getSession().getId());
   }
   public void sessionDestroyed(HttpSessionEvent arg0) {
       HttpSession session = arg0.getSession();
       ServletContext application = session.getServletContext();
       // 取得登录的用户名
       String username = (String) session.getAttribute("username");
       // 从在线列表中删除用户名
       List onlineUserList = (List) application.getAttribute("onlineUserList");
       onlineUserList.remove(username);
       System.out.println(username + "已经退出!");
   }
}

web.xml配置:

<listener>
  <listener-class>com.test.OnlineUserListener</listener-class>
</listener>

一旦监听器发现调用了sessionDestoryed方法就会把其用户从在线人数中delete,在下面两种情况下会发生sessionDestoryed事件:
a.执行session.invalidate()方法时
logout.jsp中调用了 session.invalidate()方法
b.session会话超时
session的默认超时事件是30分钟,30分钟后自动销毁session

  1. HttpSessionBindingListener
    HttpSessionBindingListener虽然叫做监听器,但使用方法与HttpSessionListener完全不同。我们实际看一下它是如何使用的。新建类OnlineUserBindingListener,实现HttpSessionBindingListener接口,构造方法传入username参数,HttpSessionBindingListener内有两个方法valueBound
    (HttpSessionBindingEvent event)和valueUnbound(HttpSessionBindingEvent event),前者为数据绑定,后者为取消绑定所谓对session进行数据绑定,就是调用session.setAttribute()把HttpSessionBindingListener保存进session中。
  2. 修改LoginServlet.java
        request.setCharacterEncoding("UTF-8");
        // 取得登录的用户名
        String username = request.getParameter("username");
        HttpSession session = request.getSession();
        // 把用户名放入在线列表
        session.setAttribute("onlineUserBindingListener", new OnlineUserBindingListener(username));
        // 成功
        response.sendRedirect("index.jsp");

这就是HttpSessionBindingListener和HttpSessionListener之间的最大区别:HttpSessionListener只需要设置到web.xml中就可以监听整个应用中的所有session。

HttpSessionBindingListener必须实例化后放入某一个session中,才可以进行监听。

从监听范围上比较,HttpSessionListener设置一次就可以监听所有session,HttpSessionBindingListener通常都是一对一的。
正是这种区别成就了HttpSessionBindingListener的优势,我们可以让每个listener对应一个username,这样就不需要每次再去session中读取username,进一步可以将所有操作在线列表的代码都移入listener,更容易维护。

  1. HttpSessionBindingListener实现:
/**
 * 配置监听器
 */
@WebListener
public class OnlineUserBindingListener implements HttpSessionBindingListener {
    String username;
    public OnlineUserBindingListener(String username) {
         this.username=username;
    }
    public OnlineUserBindingListener() {

    }
    /**
     * 数据绑定
     */
    public void valueBound(HttpSessionBindingEvent arg0) {
        HttpSession session = arg0.getSession();
        ServletContext application = session.getServletContext();
        // 把用户名放入在线列表
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        // 第一次使用前,需要初始化
        if (onlineUserList == null) {
            onlineUserList = new ArrayList();
            application.setAttribute("onlineUserList", onlineUserList);
        }
        onlineUserList.add(this.username);

    }
    /**
     * 解除绑定
     */
    public void valueUnbound(HttpSessionBindingEvent arg0) {
        HttpSession session = arg0.getSession();
        ServletContext application = session.getServletContext();
        // 从在线列表中删除用户名
        List onlineUserList = (List) application.getAttribute("onlineUserList");
        onlineUserList.remove(this.username);
        System.out.println(this.username + "退出。");

    }
}
  1. 这里可以直接使用listener的username操作在线列表,不必再去担心session中是否存在username。
    valueUnbound的触发条件是以下三种情况:
a.执行session.invalidate()时。
b.session超时,自动销毁时。
c.执行session.setAttribute("onlineUserListener", "其他对象");
或session.removeAttribute("onlineUserListener");

将listener从session中删除时。
因此,只要不将listener从session中删除,就可以监听到session的销毁。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容