zoukankan      html  css  js  c++  java
  • 第七章 监听器listener单态登录使用案例学习心得

     
    前言:这个是我自己的学习笔记,用于加深自己对于java web 理解。
     
    单态登录,一个账号只可以在一台机器上登录(浏览器),如果在其他机器上登录了,则原来的登录自动失效。单台登录的目的是防止多台机器同时使用一个账号。
           书上P205用的案例是使用一个简单的JSP页面来模拟登录情况。
    自我总结:
           理解书上的这个案例我自我的总结是:
           1.Session对于每一个来访者都会产生一个session对象
           2.书上用的监听器可以监听到所用用户的session
           3.JSP页面是通过session中的personInfo是否有这个的值是否为null,显示页面的。只要认识到session中有个属性可以控制页面的显示。personInfo具体内容可以先不知道。
           4.Listener会监听每个新增的session,看session中的personInfo中的账号信息是否有重复的,如果有,就把原来的session中的提到的3中某个属性变为null。
           5.结合1和3,如果有账号重复登录的话,先登录的session的某个值就是空,那么它的页面就会跳转到登录的页面。
    JSP页面学习:
       
     <%
            String action =request.getParameter("action");
            String account =request.getParameter("account");        
            if("login".equals(action.toLowerCase())&&account.trim().length()>0)
            {
                PersonInfo ref_PersonInfo=new PersonInfo();
                ref_PersonInfo.setAccount(account.trim().toLowerCase());
                ref_PersonInfo.setIp(request.getRemoteAddr());
                ref_PersonInfo.setLoginDate(new java.util.Date());            
                session.setAttribute("personInfo",ref_PersonInfo);            
                response.sendRedirect(response.encodeRedirectUrl(request.getRequestURI()));
                return;
            }else if("logout".equals(action)){
                session.removeAttribute("persionInfo");
                response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
                return;
            }
     %>  
    这部分代码是jsp页面的最先开始执行的可以判断用户是否执行登录或者注销操作。如果执行最后都会执行return语句,就不会显示下面的jsp代码部分了。
    <c:choose>
     
    <c:when test="${ personInfo != null }">
    <!-- 已经登录,将显示帐号信息 -->
    欢迎您,${ personInfo.account }。<br/> 
    您的登录IP为${ personInfo.ip },<br/>
    登录时间为<fmt:formatDate value="${ personInfo.loginDate }" pattern="yyyy-MM-dd HH:mm"/>。
    <a href="${ pageContext.request.requestURI }?action=logout">退出</a>
     
    <!-- 每5秒钟刷新一次页面 -->
    <script>setTimeout("location=location; ", 5000); </script>
    </c:when>
     
    <c:otherwise>
    <!-- 没有登录,将显示登录页面 -->
    ${ msg } 
    <c:remove var="msg" scope="session" />
    <form action="${ pageContext.request.requestURI }?action=login" method="post">
    帐号:
    <input name="account" />
    <input type="submit" value="登录">
    </form>
    </c:otherwise>
     
    </c:choose>
    这部分代码就是根据session中是否有 personInfo 属性,决定显示的具体页面是什么!请注意这几个式子${ personInfo != null },${ msg } 这个是EL表达式,可以找到session中的相关属性,其中 ${ msg } msg是在监听器中设置的消息。具体页面只用两种:登录页面和没有登录页面,判断标准是"${ personInfo != null }"。如果你是登录状态你的personInfo不为空null,如果有人修改了你的session,让你personInfo,页面每5秒钟刷新一次<script>setTimeout("location=location; ", 5000); </script>,那么就会显示没有登录页面。具体的修改session的状态是Listener中实现的
    <%@ page language="java" contentType="text/html; charset=UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
    <jsp:directive.page import="hellojava.listener.singleton.PersonInfo" />
    <%
            String action =request.getParameter("action");
            String account =request.getParameter("account");
            
            if("login".equals(action.toLowerCase())&&account.trim().length()>0)
            {
                PersonInfo ref_PersonInfo=new PersonInfo();
                ref_PersonInfo.setAccount(account.trim().toLowerCase());
                ref_PersonInfo.setIp(request.getRemoteAddr());
                ref_PersonInfo.setLoginDate(new java.util.Date());
                
                session.setAttribute("personInfo",ref_PersonInfo);
                
                response.sendRedirect(response.encodeRedirectUrl(request.getRequestURI()));
                return;
            }else if("logout".equals(action)){
                session.removeAttribute("persionInfo");
                response.sendRedirect(response.encodeRedirectURL(request.getRequestURI()));
                return;
            }
     %>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Insert title here</title>
            <style type="text/css">
            body {
                font-size:12px; 
            }
            </style>
        </head>
        <body>
            
            <c:choose>
            
                <c:when test="${ personInfo != null }">
                    <!-- 已经登录,将显示帐号信息 -->
                    欢迎您,${ personInfo.account }。<br/> 
                    您的登录IP为${ personInfo.ip },<br/>
                    登录时间为<fmt:formatDate value="${ personInfo.loginDate }" pattern="yyyy-MM-dd HH:mm"/><a href="${ pageContext.request.requestURI }?action=logout">退出</a>
                    
                    <!-- 每5秒钟刷新一次页面 -->
                    <script>setTimeout("location=location; ", 5000); </script>
                </c:when>
                
                <c:otherwise>
                    <!-- 没有登录,将显示登录页面 -->
                    ${ msg } 
                    <c:remove var="msg" scope="session" />
                    <form action="${ pageContext.request.requestURI }?action=login" method="post">
                        帐号:
                        <input name="account" />
                        <input type="submit" value="登录">
                    </form>
                </c:otherwise>
            
            </c:choose>
    
        </body>
    </html>
     
    JSP源代码

     LoginSessionListener代码学习:

    package com.helloweenvsfei.singleton;
    
    import java.util.HashMap;
    import java.util.Map;
    
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    
    public class LoginSessionListener implements HttpSessionAttributeListener {
    
        Log log = LogFactory.getLog(this.getClass());
    
        Map<String, HttpSession> map = new HashMap<String, HttpSession>();
    
        public void attributeAdded(HttpSessionBindingEvent event) {
    
            String name = event.getName();
    
            // 登录
            if (name.equals("personInfo")) {
    
                PersonInfo personInfo = (PersonInfo) event.getValue();
    
                if (map.get(personInfo.getAccount()) != null) {
    
                    // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
                    HttpSession session = map.get(personInfo.getAccount());
                    PersonInfo oldPersonInfo = (PersonInfo) session
                            .getAttribute("personInfo");
    
                    log.info("帐号" + oldPersonInfo.getAccount() + "在"
                            + oldPersonInfo.getIp() + "已经登录,该登录将被迫下线。");
    
                    session.removeAttribute("personInfo");
                    session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
                }
    
                // 将session以用户名为索引,放入map中
                map.put(personInfo.getAccount(), event.getSession());
                log.info("帐号" + personInfo.getAccount() + "在" + personInfo.getIp()
                        + "登录。");
            }
        }
    
        public void attributeRemoved(HttpSessionBindingEvent event) {
    
            String name = event.getName();
    
            // 注销
            if (name.equals("personInfo")) {
                // 将该session从map中移除
                PersonInfo personInfo = (PersonInfo) event.getValue();
                map.remove(personInfo.getAccount());
                log.info("帐号" + personInfo.getAccount() + "注销。");
            }
        }
    
        public void attributeReplaced(HttpSessionBindingEvent event) {
    
            String name = event.getName();
    
            // 没有注销的情况下,用另一个帐号登录
            if (name.equals("personInfo")) {
    
                // 移除旧的的登录信息
                PersonInfo oldPersonInfo = (PersonInfo) event.getValue();
                map.remove(oldPersonInfo.getAccount());
    
                // 新的登录信息
                PersonInfo personInfo = (PersonInfo) event.getSession()
                        .getAttribute("personInfo");
    
                // 也要检查新登录的帐号是否在别的机器上登录过
                if (map.get(personInfo.getAccount()) != null) {
                    // map 中有记录,表明该帐号在其他机器上登录过,将以前的登录失效
                    HttpSession session = map.get(personInfo.getAccount());
                    session.removeAttribute("personInfo");
                    session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");
                }
                map.put("personInfo", event.getSession());
            }
    
        }
    
    }
    LoginSessionListener 源代码
    源代码中有一个非常重要的数据结构为Map<String, HttpSession> map = new HashMap<String, HttpSession>();这个数据结构保存了所有的账户和session的对应关系,一旦jsp中的session添加了personInfo,都会调用
    public void attributeAdded(HttpSessionBindingEvent event) {...}方法,会在map中查找账户是否已经有了对应的session,如果已经有了,那么就把查找到的session中personInfo移除,这个时候前台的jsp页面每5秒刷新一次,发现personInfo为空就会显示为未登录页面。请注意里面有这个语句:session.setAttribute("msg", "您的帐号已经在其他机器上登录,您被迫下线。");这个时候JSP页面就会通过EL表达式${msg}读到这条消息了。
    public void attributeRemoved(HttpSessionBindingEvent event) 方法当session中的personInfo设置为空时,会触发这个方法,他会把相应的session从map中移除。
     
                                                                                                                                                                     菜包子
                                                                                                                                                 2013年6月9日10:30:13 于马甸桥东
     
     
     
     
     
  • 相关阅读:
    第38章 刷新令牌
    第37章 资源所有者密码验证(Resource Owner Password Validation)
    第36章 扩展授权
    第35章 秘密(secrets)
    第34章 授予类型
    node.js+ react + redux 环境搭建
    资源整理
    django form 组件插件
    django cookies与session
    django 初始命令
  • 原文地址:https://www.cnblogs.com/CaiBaoZi/p/3128193.html
Copyright © 2011-2022 走看看