什么是监听器?
类似于前端的事件绑定,java中的监听器用于监听web应用中某些对象、信息的创建、销毁、增加,修改,删除等动作的发生,然后作出相应的响应处理。当范围对象的状态发生变化的时候,服务器自动调用监听器对象中的方法。常用于统计在线人数和在线用户,系统加载时进行信息初始化,统计网站的访问量等等。
监听器怎么分类?
按监听的对象划分
按监听的事件划分
一共有哪些监听器?分别处理的是什么事情?
java中一共给我们提供了八个监听器接口,分别用于监听三个域对象,每个监听器都有专门监听的事件
Request
Session
Application
监听器如何使用?
两步走使用
接下来我们就挨个认识一下每个监听器及内部方法的作用
Requet域共有两个监听器接口,分别是
ServletRequestListener
ServleRequestAttributeListener
接下来我们就认识一些每个接口和接口中每个方法的用处
定义监听器类
package com.msb.listener;
import javax.servlet.*;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public class MyRequestListener implements ServletRequestListener, ServletRequestAttributeListener {@Overridepublic void requestDestroyed(ServletRequestEvent sre) {// 监听HttpServletRequest对象的销毁 项目中任何一个Request对象的销毁都会触发该方法的执行ServletRequest servletRequest = sre.getServletRequest();System.out.println("request"+servletRequest.hashCode()+"对象销毁了");}@Overridepublic void requestInitialized(ServletRequestEvent sre) {// 监听HttpServletRequest对象的创建并初始化 项目中任何一个Request对象的创建并初始化都会触发该方法的执行ServletRequest servletRequest = sre.getServletRequest();System.out.println("request"+servletRequest.hashCode()+"对象初始化");}@Overridepublic void attributeAdded(ServletRequestAttributeEvent srae) {// 任何一个Request对象中调用 setAttribute方法增加了数据都会触发该方法ServletRequest servletRequest = srae.getServletRequest();String name = srae.getName();Object value = srae.getValue();System.out.println("request"+servletRequest.hashCode()+"对象增加了数据:"+name+"="+value);}@Overridepublic void attributeRemoved(ServletRequestAttributeEvent srae) {// 任何一个Request对象中调用 removeAttribute方法移除了数据都会触发该方法ServletRequest servletRequest = srae.getServletRequest();String name = srae.getName();Object value = srae.getValue();System.out.println("request"+servletRequest.hashCode()+"对象删除了数据:"+name+"="+value);}@Overridepublic void attributeReplaced(ServletRequestAttributeEvent srae) {// 任何一个Request对象中调用 setAttribute方法修改了数据都会触发该方法ServletRequest servletRequest = srae.getServletRequest();String name = srae.getName();Object value = srae.getValue();Object newValue=servletRequest.getAttribute(name);System.out.println("request"+servletRequest.hashCode()+"对象增修改了数据:"+name+"="+value+"设置为:"+newValue);}
}
配置监听器 使用web.xml 或者通过@WebListener注解都可以
com.msb.listener.MyRequestListener
准备Servlet
@WebServlet(urlPatterns = "/myServlet3.do")
public class MyServlet3 extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setAttribute("name", "zhangsan");req.setAttribute("name", "lisi");req.removeAttribute("name");}
}
Session域共有四个监听器接口,分别是
HttpSessionListener
HttpSessionAttributeListener
HttpSessionBindingListener
HttpSessionActivationListener
接下来我们就认识一些每个接口和接口中每个方法的用处
监听器代码
HttpSessionListener
HttpSessionAttributeListener
package com.msb.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebListener
public class MySessionListener implements HttpSessionListener , HttpSessionAttributeListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {System.out.println("任何一个Session对象创建");}@Overridepublic void sessionDestroyed(HttpSessionEvent se) {System.out.println("任何一个Session对象的销毁");}@Overridepublic void attributeAdded(HttpSessionBindingEvent se) {System.out.println("任何一个Session对象中添加了数据");}@Overridepublic void attributeRemoved(HttpSessionBindingEvent se) {System.out.println("任何一个Session对象中移除了数据");}@Overridepublic void attributeReplaced(HttpSessionBindingEvent se) {System.out.println("任何一个Session对象中修改了数据");}
}
HttpSessionBindingListener
package com.msb.listener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
/*
* 可以监听具体的某个session对象的事件的
*
* HttpSessionListener 只要在web.xml中配置或者通过@WebListener注解就可以注册监听所有的Session对象
* HttpSessionBindingListener 必须要通过setAttribute方法和某个session对象绑定之后,监听单独的某个Session对象
* */
public class MySessionBindingListener implements HttpSessionBindingListener {// 绑定方法/*session.setAttribute("mySessionBindingListener",new MySessionBindingListener())*/@Overridepublic void valueBound(HttpSessionBindingEvent event) {System.out.println("监听器和某个session对象绑定了");}// 解除绑定方法/** 当发生如下情况,会触发该方法的运行* 1 session.invalidate(); 让session不可用* 2 session到达最大不活动时间,session对象回收 ;* 3 session.removeAttribute("mySessionBindingListener");手动解除绑定* */@Overridepublic void valueUnbound(HttpSessionBindingEvent event) {}
}
HttpSessionActivationListener
package com.msb.listener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/public class MySessionActivationListener implements HttpSessionActivationListener {@Overridepublic void sessionWillPassivate(HttpSessionEvent se) {System.out.println("session即将钝化");}@Overridepublic void sessionDidActivate(HttpSessionEvent se) {System.out.println("session活化完毕");}
}
Application域共有两个监听器接口,分别是
ServletContextListener
ServletContextAttributeListener
接下来我们就认识一些每个接口和接口中每个方法的用处
监听器代码
package com.msb.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public class MyApplicationListener implements ServletContextListener , ServletContextAttributeListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("ServletContext创建并初始化了");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("ServletContext销毁了");}@Overridepublic void attributeAdded(ServletContextAttributeEvent scae) {System.out.println("ServletContext增加了数据");}@Overridepublic void attributeRemoved(ServletContextAttributeEvent scae) {System.out.println("ServletContext删除了数据");}@Overridepublic void attributeReplaced(ServletContextAttributeEvent scae) {System.out.println("ServletContext修改了数据");}
}
1.需求:记录每次请求中如下的信息并存储进入日志文件请求的来源
监听器代码
package com.msb.listener;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebListener
public class RequestLogListener implements ServletRequestListener {private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");@Overridepublic void requestDestroyed(ServletRequestEvent sre) {}@Overridepublic void requestInitialized(ServletRequestEvent sre) {// 获得请求发出的IP// 获得请求的URL// 获得请求产生的时间HttpServletRequest request = (HttpServletRequest)sre.getServletRequest();String remoteHost = request.getRemoteHost();String requestURL = request.getRequestURL().toString();String reqquestDate = simpleDateFormat.format(new Date());// 准备输出流try {PrintWriter pw =new PrintWriter(new FileOutputStream(new File("d:/msb.txt"),true));pw.println(remoteHost+" "+requestURL+" "+reqquestDate );pw.close();} catch (FileNotFoundException e) {e.printStackTrace();}}
}
2.需求:
1当任何一个账户处于登录状态时,在线统计总数+1,离线时-1
2通过session监听器实现计数,但是在线人数要保存在Application域中
准备监听器
package com.msb.listener;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebListener
public class OnLineNumberListener implements HttpSessionListener {@Overridepublic void sessionCreated(HttpSessionEvent se) {// 向application域中 增加一个数字HttpSession session = se.getSession();ServletContext application = session.getServletContext();Object attribute = application.getAttribute("count");if(null == attribute){// 第一次放数据application.setAttribute("count", 1);}else{int count =(int)attribute;application.setAttribute("count", ++count);}}@Overridepublic void sessionDestroyed(HttpSessionEvent se) {// 向application域中 减少一个数字HttpSession session = se.getSession();ServletContext application = session.getServletContext();int count =(int)application.getAttribute("count");application.setAttribute("count", --count);}
}
准备销毁监听的servlet
package com.msb.servlet;
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;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebServlet(urlPatterns = "/logout.do")
public class Logout extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession session = req.getSession();session.invalidate();}
}
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title%sSourceCode%lt;/title> 当前在线人数为:${applicationScope.count}
3.项目重启免登录
Session序列化和反序列化
1、序列化与反序列
把对象转化为字节序列的过程称为序列化(保存到硬盘,持久化)
把字节序列转化为对象的过程称为反序列化(存放于内存)
2、序列化的用途
把对象的字节序列永久保存到硬盘上,通常放到一个文件中。
把网络传输的对象通过字节序列化,方便传输本节作业
3、实现步骤
要想实现序列化和反序列化需要手动配置
A、新建文件如图所示:
B、 Context.xml中文件如下
C、注意实体类必须实现serializable 接口
开发过程
1 准备实体类
package com.msb.pojo;
import java.io.Serializable;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public class User implements Serializable {private String username;private String pwd;
2.开发登录信息输入页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title%sSourceCode%lt;/title>
3开发登录信息验证Servlet
package com.msb.controller;
import com.msb.listener.MySessionActivationListener;
import com.msb.pojo.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;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebServlet("/loginController.do")
public class LoginController extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("user");String pwd = req.getParameter("pwd");// userUser user =new User(username,pwd);// sessionHttpSession session = req.getSession();session.setAttribute("user", user);}
}
4 开发校验当前是否已经登录的Controller
package com.msb.controller;
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;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
@WebServlet(urlPatterns = "/loginCheckController.do")
public class LoginCheckController extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 判断是否登录HttpSession session = req.getSession();Object user = session.getAttribute("user");Object listener = session.getAttribute("listener");// 获得对应的监听器String message ="";if(null != user){message="您已经登录过";}else{message="您还未登录";}resp.setCharacterEncoding("UTF-8");resp.setContentType("text/html;charset=UTF-8");resp.getWriter().println(message);}
}
5测试, 先登录,然后请求loginCheckController.do 校验是否登录过,然后重启项目,再起请求loginCheckController.do 校验是否登录过,发现重启后,仍然是登录过的
6监听钝化和活化
准备监听器
package com.msb.listener;
import javax.servlet.http.HttpSessionActivationListener;
import javax.servlet.http.HttpSessionEvent;
import java.io.Serializable;
/*** @Author: Ma HaiYang* @Description: MircoMessage:Mark_7001*/
public class MySessionActivationListener implements HttpSessionActivationListener, Serializable {@Overridepublic void sessionWillPassivate(HttpSessionEvent se) {System.out.println(se.getSession().hashCode()+"即将钝化");}@Overridepublic void sessionDidActivate(HttpSessionEvent se) {System.out.println(se.getSession().hashCode()+"已经活化");}
}
登录时绑定监听器
@WebServlet("/loginController.do")
public class LoginController extends HttpServlet {@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String username = req.getParameter("user");String pwd = req.getParameter("pwd");// userUser user =new User(username,pwd);// sessionHttpSession session = req.getSession();session.setAttribute("user", user);// 绑定监听器session.setAttribute("listener", new MySessionActivationListener());}
}
重启项目 重复测试即可