Web监听器:Listener
创始人
2024-03-30 20:42:39
0

Listener

  • 简介
    • 常用监听接口
  • 监听在线用户信息的实现
    • Model层
    • Controller层
    • OnlineUserListener的实现
    • View层
    • 测试

简介

监听器(Listener),是一个实现特定接口的普通Java程序,用于监听Web应用中的对象或信息发生改变时,作出相应的响应处理。当被监听对象的状态发生变化时,服务器会自动调用监听器对象中的方法。监听器常常用于系统加载时进行信息初始化、统计在线人数或用户和网站的访问量等。

在这里插入图片描述

常用监听接口

接口作用
ServletContextListener监听Web的启动与关闭
ServletContextAttributeListener监听ServletContext范围内属性的改变
ServletRequestListener监听用户请求
ServletRequestAttributeListener监听ServletRequest范围内属性的改变
HttpSessionListener监听用户session的开始与结束
HttpSessionAttributeListener监听HttpSession范围内属性的改变

监听在线用户信息的实现

首先,创建一个在线用户的表onlineusers,表结构如下图:

在这里插入图片描述

Model层

然后,创建一个在线用户表onlineusers与之相映射的主体类OnlineUers,代码如下:
其中,在线用户的属性信息:
sign—主键(session_id)
username—用户名
apage—访问的网页
ip—ip地址
atime—访问的时间(注意:Date类型)

