java web项目防止多用户重复登录解决方案
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本人声明。否则将追究法律责任。
作者:永恒の_☆ 地址:http://blog.csdn.net/chenghui0317/article/details/9373345
目前web项目中,很多情况都是可以让同一个账户信息在不同的登录入口登录这次,这样子就不那么美好了。
现在有两种解决方案:
1、将用户的登录信息用一个标志位的字段保存起来,每次登录成功就标记1,注销登录就标记为0,当标记为1的时候不允许别人登录。
2、将用户的登录信息保存在application内置作用域内, 然后利用session监听器监听每一个登录用户的登录情况。
很显然,第一种方式 每次登录 都需要操作数据库,多了一些不必要的性能开销,而且在登录状态下 万一突然电脑关闭了,那就永远都不能登录了,可用性比较低。
但是第二种方式就不一样了,可操作性强,很方便维护所有在线用户的信息。
接下来 主要介绍第二种方式的具体实现:
1、在处理登录的login方法中,先查询数据库验证下该用户是否存在,如果存在 判断该登录账户是否已经锁定了, 然后从application内置作用域对象中取出所有的登录信息,查看该username账户是否已经登录,如果登录了,就友好提示下,反之表示可以登录,将该登录信息以键值对的方式保存在application中。
代码如下:
- //没有使用零配置前 每个访问的方法都要加上@Action ,否则404
- @Action(value="login", results={
- @Result(name="index", location="index.jsp"),
- })
- public String login() throws Exception {
- try{
- User result = userService.login(user.getFuUserName(), user.getFuPassword());
- if(result!=null){
- if(result.getFuStatus()!=null && result.getFuStatus()==0){
- super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已被锁定!");
- return "error";
- }
- Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);
- boolean isExist = false;
- String sessionId = super.getSessionId(false);
- if(loginUserMap==null){
- loginUserMap = new HashMap<String, String>();
- }
- for (String username : loginUserMap.keySet()) {
- //判断是否已经保存该登录用户的信息 或者 如果是同一个用户进行重复登录那么允许登录
- if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){
- continue;
- }
- isExist = true;
- break;
- }
- if(isExist){
- super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已登录!");
- return "error";
- }else {
- loginUserMap.put(result.getFuUserName(), sessionId);
- }
- //登录成功
- super.setSessionAttr(Constant.LOGIN_USER, result);
- super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap);
- logger.info(result.getFuUserName() + " 登录成功!");
- //如果 session中fromUrl有值,就跳转到该页面
- String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL);
- if(fromUrl!=null){
- super.setSessionAttr(Constant.FROM_URL, null);
- super.getResponse().sendRedirect(fromUrl.toString());
- return null;
- }
- return "index";
- }
- }
- catch (Exception e) {
- e.printStackTrace();
- logger.info("登录失败: "+e.getMessage());
- }
- super.setRequestAttr("message", "用户名或密码错误");
- return "error";
- }
2、登录入口处理完之后,考虑到会话结束的话,那么对应的登录用户也应该相应的注销登录。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。
代码如下:
- package com.facelook.util;
- import java.util.Map;
- import javax.servlet.http.HttpSessionEvent;
- import javax.servlet.http.HttpSessionListener;
- import org.apache.log4j.Logger;
- import com.facelook.entity.User;
- public class SessionListener implements HttpSessionListener{
- private Logger logger = Logger.getLogger(this.getClass());
- @Override
- public void sessionCreated(HttpSessionEvent event) {
- }
- @Override
- public void sessionDestroyed(HttpSessionEvent event) {
- //在session销毁的时候 把loginUserMap中保存的键值对清除
- User user = (User)event.getSession().getAttribute("loginUser");
- if(user!=null){
- Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap");
- loginUserMap.remove(user.getFuUserName());
- event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap);
- }
- }
- }
web.xml中配置如下:
- <!-- session listener -->
- <listener>
- <listener-class>com.facelook.util.SessionListener</listener-class>
- </listener>
3、另外,还有一个问题,如果说登录的用户突然关闭了浏览器或者页面而没有点击退出按钮。那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。
- //在刷新或关闭时调用的事件
- $(window).bind('beforeunload',function(){
- $.ajax({
- url:"${ctx}/system/user/user!logout.action",
- type:"post",
- success:function(){
- alert("您已退出登录");
- }
- });
- );
但是如果一些客观原因,比如电脑突然关机,自动重启,等等,这些就没法避免了,所以只能等待服务器端的session会话重置之后才可以再登录。
除非 做一个 统计所有在线人员的模块,管理员在里面进行在线人员的登录登出的状态管理,把那些有问题的登录用户直接销毁掉。
接下来简单介绍下在线人员模块的管理:
1、首先需要一个session监听器来监听所有的回话create的情况,这时候每次创建一个session就可以count+1 ,然后销毁的时候count-1 ,另外还需要一个ServletContext的监听器来监听web应用的生命周期,获取servletContext对象,然后将在线人员总数统计出来存放进去;
具体代码如下:
- package com.facelook.util;
- import java.util.Map;
- import javax.servlet.ServletContext;
- import javax.servlet.ServletContextEvent;
- import javax.servlet.ServletContextListener;
- import javax.servlet.http.HttpSessionEvent;
- import javax.servlet.http.HttpSessionListener;
- import org.apache.log4j.Logger;
- import com.facelook.entity.User;
- public class SessionListener implements HttpSessionListener,ServletContextListener{
- private int count;
- private ServletContext servletContext = null;
- public SessionListener() {
- count = 0;
- }
- private Logger logger = Logger.getLogger(this.getClass());
- @Override
- public void sessionCreated(HttpSessionEvent event) {
- count++;
- setContext(event);
- logger.info("***************the http session is created...***************");
- }
- @Override
- public void sessionDestroyed(HttpSessionEvent event) {
- //在session销毁的时候 把loginUserMap中保存的键值对清除
- User user = (User)event.getSession().getAttribute("loginUser");
- if(user!=null){
- Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap");
- loginUserMap.remove(user.getFuUserName());
- event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap);
- }
- count--;
- setContext(event);
- logger.info("***************the http session is destroyed...***************");
- }
- public void setContext(HttpSessionEvent httpSessionEvent){
- httpSessionEvent.getSession().getServletContext().setAttribute("online", count);
- }
- @Override
- public void contextDestroyed(ServletContextEvent servletcontextevent) {
- this.servletContext = null;
- logger.info("***************the servlet context is destroyed...***************");
- }
- @Override
- public void contextInitialized(ServletContextEvent servletcontextevent) {
- this.servletContext = servletcontextevent.getServletContext();
- logger.info("***************the servlet context is initialized...***************");
- }
- }
2、在UserAction中创建管理在线用户的模块的方法,并且支持强制退出的功能;
- /**
- * 退出登录
- * @return
- * @throws ServletException
- * @throws IOException
- */
- public String logout() throws ServletException, IOException{
- try {
- Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);
- User user = (User) super.getSessionAttr(Constant.LOGIN_USER);
- super.removeAttribute(Constant.LOGIN_USER_MAP);
- loginUserMap.remove(user.getFuUserName());
- super.setApplicationAttr(Constant.LOGIN_USER_MAP,loginUserMap);
- logger.info("退出登录成功!");
- } catch (Exception e) {
- e.printStackTrace();
- logger.error("退出登录失败: "+e.getMessage());
- }
- return INPUT;
- }
- /**
- * 在线用户管理
- * @return
- */
- public String loginManager(){
- return SUCCESS;
- }
- /**
- * 强制退出其他用户
- * @return
- */
- public String logoutOther(){
- try {
- String username = ServletActionContext.getRequest().getParameter("username");
- Map<String, String> loginUserMap = (Map<String, String>) super.getApplicationAttr(Constant.LOGIN_USER_MAP);
- if(username!=null && loginUserMap.containsKey(username)){
- loginUserMap.remove(username);
- super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap);
- }
- } catch (Exception e) {
- e.printStackTrace();
- logger.info("强制退出失败: "+e.getMessage());
- }
- return null;
- }
3、在管理页面加载在线用户的列表;
对应的方法定义完毕之后,然后再在对应的管理页面添加在线列表,具体如下:
- <%@page import="java.util.Map"%>
- <%@page import="java.util.Map.Entry"%>
- <%@ page language="java" pageEncoding="UTF-8" %>
- <%@ include file="/common/taglib.jsp" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <title>欢迎来到Facelook</title>
- <%@ include file="/common/resource.jsp" %>
- <script type="text/javascript">
- <!--
- //在刷新或关闭时调用的事件
- $(window).bind('beforeunload',function(){
- $.ajax({
- url:"${ctx}/system/user/user!logout.action",
- type:"post",
- success:function(){
- alert("您已退出登录");
- }
- });
- });
- function logout(username){
- if(username=="${sessionScope.loginUser.fuUserName}"){
- alert("不允许退出自己账号!");
- return;
- }
- $.ajax({
- url:"${ctx}/system/user/user!logoutOther.action?username="+username,
- type:"post",
- success:function(){
- $("#tr"+username).hide();
- var count = parseInt($("#count").html());
- $("#count").html(count-1);
- alert("退出成功!");
- }
- });
- }
- //-->
- </script>
- </head>
- <body>
- <%@ include file="/common/header.jsp" %>
- <div id="main" class="wrap">
- <%@ include file="/common/lefter.jsp" %>
- <div class="righter">
- <div class="main">
- <h2>登录列表</h2>
- <%
- Map<String,String> map = (Map<String,String>)application.getAttribute("loginUserMap");
- out.println("目前共有<font id='count'>"+map.size()+"</font>个用户在线!!");
- %>
- <table border="1" width="400">
- <%for(Entry<String,String> m : map.entrySet()){%>
- <tr id="tr<%=m.getKey()%>">
- <td>
- <%=m.getKey()%>
- </td>
- <td width="80">
- <a href="javascript:logout('<%=m.getKey()%>')">强制退出</a>
- </td>
- </tr>
- <%}%>
- </table>
- </div>
- </div>
- </div>
- <%@ include file="/common/footer.jsp" %>
- <%@ include file="/common/message.jsp" %>
- </body>
- </html>
好了启动部署项目,然后启动服务,进入在线用户管理模块,简单效果如下图:
需要注意的是:当前登录用户 不允许强制退出自己的登录信息。
这样子,基本上可以实现防止多用户登录的案例了!
java web项目防止多用户重复登录解决方案的更多相关文章
- Java web项目综合练习(Estore)
Java web项目综合练习(Estore) 复习day18: ajax代码的书写步骤 2)json格式文本,转js对象的方法是那个 项目开发流程介绍 这里学习的JavaWEB项目实战,主要是把前面学 ...
- SpringMVC内容略多 有用 熟悉基于JSP和Servlet的Java Web开发,对Servlet和JSP的工作原理和生命周期有深入了解,熟练的使用JSTL和EL编写无脚本动态页面,有使用监听器、过滤器等Web组件以及MVC架构模式进行Java Web项目开发的经验。
熟悉基于JSP和Servlet的Java Web开发,对Servlet和JSP的工作原理和生命周期有深入了解,熟练的使用JSTL和EL编写无脚本动态页面,有使用监听器.过滤器等Web组件以及MVC架构 ...
- Linux(Centos)安装tomcat并且部署Java Web项目
步骤一.下载安装包 a. 下载tomcat linux安装包,地址:http://tomcat.apache.org/download-80.cgi , 我们下载的版本是8.0,下载方式如图: b ...
- Linux(Centos)之安装tomcat并且部署Java Web项目
1.准备工作 a.下载tomcat linux的包,地址:http://tomcat.apache.org/download-80.cgi,我们下载的版本是8.0,下载方式如图: b ...
- Java web项目引用java项目,类型找不到
Java web项目引用java项目,类型找不到 错误信息: java.lang.ClassNotFoundException: org.codehaus.jackson.map.ObjectMapp ...
- 使用MyEclipse搭建java Web项目开发
转自:http://blog.csdn.net/jiuqiyuliang/article/details/36875217 首先,在开始搭建MyEclipse的开发环境之前,还有三步工具的安装需要完成 ...
- Linux(Centos)之安装tomcat并且部署Java Web项目(转)
1.准备工作 a.下载tomcat linux的包,地址:http://tomcat.apache.org/download-80.cgi,我们下载的版本是8.0,下载方式如图: b ...
- IntelliJ IDEA新建JAVA WEB项目(转载)
IntelliJ IDEA是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支持.各类版本控制工具(git.svn ...
- 将Java Web项目部署到远程主机上
这里讲的是Java Web项目 第一步:购买主机,如果是大学生可以购买学生机,一个月9.9元,阿里云ECS服务器,自己选择不同的操作系统和镜像 ,我的选择 得到用户名和密码,可以进行ssh远程登录,登 ...
随机推荐
- python_103_属性方法例子
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): pr ...
- python_100_静态方法
class Dog(object): def __init__(self,name): self.name=name @staticmethod#实际上跟类没什么关系了 def eat():#def ...
- Oracle SQL语句性能优化方法大全
Oracle SQL语句性能优化方法大全 下面列举一些工作中常常会碰到的Oracle的SQL语句优化方法: 1.SQL语句尽量用大写的: 因为oracle总是先解析SQL语句,把小写的字母转换成大写的 ...
- 解决cocos游戏安卓release版本闪退问题
在cocos中偶尔会遇到闪退的问题,特别是android和ios系统下的闪退就特别难处理了, 虽然说能使用xcode和eclipse显示log,但是也会出现一些特别的情况,直接闪退而且 没有任何预兆. ...
- [Codeforces Round #250]小朋友和二叉树
题目描述: bzoj luogu 题解: 生成函数ntt. 显然这种二叉树应该暴力薅掉树根然后分裂成两棵子树. 所以$f(x)= \sum_{i \in c} \sum _{j=0}^{x-c} f( ...
- Ajax请求出现406的原因
一般出现406错误有两种可能: 1.如果后缀是html是不能响应json数据的.需要修改后缀名. 在做伪静态化过程中,以.html结尾的后缀,做post请求时,不能响应json格式,这是spring官 ...
- java解析多层嵌套json字符串
java分别解析下面两个json字符串 package jansonDemo; import com.alibaba.fastjson.JSON; import com.alibaba.fastjso ...
- 【android】安卓开发apk列表
- 谷歌的Zxing框架的扫码软件 (目前国内的应用商店很少此种类型的扫码app) - 解析IP地址功能,从IP地址(子网掩码)自动解析出网段,广播地址
- day14-推导式和生成器表达式
1.推导式规则 [每一个元素或者是和元素相关的操作 for 元素 in 可迭代数据类型] ----------遍历之后挨个处理[满足条件的元素相关的操作 for 元素 in 可迭代数据类型 if 元素 ...
- 请问batch_normalization做了normalization后为什么要变回来?
请问batch_normalization做了normalization后为什么要变回来? 请问batch_normalization做了normalization后为什么要变回来? - 莫驚蟄的回答 ...