在线用户统计(一)

          好久之前看过下在线人数统计的问题,现在重新整理了一下,把自己写的一些例子发出来和大家分享,希望大家也提出一些想法或者例子,一起研究出最好的方案=^^=

在写文章之前先介绍一个HttpSessionBindingListener这个监听器,用来监听自己什么时候增加到会话中,或者从会话删除。实现HttpSessionBindingListener这个接口要实现2个方法:valueBound(当我知道我在一个会话中时要运行的代码),valueUnbound(当我知道已经不在一个会话时要运行的代码)

代码如下:
//实现一个HttpSessionBindingListener监听器-----OnLineUser.java

import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import org.apache.log4j.Logger;
import java.util.*;

public class OnLineUser implements HttpSessionBindingListener {

	static Logger logger = Logger.getLogger(OnLineUser.class.getName());

	// 创建一个静态变量来保存在线用户
	private static Vector<String> users = new Vector<String>();
    
	//返回当前在线人数
	public int getCount() {

		return users.size();
	}
    
	//判断用户是否重复登陆
	public boolean existUser(String userName) {

		boolean existUser = false; // 用户不存在
		for (int i = 0; i < users.size(); i++) {
			if (userName.equals((String) users.get(i))) {
				existUser = true; // 用户已存在
				break;
			}
		}
		return existUser;
	}
    
	//从统计中删除用户
	public boolean deleteUser(String userName) {
		OnLineUser.logger.info("=============移除用户============");
		boolean flag = false;
		for (int i = 0; i < users.size(); i++) {
			if (userName.equals((String) users.get(i))) {
				users.remove(i);
				flag = true;
				break;
			}
		}
		return flag;
	}

	public void valueBound(HttpSessionBindingEvent e) {
		//每当OnLineUser这个实例被绑定到会话里面,就从统计中增加一个在线用户		
        users.add(e.getName());

		OnLineUser.logger.info(e.getName() + "\t登入到系统\t" + (new Date()));

		for (int i = 0; i < users.size(); i++) {
			OnLineUser.logger.info("第"+ (i+1) + "个在线用户:" + users.get(i));
		}
		OnLineUser.logger.info("在线用户数为:" + getCount() + "人");


	}

	public void valueUnbound(HttpSessionBindingEvent e) {
		String userName = e.getName();
        //每当OnLineUser的实例与Session解除绑定时,就从统计中移除改在线用户
		boolean flag = deleteUser(userName);
		if (flag == true) {
			OnLineUser.logger.info(userName + "\t退出系统\t" + (new Date()));
			OnLineUser.logger.info("\t在线用户数为:" + getCount());
		}
	}
    
	public static Vector getUsers() {
		return users;
	}

}

//敲完Listener的代码需要在DD中(web.xml)文件配置一下,只需要在web.xml增加下面这段即可
<!-- 配置listener -->
<listener>
<listener-class>com.listener.OnLineUser</listener-class>
</listener>
         <!--注意路径不一定是com.listener.OnLineUser,需按照你自己的实际路径 -->



//模拟一个业务逻辑组件的实现-----Service.java
public class Service {
     private static Service service;
     
	 private  String[] user = {"Jam","Rjx","Wjm","Jason"};
	 private  String[] pass = {"123","123","123","123"};
	   
     //单例模式的私有构造函数
     private Service(){
    	 
     }
     
     //返回Service实例
     public static Service getInstance(){
    	 if(service == null){
    		 synchronized(Service.class){
    			 if(service == null){
    				 service = new Service();
    			 }
    		 }
    	 }
    	 return service;
     }
     
     //本来是去数据库检查帐号密码是否一致,这里把情况简单化
     public boolean checkUser(String userName,String password){

    	   for(int i=0;i<user.length;i++){
    		   if(userName.equals(user[i]) && password.equals(pass[i])){
    			   return true;
    		   }    		  
    	   }
    	   return false;
     }
}




//控制层(表示层)的实现,当用户提交表单时就会来到这个Servlet-----LoginServlet.java
public class LoginServlet extends HttpServlet {
   
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	    doPost(request,response);
	}

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

		String userName = request.getParameter("userName");
		String password = request.getParameter("password");
		
		HttpSession session = request.getSession();
		
//调用service组件的checkUser方法
		boolean flag = Service.getInstance().checkUser(userName, password);
		if(flag == true){
			OnLineUser onLineUser = new OnLineUser();
			if(onLineUser.existUser(userName)){
				OnLineUser.logger.info(userName+"重复登陆");
				
			}
			else{
				
				session.setAttribute(userName, onLineUser);
//设置session的失效时间(秒为单位)
				session.setMaxInactiveInterval(10);
			}
		}
//跳转(请求分派)到onLineResult.jsp页面
		request.getRequestDispatcher("onLineResult.jsp").forward(request, response);
	}

}

//省略了Servlet在DD中的配置文件





//jsp客户端代码如下,代码比较简单,就不左解释了哈:)-----onLineLogin.jsp
<html>
  <head>
    <title>统计在线人数登陆页面</title>
  </head>
  
  <body>
        
     <form action="LoginServlet" method="post">
        <table border="1">
            <tr><td colspan="2" align="center"><font color="red">在线人数统计调查表</font></td></tr>
            <tr><td>请输入名字:</td><td><input type="text" name="userName"/></td></tr>              
            <tr><td>请输入密码:</td><td><input type="text" name="password"/></td></tr> 
            <tr align="center"><td colspan="2"><input type="submit" value="提交"></td></tr>
        </table>
     </form>
  </body>
</html>



//访问完控制层跳转的页面,显示在线人数-----onLineResult.jsp

<html>
  <head>
    <title>统计在线人数结果</title>
  </head> 
  <body>
    现在的在线人数是:<%=OnLineUser.getUsers().size() %>
  </body>
</html>




小结:在测试的过程中,我发现就算我设置session的过期时间为1秒,也要等几十秒,才会执行valueUnbound这个方法,不知道是session过期有延迟,还是监听器本身有延迟,暂时没什么头绪。至于这个做法,其中一个缺点是,当在线用户人数多的时候,后台会产生大量的OnLineUser的实例。欢迎大家提出更好的建议和方法:)

你可能感兴趣的:(xml,log4j,Web,jsp,servlet)