package cn.edu.MVCcase.Model.model;import java.util.Date;//在线状态用户类
public class OnlineUers {private String sign;private String username;private String apage;private String ip;private Date atime;public OnlineUers() {super();}public String getSign() {return sign;}public void setSign(String sign) {this.sign = sign;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getApage() {return apage;}public void setApage(String apage) {this.apage = apage;}public String getIp() {return ip;}public void setIp(String ip) {this.ip = ip;}public Date getAtime() {return atime;}public void setAtime(Date atime) {this.atime = atime;}public OnlineUers(String sign, String username, String apage, String ip, Date atime) {this.sign = sign;this.username = username;this.apage = apage;this.ip = ip;this.atime = atime;}@Overridepublic String toString() {return "OnlineUers{" +"sign='" + sign + '\'' +", username='" + username + '\'' +", apage='" + apage + '\'' +", ip='" + ip + '\'' +", atime='" + atime + '\'' +'}';}
}

接着,设置实现对数据库onlineusers表的操作的接口OnlineUersDao,代码如下:

package cn.edu.MVCcase.Model.dao;import cn.edu.MVCcase.Model.model.OnlineUers;
import java.util.List;public interface OnlineUersDao {//获取在线用户所有信息public List getOnlineUserInformation();//新增在线用户信息public void insertOnlineUserInformation(OnlineUers onlineUers);//更新在新用户信息public void updateOnlineUserInformation(OnlineUers onlineUers);//根据sign删除已下线的用户信息public void deleteOfflineUserInformation(String sign);//根据sgin获取在线用户信息public OnlineUers getOnlineUserInformationBySign(String sign);
}

再实现接口OnlineUersDao的类OnlineUersDaoImpl,同时需要继承Dao的通用基本类CurrencyDao< OnlineUers > (MVC案例的内容),代码如下:

package cn.edu.MVCcase.Model.dao;import cn.edu.MVCcase.Model.model.OnlineUers;import java.util.List;public class OnlineUersDaoImpl extends CurrencyDao implements OnlineUersDao  {@Overridepublic List getOnlineUserInformation() {String sql = "SELECT `sign`,`username`,`apage`,`ip`,`atime` FROM `onlineusers`";return super.getList(sql);}@Overridepublic void insertOnlineUserInformation(OnlineUers onlineUers) {String sql = "INSERT `onlineusers` SET `sign`=?,`username`=?,`apage`=?,`ip`=?,`atime`=?";super.TableOperation(sql,onlineUers.getSign(),onlineUers.getUsername(),onlineUers.getApage(),onlineUers.getIp(),onlineUers.getAtime());}@Overridepublic void updateOnlineUserInformation(OnlineUers onlineUers) {String sql = "UPDATE `onlineusers` SET `username`=?,`apage`=?,`ip`=?,`atime`=? WHERE `sign`=?";super.TableOperation(sql,onlineUers.getUsername(),onlineUers.getApage(),onlineUers.getIp(),onlineUers.getAtime(),onlineUers.getSign());}@Overridepublic void deleteOfflineUserInformation(String sign) {String sql = "DELETE FROM `onlineusers` WHERE `sign`=?";super.TableOperation(sql,sign);}@Overridepublic OnlineUers getOnlineUserInformationBySign(String sign) {String sql = "SELECT `sign`,`username`,`apage`,`ip`,`atime` FROM `onlineusers` WHERE `sign`=?";return super.getSelect(sql,sign);}
}

同时,为了实现解耦,降低模块间的依赖性,提高程序的独立性,在FactoryDao类中添加如下代码:

public static OnlineUersDao getOnlineUersDao() { return new OnlineUersDaoImpl(); }

再接着,设置对业务处理的接口OnlineUersService,代码如下:

package cn.edu.MVCcase.Model.service;import cn.edu.MVCcase.Model.model.OnlineUers;import java.util.List;public interface OnlineUersService {//获取在线用户所有信息public List getOnlineUserInformation();//新增在线用户信息public void insertOnlineUserInformation(OnlineUers onlineUers);//更新在新用户信息public void updateOnlineUserInformation(OnlineUers onlineUers);//根据sign删除已下线的用户信息public void deleteOfflineUserInformation(List list);//根据sgin获取在线用户信息public OnlineUers getOnlineUserInformationBySign(String sign);
}

同理,设置实现接口OnlineUersService的类OnlineUersServiceImpl,代码如下:

package cn.edu.MVCcase.Model.service;import cn.edu.MVCcase.Model.dao.FactoryDao;
import cn.edu.MVCcase.Model.dao.OnlineUersDao;
import cn.edu.MVCcase.Model.model.OnlineUers;import java.util.List;public class OnlineUersServiceImpl implements OnlineUersService {OnlineUersDao onlineUersDao = FactoryDao.getOnlineUersDao();@Overridepublic List getOnlineUserInformation() {return onlineUersDao.getOnlineUserInformation();}@Overridepublic void insertOnlineUserInformation(OnlineUers onlineUers) {onlineUersDao.insertOnlineUserInformation(onlineUers);}@Overridepublic void updateOnlineUserInformation(OnlineUers onlineUers) {onlineUersDao.updateOnlineUserInformation(onlineUers);}@Overridepublic void deleteOfflineUserInformation(List list) {//遍历删除if(list != null && list.size() > 0) {for (OnlineUers onlineUers:list) {onlineUersDao.deleteOfflineUserInformation(onlineUers.getSign());}}}@Overridepublic OnlineUers getOnlineUserInformationBySign(String sign) {return onlineUersDao.getOnlineUserInformationBySign(sign);}
}

同理,在类FactoryService中添加如下代码:

public static OnlineUersService getOnlineUersService() { return new OnlineUersServiceImpl(); }

Controller层

最后,调用service来实现业务,代码如下:

package cn.edu.MVCcase.Controller.controller;import cn.edu.MVCcase.Model.model.OnlineUers;
import cn.edu.MVCcase.Model.service.FactoryService;
import cn.edu.MVCcase.Model.service.OnlineUersService;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 java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;@WebServlet(urlPatterns={"*.onlineuserdo"})
public class OnlineUserController extends HttpServlet {private static final long serialVersionUID = 1L;OnlineUersService onlineUersService = FactoryService.getOnlineUersService();@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//设置字符集req.setCharacterEncoding("UTF-8");resp.setCharacterEncoding("UTF-8");//获取URL的文件名,如/select.studoString pathname = req.getServletPath();//截取select.studopathname = pathname.substring(1);//截取selectpathname = pathname.substring(0,pathname.length()-13);//获取pathname通过反射调用相应的方法try {Method method = this.getClass().getDeclaredMethod(pathname,HttpServletRequest.class,HttpServletResponse.class);method.invoke(this,req,resp);} catch (Exception e) {e.printStackTrace();}}public void onlineuser(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {List list = onlineUersService.getOnlineUserInformation();req.setAttribute("onlineuser",list);req.getRequestDispatcher("/OnlineUser.jsp").forward(req,resp);}
}

OnlineUserListener的实现

监听器实现的基本思路:
首先,记录在线用户信息并写入到onlineuser表中(判断是否存在,如果存在,则更新访问时间与访问页面;如果不存在,则插入该信息);同时,假设在线用户超过十分钟处于静止状态(即没有任何操作),则视为用户已下线,onlineuser表中需要删除该信息(OnlineUserServletContextListener类实现:服务器启动时,每五秒进行检查,发现离线用户则删除该信息);最后,游客登录成功后需要将username改为对应的用户名。

在线用户的监听,信息获取或更新的实现,代码如下:

package cn.edu.MVCcase.OnlineUserListener.listener;import cn.edu.MVCcase.Model.model.OnlineUers;
import cn.edu.MVCcase.Model.service.FactoryService;
import cn.edu.MVCcase.Model.service.OnlineUersService;import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.Date;@WebListener
public class OnlineUserListener implements ServletRequestListener {OnlineUersService onlineUersService = FactoryService.getOnlineUersService(); //OnlineUersService对象,用于请求操作数据库@Overridepublic void requestDestroyed(ServletRequestEvent servletRequestEvent) {}@Overridepublic void requestInitialized(ServletRequestEvent servletRequestEvent) {//获取在线用户信息HttpServletRequest servletRequest = (HttpServletRequest)servletRequestEvent.getServletRequest();HttpSession session = servletRequest.getSession();//获取session_id(即sign)String sign = session.getId();//获取usekeyString username = (String) session.getAttribute("admin");username = username==null?"游客":username;//获取访问的页面String apage = servletRequest.getRequestURI();//获取ip地址String ip = servletRequest.getRemoteAddr();//操作数据库前先将信息封装OnlineUers onlineUers = new OnlineUers();onlineUers.setSign(sign);onlineUers.setUsername(username);onlineUers.setApage(apage);onlineUers.setIp(ip);onlineUers.setAtime(new Date());//获取访问时间OnlineUers onlineUersTableOperation = onlineUersService.getOnlineUserInformationBySign(sign);if(onlineUersTableOperation != null) {//更新访问时间与页面onlineUersTableOperation.setAtime(new Date());onlineUersTableOperation.setApage(apage);onlineUersService.updateOnlineUserInformation(onlineUers);}else {//插入信息onlineUersService.insertOnlineUserInformation(onlineUers);}}
}

离线用户的监听,离线用户信息删除与清空的实现,代码如下:

package cn.edu.MVCcase.OnlineUserListener.listener;import cn.edu.MVCcase.Model.model.OnlineUers;
import cn.edu.MVCcase.Model.service.FactoryService;
import cn.edu.MVCcase.Model.service.OnlineUersService;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;@WebListener
public class OnlineUserServletContextListener implements ServletContextListener {//定义十分钟public final int MAX_Millis = 10*60*1000;OnlineUersService onlineUersService = FactoryService.getOnlineUersService();@Override//服务器启动时被执行public void contextInitialized(ServletContextEvent servletContextEvent) {//视为已下线用户信息List OfflineUsers = new ArrayList<>();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置定时器(每隔五秒执行)new Timer(5*1000, new ActionListener(){@Override//检查的具体方法public void actionPerformed(ActionEvent event) {//获取在线用户信息List list = onlineUersService.getOnlineUserInformation();if(list != null && list.size() > 0 ) {Date OffDate = null;for (OnlineUers onlineUers:list) {OffDate = onlineUers.getAtime();simpleDateFormat.format(OffDate);Long OffMillis;try {OffMillis = simpleDateFormat.parse(OffDate.toString()).getTime();//当前系统时间,System.currentTimeMillis()//时间转换成时间戳,Long.parseLong(onlineUers.getAtime().toString())if ((System.currentTimeMillis()-OffMillis) > MAX_Millis) {OfflineUsers.add(onlineUers);}} catch (ParseException e) {e.printStackTrace();}}}//删除已下线用户的信息onlineUersService.deleteOfflineUserInformation(OfflineUsers);//再清空已下线用户信息OfflineUsers.clear();}}).start();}@Overridepublic void contextDestroyed(ServletContextEvent servletContextEvent) {}
}

用户登录的监听,游客登录成功的username对应修改的实现(注:登录代码中凡成功登录跳转主页面的都需添加),代码如下:

//成功登录,username由游客变成对应的用户名
OnlineUersService onlineUersService = FactoryService.getOnlineUersService();
HttpSession session = req.getSession();
OnlineUers onlineUers = onlineUersService.getOnlineUserInformationBySign(session.getId());
if (onlineUers != null) {//更换onlineUers.setUsername(username);//更新onlineUersService.updateOnlineUserInformation(onlineUers);
}

View层

现在是重点讲解Listener知识,所以简单做个页面看看,不做太多的修饰,代码如下:

<%@ page import="cn.edu.MVCcase.Model.model.OnlineUers" %>
<%@ page import="java.util.List" %>
<%--Created by IntelliJ IDEA.User: dellDate: 2022/10/15Time: 12:57To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

在线用户

/onlineuser.onlineuserdo" method="post">
<%List list = (List) request.getAttribute("onlineuser");//list有值才进行遍历获取元素if(list != null && list.size()>0) {for(OnlineUers onlineUers:list){%><%}}%>
signuserkey访问的页面ip地址访问的时间
<%=onlineUers.getSign()%><%=onlineUers.getUsername()%><%=onlineUers.getApage()%><%=onlineUers.getIp()%><%=onlineUers.getAtime()%>

测试

administrator表中有两个账号,测试将两个账号分别在不同的浏览器同时登录,admin在onlineuser.onlineuserdo下观看监听情况,小明在登录主页面。如下图:

在这里插入图片描述

在这里插入图片描述

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
客厅放八骏马摆件可以吗(家里摆... 今天给各位分享客厅放八骏马摆件可以吗的知识,其中也会对家里摆八骏马摆件好吗进行解释,如果能碰巧解决你...
苏州离哪个飞机场近(苏州离哪个... 本篇文章极速百科小编给大家谈谈苏州离哪个飞机场近,以及苏州离哪个飞机场近点对应的知识点,希望对各位有...