用戶登錄唯一性


需求:
同一登錄人登錄后,在其他計算機登錄時,之前登錄的電腦上的賬號下線,並提示當前賬號在其他位置登錄。
 
設計思路:
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攔截器


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM