有关登录限制综合案例的疑问
来源:2-4 实现动态图表
哆丶哆
2019-07-13 17:57:35
老师,在学习本章的综合案例时,主要是实现用户登录限制的功能:即一个用户在同一时间只能在一个浏览器上登录,第二次登录同账户时,会把原账户“踢下去”。我看了视频讲解以及相关代码,如下是实现逻辑功能的相关的java类,我发现思想大致是这样的:
用户第一次登录,触发session添加属性的监听方法,为用户名设置sessionID和session对象的映射,顺利登录系统
用户第二次在别处登录时(用户名和第一次一样),在填写用户名点击登录时候,触发了session添加属性的监听方法,会判断出这个用户名所映射的sessionID是否为空,不为空说明之前已经有登录过,则要清空之前的session,重新为用户名映射新的sessionID和session对象
第一次登录用户的地方,由于session会话信息被清空了,当再次访问首页时,由于没有登录信息,会被拦截器拦截,强制进入登录页面,需要重新登录
对此,学生产生的几个疑问:
1.请问我对本项目的实现思想理解正确么?
2.如果我理解无误,那么,我想象有这么一个情况:张三和李四同时在A电脑的浏览器打开不同窗口分别登录系统,因为是在同一个浏览器,所以张三和李四所用的session会话对象应该是同一个。这时,第三个人在B电脑登录了张三的帐号,按照代码逻辑,应该把张三之前映射的session对象数据清空,重新在B电脑生成的新的session对象与张三用户名进行重新映射。可是这样的话,虽然张三能被顺利限制登录,但是和他公用一个session对象的李四不也被一起“踢出系统”了么?可是现实中并没有人在其他地方登录李四的账号呀。那要怎么在代码中防止这种不合理的情况发生呢?
3.从代码上可以看出,用户名和session的相关映射关系被保留到同一个LoginCache类的单例对象 中,请问,这个对象的生命周期是多长呢?是从被创建开始就一直存在,直到服务器关闭销毁么?
单例对象LoginCache.java:
package com.imooc.cache;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
/**
* 登录用户与session缓存对象
* @author lv
*
*/
public class LoginCache {
private static LoginCache instance = new LoginCache();
private Map<String,String> loginUserSession = new HashMap<String,String>();// key值:登录用户登录名,value值:登录用户sessionId
private Map<String,HttpSession> loginSession = new HashMap<String,HttpSession>();//key值:登录用户sessionId,value值:登录用户session对象
private LoginCache(){
}
public static LoginCache getInstance(){
return instance;
}
/**
* 通过登录名获取对应登录用户的sessionId
* @param username
* @return
*/
public String getSessionIdByUsername(String username){
return loginUserSession.get(username);
}
/**
* 通过sessionId获取对应的session对象
* @param sessionId
* @return
*/
public HttpSession getSessionBySessionId(String sessionId){
return loginSession.get(sessionId);
}
/**
* 存储登录名与对应的登录sessionID至缓存对象
* @param username
* @param sessionId
*/
public void setSessionIdByUserName(String username,String sessionId){
loginUserSession.put(username, sessionId);
}
/**
* 存储sessionId与对应的session对象至缓存对象
* @param sessionId
* @param session
*/
public void setSessionBySessionId(String sessionId,HttpSession session){
loginSession.put(sessionId, session);
}
}过滤器SessionFilter.java:
package com.imooc.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 用户登录权限过滤器
* @author lv
*
*/
public class SessionFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hrequest = (HttpServletRequest)request;
HttpServletResponse hresponse = (HttpServletResponse)response;
String loginUser = (String)hrequest.getSession().getAttribute("loginUser");//从session对象中获取登录用户名
if(loginUser==null){//登录用户名不存在,用户未登录,强制重定向至登陆页面
hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");
return;
}else{
chain.doFilter(request, response);//已登录,转入相应的请求处理
return;
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}监听器LoginSessionListener .java:
package com.imooc.listener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import com.imooc.cache.LoginCache;
/**
* 用户登录监听器
* @author lv
*
*/
public class LoginSessionListener implements HttpSessionAttributeListener {
private static final String LOGIN_USER="loginUser";
@Override
public void attributeAdded(HttpSessionBindingEvent hsbe) {
String attrName = hsbe.getName();//监听到session属性值发生添加操作,获取对应操作的属性名
if(LOGIN_USER.equals(attrName)){//若属性名为登录属性名,判定为用户登录操作
String attrVal = (String)hsbe.getValue();//获取添加的属性值,即用户登录名
HttpSession session = hsbe.getSession();//该次操作的session对象
String sessionId = session.getId();//该次操作的session对象ID
String sessionId2 = LoginCache.getInstance().getSessionIdByUsername(attrVal);//从缓存对象里面,获得该用户登录名对应的sessionID值
if(null == sessionId2){//未获得结果,不需要清理前次登录用户会话信息
}else{
HttpSession session2 = LoginCache.getInstance().getSessionBySessionId(sessionId2);//获取前次该用户登录对应的session对象
session2.invalidate();//清理前次登录用户会话存储信息,使得前次登录失效
}
//完成该次登录用户登录名、sessionID,session对象的缓存对象存储
LoginCache.getInstance().setSessionIdByUserName(attrVal, sessionId);
LoginCache.getInstance().setSessionBySessionId(sessionId, session);
}
}
@Override
public void attributeRemoved(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void attributeReplaced(HttpSessionBindingEvent arg0) {
// TODO Auto-generated method stub
}
}1回答
1、同学对本项目理解的是正确的。
2、一般情况下,在同一个浏览器,打开不同的窗口,并不能登录两个账号,如果登录第二个账户的时候,则第一个账户则被踢下去了。并且两个账户不能共用一个session的,当登录的是李四的时候,就会创建一个新的session了。所以也就不会出现同学说的第二种情况了。(同学想想,你可以在同一个浏览器登录两个京东,或者淘宝的账号吗?即使开两个窗口也不行)
3、这个对象的生命周期是从被创建开始就一直存在,直到服务器关闭销毁。
如果我的回答解决了你的疑惑,请采纳!祝学习愉快!
相似问题