Listener的簡單介紹及使用
阿新 • • 發佈:2019-01-13
一、Listener概述
Listener可以監聽容器中某一執行動作,並根據其要求做出相應的響應。 常用的Web事件的監聽介面如下: ServletContextListener:用於監聽Web的啟動及關閉 ServletContextAttributeListener:用於監聽ServletContext範圍內屬性的改變 ServletRequestListener:用於監聽使用者請求 ServletRequestAttributeListener:用於監聽ServletRequest範圍屬性的改變 HttpSessionListener:用於監聽使用者session的開始及結束 HttpSessionAttributeListener:用於監聽HttpSession範圍內的屬性改變
二、ServletContextListener的使用
1、配置web.xml(下面例子都使用此配置檔案)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" >
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 初始化引數 -->
<context-param>
<param-name>driver</param-name>
<param-value>com.mysql.jdbc.Driver</param-value>
</context-param>
<context-param>
<param-name>url</param-name>
<param-value>jdbc:mysql://localhost:3306/escshop</param-value>
</context-param>
<context-param>
<param-name>user</param-name>
<param-value>root</param-value>
</context-param>
<context-param>
<param-name>pass</param-name>
<param-value></param-value>
</context-param>
<!-- 定義Filter -->
<filter>
<filter-name>logFilter</filter-name>
<filter-class>Filter.LogFilter</filter-class>
</filter>
<!-- 定義Filter攔截的URL地址 -->
<filter-mapping>
<filter-name>logFilter</filter-name>
<!-- 負責攔截的URL,/*表示攔截所有的請求 -->
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 定義AuthorityFilter -->
<filter>
<filter-name>authority</filter-name>
<filter-class>Filter.AuthorityFilter</filter-class>
<init-param>
<param-name>encode</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>indexPage</param-name>
<param-value>/index.jsp</param-value>
</init-param>
<init-param>
<param-name>shopPage</param-name>
<param-value>/shop.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>authority</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 登入servlet -->
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>Login.LoginServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
<!-- 配置監聽Web啟動與關閉的Listener -->
<listener>
<listener-class>listener.GetConnListener</listener-class>
</listener>
<!-- 用於監聽ServletContenxt(application)範圍的變化 -->
<listener>
<listener-class>listener.MyServletContenxtAttributeListener</listener-class>
</listener>
<!-- 用於監聽使用者請求到達 -->
<listener>
<listener-class>listener.RequestListener</listener-class>
</listener>
<listener>
<listener-class>listener.OnlineRequestListener</listener-class>
</listener>
<!--使用者監聽使用者session建立與銷燬 -->
<listener>
<listener-class>listener.OnlineListener</listener-class>
</listener>
</web-app>
2、使用ServletContextListener
package listener;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 監聽Web應用啟動及關閉
* @author xieyongxue
*
*/
public class GetConnListener implements ServletContextListener{
//應用關閉時,此方法被呼叫
public void contextDestroyed(ServletContextEvent sce) {
// TODO Auto-generated method stub
ServletContext application=sce.getServletContext();
Connection conn=(Connection) application.getAttribute("conn");
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//應用啟動時,此方法被呼叫
public void contextInitialized(ServletContextEvent sce) {
// TODO Auto-generated method stub
//獲取到該應用的ServletContext的例項
ServletContext application=sce.getServletContext();
//獲取資料庫驅動
String driver=application.getInitParameter("driver");
//載入資料庫連線URL
String url=application.getInitParameter("url");
//獲取登入資料庫的名稱
String user=application.getInitParameter("user");
//獲取連線資料庫的密碼
String pass=application.getInitParameter("pass");
try {
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
System.out.println("載入資料庫驅動失敗!"+e.toString());
e.printStackTrace();
}
Connection conn= DriverManager.getConnection(url, user, pass);
//將資料庫連線設定成application的屬性
application.setAttribute("conn", conn);
} catch (SQLException e) {
// TODO Auto-generated catch block
System.out.println("連線資料庫失敗!"+e.toString());
e.printStackTrace();
}
}
}
3、使用ServletContextAttributeListener
package listener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
public class MyServletContenxtAttributeListener implements ServletContextAttributeListener{
//當程式向application範圍新增屬性時觸發此方法
public void attributeAdded(ServletContextAttributeEvent scab) {
// TODO Auto-generated method stub
ServletContext application=scab.getServletContext();
//獲取新增的屬性名與值
String name=scab.getName();
Object value=scab.getValue();
System.out.println(application+"範圍內新增了name值為="+name+"value值="+value);
}
//當程式向application範圍移除屬性時觸發此方法
public void attributeRemoved(ServletContextAttributeEvent scab) {
// TODO Auto-generated method stub
ServletContext application=scab.getServletContext();
//獲取移除的屬性名與值
String name=scab.getName();
Object value=scab.getValue();
System.out.println(application+"範圍內移除了name值為="+name+"value值="+value);
}
//當程式向application範圍替換屬性時觸發此方法
public void attributeReplaced(ServletContextAttributeEvent scab) {
// TODO Auto-generated method stub
ServletContext application=scab.getServletContext();
//獲取替換的屬性名與值
String name=scab.getName();
Object value=scab.getValue();
System.out.println(application+"範圍內替換了name值為="+name+"value值="+value);
}
}
4、測試例子
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
application.setAttribute("addAttrName","addAttrValue");
application.removeAttribute("addAttrName");
application.setAttribute("newAttrName","newAttrValue");
application.setAttribute("newAttrName","1234567");
request.setAttribute("requestName1","requestValue1");
request.removeAttribute("requestName1");
request.setAttribute("requestName2","requestValue2");
request.setAttribute("requestName2","requestValue23");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Login</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
${tip}<br>
<form action="login?action=service" method="post">
名稱:<input type="text" name="user"><br>
密碼:<input type="text" name="pass"><br/>
<input type="submit" value="登入"><input type="reset" value="重置">
</form>
</body>
</html>
二、使用HttpSessionListener統計使用者線上人數
1、實現HttpSessionListener監聽器
package listener;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
public class OnlineListener implements HttpSessionListener{
//當用戶與伺服器開始session時觸發該方法
public void sessionCreated(HttpSessionEvent se) {
// TODO Auto-generated method stub
HttpSession session=se.getSession();
ServletContext application=session.getServletContext();
//獲取sessionId
String sessionId=session.getId();
session.setMaxInactiveInterval(15);
//如果是新連線
if(session.isNew()){
Map<String,String> online=(Map<String, String>) application.getAttribute("online");
String user=(String) session.getAttribute("user");
user=(user==null?"遊客":user);
if(online==null){
online=new HashMap<String, String>();
}
online.put(sessionId, user);
application.setAttribute("online", online);
}
}
//當用戶與伺服器斷開session時觸發該方法
public void sessionDestroyed(HttpSessionEvent se) {
// TODO Auto-generated method stub
HttpSession session=se.getSession();
ServletContext application=session.getServletContext();
String sessionId=session.getId();
System.out.println("sessionId:"+sessionId);
HashMap<String,String> online=(HashMap<String, String>) application.getAttribute("online");
if(online!=null){
online.remove(sessionId);
}
application.setAttribute("online",online);
}
}
2、登入控制器
package Login;
import java.io.IOException;
import java.util.HashMap;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
public class LoginServlet extends HttpServlet{
public void service(HttpServletRequest request,HttpServletResponse response)throws ServletException,IOException{
String user=request.getParameter("user");
String pass=request.getParameter("pass");
HttpSession session=request.getSession();
//session.setMaxInactiveInterval(3);
session.setAttribute("user", user);
session.setAttribute("pass", pass);
ServletContext application=session.getServletContext();
HashMap<String,String> dataMap=(HashMap<String, String>) application.getAttribute("online");
if(dataMap==null){
dataMap=new HashMap<String, String>();
}
dataMap.put(session.getId(),user);
application.setAttribute("online", dataMap);
try {
//轉發
//request.getRequestDispatcher("/shop.jsp").forward(request, response);
//重定向
System.out.println("user1:"+session.getAttribute("user"));
response.sendRedirect("/webPrj/shop.jsp");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3、登入介面
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
application.setAttribute("addAttrName","addAttrValue");
application.removeAttribute("addAttrName");
application.setAttribute("newAttrName","newAttrValue");
application.setAttribute("newAttrName","1234567");
request.setAttribute("requestName1","requestValue1");
request.removeAttribute("requestName1");
request.setAttribute("requestName2","requestValue2");
request.setAttribute("requestName2","requestValue23");
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Login</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
${tip}<br>
<form action="login?action=service" method="post">
名稱:<input type="text" name="user"><br>
密碼:<input type="text" name="pass"><br/>
<input type="submit" value="登入"><input type="reset" value="重置">
</form>
</body>
</html>
4、線上使用者顯示
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'shop.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="buy.jsp">
書籍:<input type="checkbox" name="item" value="book">
電腦:<input type="checkbox" name="item" value="computer">
汽車:<input type="checkbox" name="item" value="car">
<input type="submit" value="提交">
</form>
<h1>線上使用者:</h1>
<table>
<tr>
<td>ID</td>
<td>名稱</td>
</tr>
<%
HashMap<String,String> online=(HashMap<String,String>)application.getAttribute("online");
for(String sessionId:online.keySet()){
%>
<tr>
<td><%=sessionId%></td>
<td><%=online.get(sessionId)%></td>
</tr>
<%
}
%>
</table>
</body>
</html>
三、使用RequestListener更精確監控使用者線上狀態
1、實現ServletRequestListener
package listener;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import dao.DbDao;
public class RequestListener implements ServletRequestListener,ServletRequestAttributeListener{
//當請求銷燬時觸發該方法
public void requestDestroyed(ServletRequestEvent sre) {
// TODO Auto-generated method stub
HttpServletRequest request=(HttpServletRequest)sre.getServletRequest();
System.out.println("----發向"+request.getRequestURI()+"被銷燬");
}
//當請求初始化時觸發該方法
public void requestInitialized(ServletRequestEvent sre) {
// TODO Auto-generated method stub
HttpServletRequest request=(HttpServletRequest)sre.getServletRequest();
System.out.println("---發向"+request.getRequestURI()+"被初始化");
HttpSession session=request.getSession();
//獲取sessionId
String sessionId=session.getId();
//獲取IP與地址
String ip=request.getRemoteAddr();
//獲取正在訪問的頁面
String page=request.getRequestURI();
//獲取使用者名稱稱
String user=(String)session.getAttribute("user");
user=(user==null)?"遊客":user;
DbDao db=new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/escshop", "root", "");
ResultSet rs=db.query("SELECT * FROM online_information WHERE sessionId=?", true, sessionId);
try {
if(rs.next()) {
rs.updateString(4, page);
rs.updateString(5,String.valueOf(System.currentTimeMillis()));
rs.updateRow();
rs.close();
}else{
db.insert(sessionId, user, ip, page, String.valueOf(System.currentTimeMillis()));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//當新增屬性時觸發該方法
public void attributeAdded(ServletRequestAttributeEvent srae) {
// TODO Auto-generated method stub
ServletContext request=srae.getServletContext();
String name=srae.getName();
Object value=srae.getValue();
System.out.println(request+"範圍內新增了屬性名為name="+name+"\t"+"屬性值為value="+value);
}
//當移除屬性時觸發該方法
public void attributeRemoved(ServletRequestAttributeEvent srae) {
// TODO Auto-generated method stub
ServletContext request=srae.getServletContext();
String name=srae.getName();
Object value=srae.getValue();
System.out.println(request+"範圍內移除了屬性名為name="+name+"\t"+"屬性值為value="+value);
}
//當替換屬性時觸發該方法
public void attributeReplaced(ServletRequestAttributeEvent srae) {
// TODO Auto-generated method stub
ServletContext request=srae.getServletContext();
String name=srae.getName();
Object value=srae.getValue();
System.out.println(request+"範圍內替換了屬性名為name="+name+"\t"+"屬性值為value="+value);
}
}
2、實現ServletContextListener監聽器
package listener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.swing.Timer;
import dao.DbDao;
public class OnlineRequestListener implements ServletContextListener{
//超過10分鐘沒訪問則判斷已經離線
public final int MAX_MILLITS=10*60*1000;
//應用銷燬時執行此方法
public void contextDestroyed(ServletContextEvent arg0) {
// TODO Auto-generated method stub
}
//應用啟動時執行此方法
public void contextInitialized(ServletContextEvent arg0) {
// TODO Auto-generated method stub
//每5秒檢查一次啊
new Timer(1000*5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
DbDao db=new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/escshop", "root", "");
ResultSet rs=db.query("SELECT * FROM online_information");
StringBuffer buff=new StringBuffer("(");
try {
while (rs.next()) {
//如果距離時間超過上次訪問時間
if(System.currentTimeMillis()-Long.parseLong(rs.getString("time"))>MAX_MILLITS){
buff.append("'");
buff.append(rs.getString(1));
buff.append("' ,");
}
}
System.out.println("buff:"+buff);
//有刪除的記錄
if(buff.length()>3){
buff.setLength(buff.length()-3);
buff.append("')");
//刪除所有在指定時間內未訪問的使用者資訊
String sql="delete from online_information where sessionId in"+buff.toString();
System.out.println("sql:"+sql);
db.delete(sql);
}
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}).start();
}
}
3、資料庫操作
package dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DbDao {
private String driver;
private String url;
private String user;
private String password;
//構造方法
public DbDao(String driver,String url,String user,String password){
this.driver=driver;
this.url=url;
this.user=user;
this.password=password;
}
//查詢指定ID資訊
public ResultSet query(String sql,boolean flag,String id){
ResultSet rs=null;
try {
Class.forName(driver);
try {
Connection conn=DriverManager.getConnection(url, user, password);
Statement smt=conn.createStatement();
if(flag){
sql=sql.replace("?","'"+id+"'");
}
rs=smt.executeQuery(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
//查詢所有資訊
public ResultSet query(String sql){
ResultSet rs=null;
try {
Class.forName(driver);
try {
Connection conn=DriverManager.getConnection(url, user, password);
Statement smt=conn.createStatement();
rs=smt.executeQuery(sql);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rs;
}
//插入資訊
public boolean insert(String sessionId,String userName,String ip,String page,String time){
boolean flag=false;
try {
Class.forName(driver);
try {
Connection conn=DriverManager.getConnection(url, user,password);
Statement smt=conn.createStatement();
String sql="INSERT INTO online_information(sessionId,USER,ip,page,TIME)"
+"VALUES('"+sessionId+"','"+userName+"','"+ip+"','"+page+"','"+time+"')";
System.out.println("SQL:"+sql);
flag=smt.executeUpdate(sql)>0?true:false;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return flag;
}
//刪除指定的目錄
public boolean delete(String sql){
boolean flag=false;
try {
Class.forName(driver);
try {
Connection conn=DriverManager.getConnection(url, user,password);
Statement smt=conn.createStatement();
flag=smt.executeUpdate(sql)>0?true:false;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return flag;
}
}
4、顯示線上人員狀態的JSP
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@page import="dao.DbDao"%>
<%@page import="java.sql.ResultSet"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>online線上人數</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
</head>
<body>
<h1>當前線上人員:</h1>
<table>
<%
DbDao db=new DbDao("com.mysql.jdbc.Driver","jdbc:mysql://localhost:3306/escshop", "root", "");
ResultSet rs= db.query("SELECT * FROM online_information");
while(rs.next()){
%>
<tr>
<td><%=rs.getString(1)%></td>
<td><%=rs.getString(2)%></td>
<td><%=rs.getString(3)%></td>
<td><%=rs.getString(4)%></td>
<td><%=rs.getString(5)%></td>
</tr>
<%} %>
</table>
</body>
</html>