流浪遇上光辉

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
需求:
同一登录人登录后,在其他计算机登录时,之前登录的电脑上的账号下线,并提示当前账号在其他位置登录。
 
设计思路:
1.新建一个全局类,用来存储全局的SessionId静态变量map。
2.在登录的后台逻辑里,将用户ID为key,SessionID为value存放在这个类中,其他计算机登录时,覆盖这个SessionID。
3.在springMVC拦截器的预处理方法preHandle中,判断当前登录的SessionID和全局类中的SessionID是否一致,如果不一致重定向登录页,并带参数code
4.在登录页判断code是否有值,如果有值,证明是被迫下线的,弹窗提示当前账号在其他位置登录。
5.新增session监听器,如果该用户下线,销毁session的时候,删除在全局类中该用户的key,value,避免只存不删,有内存溢出的风险。
 
代码:
实体类:
/**
 * 全局类,用来存储全局的SessionId静态变量
 * @authour ZZD
 * @date 2019/4/26 11:09
 **/
public class SessionSave {
 
    private static Map<String,String> SessionIdSave = new HashMap();
 
    public static Map<String, String> getSessionIdSave() {
        return SessionIdSave;
    } 
    public static void setSessionIdSave(Map<String, String> sessionIdSave) {
        SessionIdSave = sessionIdSave;
    }
} 
controller:
@RequestMapping("/login")
@ResponseBody
public String login(HttpServletRequest request) {
    /****省略其他逻辑*****/
    /**
 * 用户登录唯一性
 */
//登录人ID,用于作为key
String userID = user.getUserID();
//session的ID,用于作为value
String sessionID = request.getRequestedSessionId();
//判断全局类中是否有该用户id的key,如果没有则添加,如果有且session不同,更换session的id为当前登录人的session的id
if (!SessionSave.getSessionIdSave().containsKey(userID)) {
    SessionSave.getSessionIdSave().put(userID, sessionID);
}else if(SessionSave.getSessionIdSave().containsKey(userID)&&!sessionID.equals(SessionSave.getSessionIdSave().get(userID))){
    SessionSave.getSessionIdSave().remove(userID);
    SessionSave.getSessionIdSave().put(userID, sessionID);
}
return "main";
}
springMVC拦截器:
public class LoginInterceptor extends HandlerInterceptorAdapter {
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      /******省略其他逻辑****/
         String sessionId = SessionSave.getSessionIdSave().get(result.getUserID());//获取全局类SessionSave保存账户的静态sessionId
         String currentSessionId = request.getSession().getId();//获取当前的sessionId
         if (!currentSessionId.equals(sessionId)) {//如果两个sessionId不等,则当前账户强制下线,需要重新登录
            String serverPath = request.getScheme()+"://"+request.getServerName()+":"+
                  request.getServerPort()+request.getContextPath()+"/";
            //重定向带参数code为1  index为登录页面的Controller路径
            response.sendRedirect(serverPath + "index?code=1");
            return false;
         }
      return super.preHandle(request, response, handler);
   }
   @Override
   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
session监听器:
/**
 * 监听session销毁
 * @authour ZZD
 * @date 2019/4/26 15:15
 **/
@WebListener
public class SessionListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {
    }
    /**
     * 监听session销毁,得到销毁的sessionID,然后根据sessionID删除全局的SessionSave中的键值对,避免只插不删,有内存溢出的风险
     * @param httpSessionEvent
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
       Map<String,String> map =  SessionSave.getSessionIdSave();
       String sessionId = httpSessionEvent.getSession().getId();
       //根据value删除map的键值对
        Collection<String> col = map.values();
        while(true == col.contains(sessionId)) {
            col.remove(sessionId);
        }
    }
}
index的controller和对应的jsp这里就不展示了。
 
用到的基础:
 
局部变量:
定义在方法中的变量都是局部变量(main方法也是方法,所以定义在main方法中的变量也是局部变量)。
生存周期:
局部变量的生存周期和方法的生存周期一致,调用该方法声明局部变量并初始化时,该局部变量被创建并分配内存空间;直到该方法调用结束,局部变量也就结束了。
是否需要初始化:
局部变量在使用前必须进行初始化,系统默认不会对局部变量进行初始化操作,如果局部变量在使用前,没有进行初始化则会在编译期报错;
创建位置:
局部变量是创建在栈内存中的;
全局变量:
非静态全局变量:
非静态全局变量都是定在类中,是类的成员变量或者说是成员属性属于类的一部分(或 者说是对象的一部分);
生存周期:
非静态全局变量加载在堆内存中,随着声明初始化而创建,随着对象消亡而消亡;
是否需要初始化:
全局变量都是不需要被强制初始化的,系统都会默认根据其数据类型进行默认赋值;但是建议 在声明时都进行初始化操作;
创建位置:
创建在堆内存中,因为非静态的全局变量数对象的成员变量是对象的一部分;
静态全局变量:
静态的类成员变量;
生存时间:
静态全局变量随着类的字节码文件加载而加载产生,随着字节码文件的消失而消失,生存时间比类的 对象还要长;
是否初始化:
凡是全局变量都是可以不要初始化的,静态变量也是一样,系统会自动根据其数据类型进行赋默认值,但是建议变量在声明时都进行初始化;
创建位置:
静态变量时存在于对内存中的,所以静态全局变量也是存在于堆内存中的。
 
监听器
监听器用于监听对象的上的事件发生,在Servlet中监听器主要监听请求对象、会话对象、上下文对象以及监听这些对象的作用域操作。JavaEE为我们提供了一系列的监听器接口,开发时按需实现相应的接口即可。
监听器
说明
ServletRequestListener
监听请求对象的创建和销毁
HttpSesisonListener
监听会话对象的创建和销毁
ServletContextListener
监听Servlet上下文对象的创建和销毁
作用:
a.统计在线人数 :利用HttpSessionLisener来实现
b.加载初始化信息:利用ServletContextListener来实现
c.统计网站的访问量
d.监控访问信息
 
springMVC拦截器
posted on 2019-09-25 14:22  流浪遇上光辉  阅读(1654)  评论(0编辑  收藏  举报