Web---Listener---在线用户管理案例

解决思路:

  • 使用HttpSessionListener记录在线人数。
  • 在用户访问时使用Filter进行IP登记,和用户是否登录校验。

效果:

主页

Web---Listener---在线用户管理案例_第1张图片

登录后

Web---Listener---在线用户管理案例_第2张图片

管理员,查看在线用户页面。管理员可以把登录用户踢出。

登录用户,查看在线用户页面。登录用户没有权限踢人。

游客只能查看新闻,点击查看在线用户时会被踢到登录页面

Web---Listener---在线用户管理案例_第3张图片

关键代码:

记录在线用户

采用HttpSessionListener监听器来进行记录在线用户,只要session创建就把该session和该session的id存起来。以便后面查看在线用户时封装数据显示。

因为多用户,即多线程问题,需要考虑多线程下数据的安全性,所以采用了效率高且安全的ConcurrentHashMap容器,同时还需注意,在项目中 onlines 是单例,创建时是以懒汉模式进行创建的,需要考虑多线程同时初始化问题,这里在初始化时采用同步块的方式即可解决该问题。

package cn.hncu.listener;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

public class MySessionListener implements HttpSessionListener {


    @SuppressWarnings("unchecked")
	public void sessionCreated(HttpSessionEvent se)  { 
    	//先从 ServletContext 中拿出 onlines 属性值
    	HttpSession session = se.getSession();
    	ServletContext sctx = session.getServletContext();
		Map onlines = (Map) sctx.getAttribute("onlines");
    	//判断 onlines 是否为null
    	if( onlines == null ) { //如果为null,则进行创建一个Map 
    		/* 因为 onlines 是多用户共享的,存在线程安全问题 
    		 * 所以采用 ConcurrentHashMap 线程安全的 Map,
    		 * 它采用 segment分段锁技术 理论上效率是 HashTable 的  16倍,16是分段锁的个数。默认是16个,可以更改。
    		 */
    		/* 可想而知 这里的 onlines 是单例,而且是懒汉模式 
    		 * 所以需要预防:两个或者更多 session 同时初始化时 从 ServletContext 
    		 * 中获取到的 onlines 都为 null 时,这时就要进行加锁,只能一个 session 来创建 
    		 * 并且加入到 ServletContext 中,其他的就 用 '第一个用户' 创建的  onlines 
    		 */
    		//拿锁
    		synchronized (MySessionListener.class) {
    			//从新获取一下
    			onlines = (Map)sctx.getAttribute("onlines");
    			//如果还是为null 那么 当前这个 session用户将是 被誉为'第一个用户'
				if( onlines == null ) {
					// '第一个用户' 进行创建 Map 容器
					onlines = new ConcurrentHashMap();
					//放入 sctx 中
					sctx.setAttribute("onlines", onlines);
				}
			}//释放锁
    	}
    	//把 sessionId 和 session 对象放入 现在用户池中
    	onlines.put(session.getId(), session);
    }
    //当 session调用  invalidate() 方法时 就会触发该方法
    public void sessionDestroyed(HttpSessionEvent se)  { 
    	// 1.获取 sessionId
    	String sessionId = se.getSession().getId();
    	// 2.获取 sctx
    	ServletContext sctx = se.getSession().getServletContext();
    	// 3.获取 onlines 在线用户池
    	@SuppressWarnings("unchecked")
		Map onlines = (Map) sctx.getAttribute("onlines");
    	// 4.判断 onlines 中是否含有 sessionId 的key值
    	if( onlines != null && onlines.containsKey(sessionId) ) { //防护一下
    		// 5.含有就从在线用户池中移除掉
    		onlines.remove(sessionId);
    	}
    }
	
}

封装显示数据的servlet

为了让JSP页面和后台的耦合度减低,使用ShowOnlinesServlet进行数据再封装后显示。把Map形式的数据该装成List>的形式,这样JSP页面数据只依赖util包中的类,后期维护也方便。

package cn.hncu.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

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 cn.hncu.domain.User;

public class ShowOnlinesServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//把 在线用户信息封装成 一个map,把所有用户封装成一个list
		
		// 1 获取onlines在线用户池
		@SuppressWarnings("unchecked")
		Map onlines = (Map) getServletContext().getAttribute("onlines");
		if( onlines == null ) {
			request.getSession().invalidate();
			return;
		}
		
		// 2 创建List> 集合
		List> onlineInfos = new ArrayList>();
		
		// 3 遍历onlines
		for (Entry entry : onlines.entrySet()) {
			HashMap onlineInfo = new HashMap();
			
			//封装用户
			HttpSession session = entry.getValue();
			User user = (User) session.getAttribute("user");
			onlineInfo.put("user", user);
			
			//封装第一次访问时间
			Date creationDate = new Date( session.getCreationTime() );
			onlineInfo.put("creationDate", creationDate);
			
			//封装上一次访问时间
			Date AccessedDate = new Date( session.getLastAccessedTime() );
			onlineInfo.put("AccessedDate", AccessedDate);
			
			//封装用户ip
			onlineInfo.put("IP", session.getAttribute("IP"));
			
			//封装sessionId以便踢出操作
			onlineInfo.put( "sessionId", entry.getKey() ); 
			
			//把 onlineInfo 加入到 onlineInfos
			onlineInfos.add(onlineInfo);
		}
		//收集完毕后,把信息传递给前端页面
		request.setAttribute("onlineInfos", onlineInfos);
		request.getRequestDispatcher("/jsps/show.jsp").forward(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	}

}

显示在线用户的JSP

采用了JSTL标签库进行数据显示。

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>



	
		
		在线用户管理
		
	
	
		
				
					
用户名 第一次访问时间 上一次访问时间 Ip 操作
游客 ${onlineInfo.user.name} ${onlineInfo.IP} 踢出

完整代码链接

你可能感兴趣的:(4.Web,Web,Listener,在线用户管理)