servlet中监听器主要的监听对象有三个:
ServletContext HttpSession ServletRequest.
分别可以监听三个对象的创建 销毁,以及属性的更改。
=========================================
实现监听在线人数:
在开始实现功能之前首先创建一个用户模型,为了区别每个用户,我们用sessionId来作为一个用户的id,代码实现:
package model;
public class User {
private String ipStr;
private String address;
private String sessionId;
public User() {
super();
// TODO Auto-generated constructor stub
}
public String getSessionId() {
return sessionId;
}
public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}
public String getIpStr() {
return ipStr;
}
public void setIpStr(String ipStr) {
this.ipStr = ipStr;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
第一步:创建出存放在线用户的容器
当应用服务一旦启动,就创建出一个容器来存放在线的人数。这里使用到ServletContextListener。实现这个接口的监听器将监听到我们的服务器程序的启动和销毁。代码实现:
package listener;
import java.util.ArrayList;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import model.User;
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextDestroyed(ServletContextEvent event) {
System.out.println("===================servlet 服务销毁===================");
}
@Override
public void contextInitialized(ServletContextEvent event) {
ServletContext context = event.getServletContext();
ArrayList<User> userList = new ArrayList<>();
context.setAttribute("userList", userList);
System.out.println("===================servlet 服务启动===================");
}
}
把用户列表存放到servletContext这个对象中,这个对象的生命周期是整个服务程序的生命周期。
第二步:获得每个用户,并存放到容器中。
在一般的web程序中,用户一旦登录,我们会把用户的信息存放到session对象中。当用户退出登录时,从session对象中移除我们的用户信息。为了获取到用户的ip地址等详细信息。要用到ServletRequestListener这个接口。代码实现:
package listener;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import model.User;
@WebListener
public class MyHttpRequestListener implements ServletRequestListener {
@Override
public void requestDestroyed(ServletRequestEvent event) {
System.out.println("===================一个request销毁===================");
}
@Override
public void requestInitialized(ServletRequestEvent event) {
System.out.println("===================一个request创建===================");
HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
HttpSession session = request.getSession();
ServletContext app = session.getServletContext();
ArrayList<User> userList = (ArrayList<User>) app.getAttribute("userList");
//遍历用户列表,如果用户已经存放就不做操作
for (User user : userList) {
//这里用sessionID来模拟一个登陆的用户,正常应该是从session中getAttribute 到当前登录的用户
if(user.getSessionId().equals(session.getId())){
return;
}
}
//如果用户没有存放到我们的容器中,就吧这个用户存放到容器里面。这里只是模拟生成了一个用户。正常应该是直接把用户存放到servletContext 的 userList 这个容器中就可以了。
User currentUser = new User();
try {
currentUser.setIpStr(InetAddress.getLocalHost().getHostAddress());
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
currentUser.setSessionId(session.getId());
currentUser.setAddress("test");
URL url = null;
URLConnection connection = null;
try {
url = new URL("http://ip.taobao.com/service/getIpInfo.php?ip="+currentUser.getIpStr());
connection = url.openConnection();
connection.setConnectTimeout(2000);// 设置连接超时时间,单位毫秒
connection.setReadTimeout(2000);// 设置读取数据超时时间,单位毫秒
connection.setDoOutput(true);// 是否打开输出流 true|false
connection.setDoInput(true);// 是否打开输入流true|false
connection.setUseCaches(false);// 是否缓存true|false
connection.connect();// 打开连接端口
DataOutputStream out = new DataOutputStream(connection
.getOutputStream());// 打开输出流往对端服务器写数据
out.flush();// 刷新
out.close();// 关闭输出流
BufferedReader reader = new BufferedReader(new InputStreamReader(
connection.getInputStream(), "gbk"));// 往对端写完数据对端服务器返回数据
// ,以BufferedReader流来读取
StringBuffer buffer = new StringBuffer();
String line = "";
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
currentUser.setAddress(buffer.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
userList.add(currentUser);
app.setAttribute("userList", userList);
}
}
第三步:当用户退出后,从容器中移除用户
这里我们要监听到session的生命周期,用到HttpSessionListener这个接口。如果实现用户一段时间内不操作,销毁session的话要在web.xml中配置session超时:
<session-config>
<session-timeout>1</session-timeout>
</session-config>
HttpSessionListener,代码实现:
package listener;
import java.util.ArrayList;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import model.User;
@WebListener
public class MyHttpSessionListener implements HttpSessionListener {
@Override
public void sessionCreated(HttpSessionEvent event) {
System.out.println("===================一个session创建===================");
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
@SuppressWarnings("unchecked")
ArrayList<User> userList =(ArrayList<User>) session.getServletContext().getAttribute("userList");
ArrayList<User> newUserList = new ArrayList<>();
for (User user : userList) {
if (! user.getSessionId().equals(session.getId())) {
newUserList.add(user);
}
}
session.getServletContext().setAttribute("userList", newUserList);
System.out.println("===================一个session销毁===================");
}
}
至此大概思路已经完成。剩下的操作,按照需求完善。