思路
若密码验证成功,在context域(javaweb有四个域,context,session,request,page,范围依次从大到小)中加入一个Map<Integer, HttpSession>类型的map用于储存当前所有在线用户,key为独一无二的UID,value为用户登陆时的session对象。若已经登陆,则把之前的remove,然后再把当前session加入map中。
在登出方法中将改该session移除。
代码
login
//获取当前系统所有的在线用户
Map<Integer,HttpSession> onlineUserList=(Map<Integer, HttpSession>)request.getSession().getServletContext().getAttribute("ONLINE_USERS");
if(onlineUserList==null){
onlineUserList = new HashMap<>();
}
//如果当前用户存在其他session信息,那么就让旧的session失效,保证同时只有一人登录
HttpSession oldSession=onlineUserList.get(user.getUid());
if(oldSession!=null){
try {
oldSession.invalidate();
} catch (Exception e) {
System.out.println("session已过期");
e.printStackTrace();
}
onlineUserList.remove(user.getUid());
}
//记录新的session,并记录到所有用户下
onlineUserList.put(user.getUid(), session);
request.getSession().getServletContext().setAttribute("ONLINE_USERS",onlineUserList);
logout
Map<Integer,HttpSession> onlineUserList=(Map<Integer, HttpSession>)request.getSession().getServletContext().getAttribute("ONLINE_USERS");
HttpSession session = request.getSession();
if(onlineUserList != null && session.getAttribute("userDetails") != null){
User user = (User)session.getAttribute("userDetails");
onlineUserList.remove(user.getUid());
session.invalidate();
}
要注意的坑
- 刚开始没有用try-catch,是因为没有考虑到session过期的情况,默认30分钟无响应则session过期,此时用户没有通过logout按钮退出登录,因此session还在map中,但是这个session其实已经过期了,调用它的invalidate方法就会报错,又没有可以事先判断该session是否过期的方法,所以只能采用暴力且丑陋的try-catch。
- 由于注册完之后是直接变成登录状态,没有经过正常的login进行登录,导致服务器中有在线用户但是没有那个map,若此时用户点击登出,会产生空指针错误,所以要先判断是否为null。