• 用户登录唯一性


    需求:
    同一登录人登录后,在其他计算机登录时,之前登录的电脑上的账号下线,并提示当前账号在其他位置登录。
     
    设计思路:
    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拦截器
  • 相关阅读:
    js触摸屏案例
    Docker
    Docker 镜像加速
    Docker 命令大全
    linux gpasswd
    Docker基础教程
    PHP输出毫秒时间戳
    PHP Variable handling 函数
    Partition Array by Odd and Even
    Median
  • 原文地址:https://www.cnblogs.com/cgfpx/p/11584281.html
Copyright © 2020-2023  润新知