博主信息:
📢@博主: 嘟嘟的程序员铲屎官
💬:一位爱喵咪,爱开源,爱总结,爱分享技术的Java领域新星博主,如果你想和博主做朋友,关注博主,并私聊博主(给我发一条消息我就会关注你喔),博主本人也十分喜欢解决问题,如果你有什么问题,也可以来私聊博主喔,希望能够和C站的朋友相互学习,相互进步。
💬:关于本篇博客,最近在学习JavaWeb部分的知识,对<<JavaWeb入门经典>>本书第7章第5节Listener监听器进行个人总结,如果有什么错误的,请各位大佬能够及时提出,以免小弟误人子弟!
@Toc
一.Listener监听器
1.什么是Listener监听器
在Servlet技术中定义很多的事件,为了对这些事件进行处理,针对这些事件编写相关的事件监听器,从而使用监听器处理事件,本篇博客主要讲解三大域对象(ServletContext、HttpSession、ServletRequest)的监听器,三大域对象的监听器分别对应的事件ServletContextEvent(上下文事件),HttpSessionEvent(会话事件),
HttpServletRequestEvent(请求事件)。
2.Listener简介
通过Listener接口对事件进行监听,下表列出常用8个Listener接口和6个Event类
servlet-api.jar中一共有13个和Listener相关的.java
在这篇博客<<JavaWeb开发Filter学习>>下第3.Filter的核心对象知识点中我们对servlet-api.jar
进行了解压,并对javax.servlet包下的*.class
文件进行了反编译,我们看看在servlet反编译文件下有哪一些Java文件跟Listener相关。
在javax.servlet包下和Listener相关的.Java
文件(7个):
进入到servlet反编译文件中
在文件搜索框中输入*listener*
在原包(javax.servlet解压包)中进行我们可以发现annotation和http文件都存在以Listener相关的.class文件,分别对这二个包进行反编译
在javax.servlet.annotation包下和Listener相关的.Java
文件(1个):
在javax.servlet.http包下和Listener相关的.class
文件(5个):
由于http包下的.class
文件有的没有反编译成功,所以就在原包中进行搜索与Listener相关的.class
3.使用监听器
使用监听器有以下二个步骤:
- 创建监听器(只要创建一个实现相关接口的Java类即可)
- 注册监听器
注册监听器的二种方式:
使用@webListener标签进行注册
![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/16635a7e746144c0853bc4fcacd6b1c0.png)
在web.xml中使用部署描述符进行注册
4.Servlet Context监听器
Servlet Context监听器可以监听ServletContext对象的创建、删除和添加属性,以及删除和修改操作,该监听器需要用到如下两个接口,该接口都是javax.servlet包下的成员。
(1) ServletContextListener接口
- 该接口位于javax.servlet下
- 主要监听ServletContext的创建和删除。
- 它提供了二个抽象方法:
contextInitialized();contextDestroyed()
<<JavaWeb入门经典>>本书对这二个抽象方法的解释:
(2) ServletAttributeListener接口
- 该接口位于javax.servlet下
- 主要监听ServletContext属性的增加、删除及修改
- 它提供了3个抽象方法:
attributeAdded();attributeRemoved();attributeReplaced()
<<JavaWeb入门经典>>本书对这三个抽象方法的解释:
5.Session 监听器
与HttpSession有关的监听器接口有4个:HttpSessionListener、HttpSessionActivation-Listener、HttpSessionAttributeListener和 HttpSessionBindingListener。这些接口都是javax.servlet.http包的成员,下面将进行详细的讲解。
(1) HttpSessionListener接口
- 该接口位于javax.servlet.http包下
- 该接口监听HTTP会话的创建及销毁,它提供了如下两个抽象方法。
sessionCreated();sessionDestroyed()
<<JavaWeb入门经典>>本书对这二个抽象方法的解释:
(2) HttpSessionAttributeListener接口
- 该接口位于javax.servlet.http包下
- 该接口实现监听 HTTP会话中属性的设置请求(属性
添加
,删除
,替换
),它提供了如下三个方法。
attributeAdded();attributeRemoved();attributeReplaced();
<<JavaWeb入门经典>>本书对这三个抽象方法的解释:
(3) HttpSessionActivationListener接口
- 该接口位于javax.servlet.http包下
- 该接口实现监听HTTP会话active和 passivate情况,它提供了如下2个方法。
sessionWillPassivate();sessionDidActivate()
<<JavaWeb入门经典>>本书对这二个抽象方法的解释:
(4) HttpSessionBindingListener接口
- 该接口位于javax.servlet.http包下
- 该接口实现监听HTTP会话中对象的绑定信息,它是唯一不需要在web.xml中设置Listener的,并提供了以下两个方法。
valueBound();valueUnbound();
<<JavaWeb入门经典>>本书对这二个抽象方法的解释:
6.ServletRequest 监听器
在ServletRequest级别上有3个监听器接口:ServletRequestListener、ServletRequestAttributeListener和AsyncListener,这些接口都是javax.servlet包的成员。下面主要讲解了前二种接口。
(1) ServletRequestListener接口
- 该接口位于javax.servlet包下
- ServletRequestListener对 ServletRequest的创建和销毁做出响应。
- 该接口提供如下二个方法
requestDestroyed();requestInitialized();
<<JavaWeb入门经典>>本书对这二个抽象方法的解释:
(2) ServletRequestAttributeListener接口
- 该接口位于javax.servlet包下
- 当在ServletRequest中
添加
、删除
或者替换
某个属性时会调用以下三个方法
attributeAdded();attributeRemoved();attributeReplaced();
<<JavaWeb入门经典>>本书对这三个抽象方法的解释:
7.实例练习(使用监听器统计在线用户及人数)
分析:
项目结构:
index.html
web.xml
(在web.xml中配置session-timeout标签 标志session过期时间为1分钟 0为不过期)
HttpSessionListener.java
@WebListener
public class HttpSessionListener implements javax.servlet.http.HttpSessionListener{
private int userCounts=0;
@Override
public void sessionCreated(HttpSessionEvent httpSessionEvent) {
// TODO Auto-generated method stub
httpSessionEvent.getSession().setAttribute("userCounts", ++userCounts);
}
@Override
public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
// TODO Auto-generated method stub
// 将人数数据加到HttpSession中
httpSessionEvent.getSession().setAttribute("userCounts", --userCounts);
// 获取用户列表
@SuppressWarnings("unchecked")
ArrayList<User> list=(ArrayList<User>)httpSessionEvent.
getSession().getServletContext().getAttribute("userList ");
if (list!=null) {
// 根据SessionId属性将当前用户从userList集合中移除
for (User user : list) {
if (user.getSessionId().equals(httpSessionEvent.getSession().getId())) {
list.remove(user);
}
}
}
}
}
ServletRequestListener.java
@WebListener
public class ServletRequestListener implements javax.servlet.ServletRequestListener{
@Override
public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
// TODO Auto-generated method stub
}
@Override
public void requestInitialized(ServletRequestEvent servletRequestEvent) {
// TODO Auto-generated method stub
// 获取ServletContext中的userList集合
@SuppressWarnings("unchecked")
ArrayList<User> list=(ArrayList<User>)servletRequestEvent.getServletContext().getAttribute("userList");
// ServletContext是否创建,未创建返回的集合为null,需要进行初始化
if (list==null) {
list=new ArrayList<>();
}
// 创建HttpServletRequest对象
HttpServletRequest httpServletRequest=(HttpServletRequest)servletRequestEvent.getServletRequest();
// 当前用户是否在该集合中,没有则将用户信息加入到集合中去,并保存到ServletContext中
if (noAtUserList(list,httpServletRequest)) {
// 将当前用户添加到userList集合中
User user=new User();
user.setSessionId(httpServletRequest.getSession().getId());
user.setIp(httpServletRequest.getRemoteAddr());
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:MM:ss");
user.setFirstTime(sdf.format(new Date()));
list.add(user);
}
// 将数据保存到ServletContext中
servletRequestEvent.getServletContext().setAttribute("userList", list);
}
@SuppressWarnings("unused")
private boolean noAtUserList(ArrayList<User>list,HttpServletRequest httpServletRequest) {
for (User user : list) {
if (user.getSessionId().equals(httpServletRequest.getSession().getId())) {
return false;
}
}
return true;
}
}
User.java
public class User {
// 当前用户的session id
private String sessionId;
// 当前用户的ip地址
private String ip;
// 当前用户第一次访问的时间
private String firstTime;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getFirstTime() {
return firstTime;
}
public void setFirstTime(String firstTime) {
this.firstTime = firstTime;
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
}
usersInfoservlet.java
@SuppressWarnings("serial")
@WebServlet(urlPatterns={"/usersInfo"})
public class usersInfoservlet extends HttpServlet{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
// 设置网页编码,防止出现乱码
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setHeader("content-type", "text/html;charset=UTF-8");
// 获取userList
@SuppressWarnings({ "unused", "unchecked" })
ArrayList<User>userList=(ArrayList<User>)req.getServletContext().getAttribute("userList");
// 获取当前用户数
int userCounts=((req.getSession().getAttribute("userCounts") == null) ? 0:(int) req.getSession().getAttribute("userCounts"));
// 显示信息
PrintWriter writer=resp.getWriter();
writer.print("<html><head></head>");
writer.print("<body>当前人数:"+userCounts+"</br>");
if (userList!=null) {
for (int i = 0; i < userList.size(); i++) {
writer.print("第"+(i+1)+"个用户,信息:</br>");
writer.print("sessionId:"+userList.get(i).getSessionId()+"</br>");
writer.print("ip:"+userList.get(i).getIp()+"</br>");
writer.print("firstTime:"+userList.get(i).getFirstTime()+"</br>");
}
}
writer.print("</body></html>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(req, resp);
}
}
运行效果:
打开另外一个游览器,访问:http://localhost:8085/app05/usersInfo
再打开一个游览器,再次访问