【JavaWeb】用监听器实现单一登录
导读:监听器用来监视ServletContext/Session/Request的创建、初始化、销毁以及其中的属性变动。
监听器的分类
常见的主要有以下6个,分别处理Servlet全局、Session和Request。
- ServletContextListener
- ServletContextAttributeListener
- HttpSessionListener
- HttpSessionAttributeListener
- ServletRequestListener
- ServletRequestAttributeListenser
监听器的作用
由于每当一个用户访问一个网站都会产生一个会话或是一个请求,所以可以使用监听器来监视这些会话和请求,能够用于
- 统计在线人数
- 统计访问量
- 应用启动时信息初始化
- 与Spring结合
监听器的实现
根据需要实现上述的六种接口,对象监听器实现Init和Destroy方法,属性监听器实现Add/Remove/Replace方法。然后在web.xml中对监听器进行配置,相比于Servlet和Filter,监听器的配置更为简单。
ServletContextListener举例
public class MyServletContextListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {String appName=sce.getServletContext().getInitParameter("app_name");String version=sce.getServletContext().getInitParameter("version");sce.getServletContext().setAttribute("app_name",appName);sce.getServletContext().setAttribute("version",version);System.out.println("Init:"+appName+" "+version);}@Overridepublic void contextDestroyed(ServletContextEvent sce) {String appName=(String)sce.getServletContext().getAttribute("app_name");String version=(String)sce.getServletContext().getAttribute("version");System.out.println("Destroy:"+appName+" "+version);}
}
在web.xml中进行配置,设置全局属性,用于获取。
<context-param><param-name>app_name</param-name><param-value>Listener Web</param-value>
</context-param>
<context-param><param-name>version</param-name><param-value>1.0</param-value>
</context-param><listener><listener-class>listener.MyServletContextListener</listener-class>
</listener>
这样,一旦WEB应用一启动,监听器就能够监视ServletContext对象的创建和销毁,控制台就会输出"Init:Listener 1.0",关闭WEB应用,就会输出"Destroy:Listener 1.0"。
对于Session和Request也类似,只要一创建新的Session和Request,就会被监听器所捕获到,执行操作。
ServletContextAttributeListener举例
属性监视器用来监视属性的添加、变换和移除。新建一个全局属性监听器。
public class MyServletContextAttrListener implements ServletContextAttributeListener {@Overridepublic void attributeAdded(ServletContextAttributeEvent scae) {System.out.println(scae.getName()+scae.getValue());}@Overridepublic void attributeRemoved(ServletContextAttributeEvent scae) {System.out.println(scae.getName()+scae.getValue());}@Overridepublic void attributeReplaced(ServletContextAttributeEvent scae) {System.out.println(scae.getName()+scae.getValue());}
}
新建一个jsp,用于添加全局属性:
<%application.setAttribute("servletContextPar","servlet");
%>
访问这个jsp,由于执行了添加属性的操作,所以会在后台输出属性名和属性值。
其它属性监听器类似。
监听器实现单一登录
类似QQ这种软件,当用户在别处登录时,本地登录将会被“挤掉”,可以用监听器来实现。下面的案例,使用HttpSessionAttributeListener来实现这个功能。
登录:
index首页有一个表单,用于提交用户名和密码,然后发送请求参数到login.jsp。在login.jsp中,将传过来的用户名存放在名为loginUser的session属性中,接着重定向到主页main.jsp。
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<%String username=request.getParameter("username");session.setAttribute("loginUser",username);response.sendRedirect(request.getContextPath()+"/main.jsp");
%>
main.jsp中,需要获取重定向过来的username,并在页面上显示:
<%String user = (String)session.getAttribute("loginUser");
%><ul class="navig"><li><a href="index.html" class="scroll"><%=user %></a><span>|</span></li><li><a href="index.html" class="scroll">HOME</a><span>|</span></li><li><a href="#portfolio" class="scroll">PORTFOLIO</a><span>|</span></li><li><a href="#contact" class="scroll">CONTACT</a></li>
</ul>
过滤器拦截:
如果用户未经登录,就想访问main.jsp,会被拒绝,重新定向到登录页面,并附带一条错误信息,这就需要创建一个Filter来处理。
public class SessionFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletRequest hrequest=(HttpServletRequest)request;HttpServletResponse hresponse=(HttpServletResponse)response;//获取session中的loginUserString loginUser=(String)hrequest.getSession().getAttribute("loginUser");if(loginUser==null){//如果为空,则表示用户没有登录,返回到index.jsp并附带消息hresponse.sendRedirect(hrequest.getContextPath()+"/index.jsp?flag=1");}else{chain.doFilter(request,response);}}
}
在index.jsp登录页面中,先获取过滤器传过来的flag参数,再显示警告。
<%String flag=request.getParameter("flag");
%><script type="text/javascript">var flag='<%=flag%>'if(flag=="1"){alert("尚未登录或在异地登录,请重新登录!")}
</script>
单例类构建:
由于只允许一个用户登录,需要一个单例类来封装这个用户。这个单例类用来映射用户名-SessionId,SessionId-Session的关系。由于3.0以上的Servlet不能由sessionId获取到session,所以需要直接写一个由sessionId获取session的方法。
还有一点,为什么不直接使用用户名去映射session,而是要通过sessionId来中转一下。这是因为同一个浏览器的同一个用户,如果退出了浏览器,此时session还在,当这个用户再访问网站时,会建立一个新的session,释放旧的session,浪费资源。如果通过用户名-sessionId,得知当前浏览器当前用户又一次登录了,直接用这个用户名之前的sessionId获取之前的session就行了,避免了资源浪费。
public class LoginCache {//单例类要点private static LoginCache instance=new LoginCache();private LoginCache(){}public static LoginCache getInstance(){ return instance; }//用户名跟sessionId映射private Map<String,String>loginUserSession=new HashMap<>();//sessionId和session的映射private Map<String, HttpSession>loginSession=new HashMap<>();public String getSessionIdByUsername(String username){return loginUserSession.get(username);}public HttpSession getSessionBySessionId(String sessionId){return loginSession.get(sessionId);}public void setSessionIdByUserName(String username,String sessionId){loginUserSession.put(username,sessionId);}public void setSessionBySessionId(String sessionId,HttpSession session){loginSession.put(sessionId,session);}
}
监听器构建:
public class LoginSessionListener implements HttpSessionAttributeListener {private static final String LOGIN_USER="loginUser";@Overridepublic void attributeAdded(HttpSessionBindingEvent hsbe) {//获取新添加的属性名String attrName=hsbe.getName();//如果=loginUser,就表示有新用户登录了if(LOGIN_USER.equals(attrName)){//获得新登录的用户名String attrVal=(String)hsbe.getValue();//获得当前会话(新登录)的Session对象HttpSession session=hsbe.getSession();//获得SessionIdString sessionId=session.getId();//在LoginCache中查找新登录的用户名是否存在String sessionId2=LoginCache.getInstance().getSessionIdByUsername(attrVal);if(sessionId2==null){}//如果存在else{//就获取之前用户的SessionId2,并将其释放HttpSession session2=LoginCache.getInstance().getSessionBySessionId(sessionId2);session2.invalidate();}//添加刚才登录的Session作为已存在的SessionLoginCache.getInstance().setSessionIdByUserName(attrVal,sessionId);LoginCache.getInstance().setSessionBySessionId(sessionId,session);}}
}
这样,当从别的浏览器登录时,刷新当前浏览器,就会被挤掉。
【JavaWeb】用监听器实现单一登录相关推荐
- JavaWeb中监听器Listener+过滤器filter+拦截器interceptor区别
JavaWeb中监听器Listener+过滤器filter+拦截器interceptor区别 如果从整个项目中看,一个servlet请求的执行过程就变成了这样context-param–>lis ...
- java拦截到登陆界面,JavaWeb 使用Filter实现自动登录
JavaWeb 使用Filter实现自动登录 思路 使用cookie存储账号.密码,使用Filter拦截,从cookie中取出账号.密码.若用户要注销|登出.不再想使用自动登录,将cookie的有效期 ...
- openid saml2_单一登录云:SAML和OpenId
openid saml2 当访问不同组织拥有的不同应用程序时,每次从一个应用程序转到另一个应用程序时都必须进行身份验证. 这不仅耗时,而且您还必须记住多个经常丢失的密码. 单一登录是一次认证的能力,并 ...
- 单一登录云:SAML和OpenId
当访问不同组织拥有的不同应用程序时,每次从一个应用程序转到另一个应用程序时都必须进行身份验证. 不仅浪费时间,而且您还必须记住多个经常丢失的密码. 单一登录是一次认证的能力,并且能够使用已认证的身份在 ...
- java单终端登陆_配置终端服务单一登录
配置终端服务单一登录 配置终端服务单一登录 单一登录是一种身份验证方法,允许具有域帐户的用户使用密码或智能卡登录一次,然后,不再要求其提供凭据即可访问远程服务器. 若要在终端服务中实现单一登录功能,请 ...
- asp.net单一登录
asp.net 使用 Application 限制单一登录 原理:用户登录后系统会分配一个与用户唯一对应的SessionID,将当前用户ID与其SessionID对应保存在Application中,一 ...
- java单一登录_java实现单一登录 踢人效果
1.建一个session监听类 public class SessionListener implements HttpSessionListener{ public static HashMap s ...
- java实现单一登录 踢人效果
1.建一个session监听类 public class SessionListener implements HttpSessionListener{public static HashMap se ...
- Javaweb 实现简单的用户注册登录(含数据库访问功能)
Javaweb 实现简单的用户注册登录(含数据库访问功能) 实现效果图: 登录界面: 登陆成功: 登陆失败: 注册界面: 注册成功: 1.登录界面login.jsp <%@ page langu ...
- ibm tivoli_Windows和Tivoli Access Manager的Intranet单一登录
ibm tivoli 基于Microsoft Windows的Intranet提供了使用桌面凭据登录基于Microsoft Internet信息服务的Intranet基础结构的能力. 这是使用Micr ...
最新文章
- 如何完整迁移git仓库到另一个远程地址
- 《JavaScript 闯关记》之函数
- 今天网络又出问题了,现在的问题变成原IP地址不可用
- 【翻译】C#编程语言和JAVA编程语言的比较(下)
- 【MFC系列-第11天】CWinApp类成员分析
- LeetCode 2063. 所有子字符串中的元音(数学)
- phpcmsV9 会员升级 - 配置篇
- FPGA入门基础介绍
- 以新型数据治理构筑城市发展新引擎,中国电子和清华大学联合发布 《2021中国城市数据治理工程白皮书》
- Python让繁琐工作自动化——chapter16 发送电子邮件和短信
- 田汉卿:量化投资与风险控制(会议纪要)
- 网管教程+从入门到精通软件篇
- 在项目中遇到导入TXT乱码现象。为什么UTF-8不行?ANSI是什么编码?
- Android 使用 Scheme 启动淘宝,天猫等其他APP
- 这台iPad最适合程序媛吃鸡,号称吃鸡神器!
- life: zz 关于爱情
- zabbix_get [12429]: Check access restrictions in Zabbix agent configuration
- 家庭教育机构如何线上线下灵活结合?
- oppo计算机怎么添加到桌面,OPPO怎么把快捷方式添加到桌面 OPPO把快捷方式添加到桌面方法...
- 主动降噪相消干涉原理