用到的技术:map集合,sessionListener监听器,Fiter过滤器。

实现思路:

  一.利用一个全局的map集合来保存每个用户sessionID的值的一个集合。一个用户对应一个sessionID当相同的用户登录的时候判断它在集合总有没有值。(保存用户所有登录记录)

  二.

    2.1.实现sessionListener在当一个session被销毁的时候强制移除当前用户所对应的sessionID

    2.2.实现Fiter来判断每次请求map集合中是否有值。(实现强制退出)

代码:代码是复制别人的,做了些修改。

public class LoginUserMap {
  //ConcurrentHashMap这个集合是线程安全的而且性能方面比hasTable和hasMap都好。在高并发的条件下执行速度更快。
  private static Map<String, String> loginUsers = new ConcurrentHashMap<String, String>();
 
  /**
   * 将用户和sessionId存入map
   * @param key
   * @param value
   */
  public static void setLoginUsers(String loginId, String sessionId) {
    loginUsers.put(loginId, sessionId);
  }
 
  /**
   * 获取loginUsers
   * @return
   */
  public static Map<String, String> getLoginUsers() {
    return loginUsers;
  }
 
  /**
   * 根据sessionId移除map中的值
   * @param sessionId
   */
  public static void removeUser(String sessionId) {
    for (Map.Entry<String, String> entry : loginUsers.entrySet()) {
      if (sessionId.equals(entry.getValue())) {
        loginUsers.remove(entry.getKey());
        break;
      }
    }
  }
 
  /**
   * 判断用户是否在loginusers中
   * @param loginId
   * @param sessionId
   * @return
   */
  public static boolean isInLoginUsers(String loginId, String sessionId) {
    return (loginUsers.containsKey(loginId) && sessionId.equals(loginUsers.get(loginId)));
  }
 
}
//登录方法所在的地方
public void login(ttpServletRequest request) {
  try
      ......//一系列登录的方法
      HttpSession session = request.getSession();
      LoginUserMap.setLoginUsers(username, session.getId());//保存sessionId到map中
    } catch (LoginException ex) {
      throw ex;
    }
}
//实现HttpSessionListener
public class SessionListener implements HttpSessionListener {
  private Log log = LogFactory.getLog(SessionListener.class);
 
  /**
   * 创建session时候的动作
   * @param event
   */
  @Override
  public void sessionCreated(HttpSessionEvent event) {
 
  }
 
  /**
   * 销毁session时候的动作
   * @param event
   */
  @Override
  public void sessionDestroyed(HttpSessionEvent event) {
    HttpSession session = event.getSession();
    String sessionId = session.getId();
    //移除loginUsers中已经被销毁的session
    LoginUserMap.removeUser(sessionId);
    log.info(sessionId + "被销毁!");
    }
}
//xml配置
<listener>
  <listener-class>....SessionListener</listener-class>
</listener>
//实现过滤器
public class LoginLimitFilter implements Filter{
 
  private Log log = LogFactory.getLog(LoginLimitFilter.class);
 
  /**
   * 销毁时的方法
   */
  @Override
  public void destroy() {
 
  }
 
  /**
   * 过滤请求
   * @param request
   * @param response
   * @param filterChain
   * @throws IOException
   * @throws ServletException
   */
  @Override
  public void doFilter(ServletRequest request, ServletResponse response,
     FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest servletRequest = (HttpServletRequest) request;
    HttpServletResponse servletResponse = (HttpServletResponse) response;
    HttpSession session = servletRequest.getSession();
 
    //获取项目路径
    String path = servletRequest.getContextPath();
    String basePath = servletRequest.getScheme()+"://"+servletRequest.getServerName()+":"+servletRequest.getServerPort()+path;
 
    try {
      //获取登录信息
      String loginId = session.getAttribute("yhid")
      //判断当前用户的sessionId是否在loginUsers中,如果没有执行if后的操作
      if(!LoginUserMap.isInLoginUsers(loginId, session.getId())) {
        //当前用户logout 注:退出登录最好别用session销毁的方法。
        logout();//自己的logout方法
        //调到登录页面,并表明退出方式为挤下线
        servletResponse.sendRedirect(basePath + "?logoutway=edge");
      }
    } catch (Exception e) {
      log.debug("获取当前用户信息失败,用户未登陆!", e);
    } finally {
      filterChain.doFilter(request, response);
    }
  }
 
  /**
   * 初始化方法
   * @param arg0
   * @throws ServletException
   */
  @Override
  public void init(FilterConfig arg0) throws ServletException {
 
  }
 
}
//xml
<filter>
  <filter-name>LoginLimitFilter</filter-name>
  <filter-class>io.github.brightloong.loginlimite.LoginLimitFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>LoginLimitFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
//前台页面js放在首页就可以了
window.onload = function(){
  if(window.parent != window){
    window.parent.location.href=window.location.href;
  } else {
    if(GetQueryString('logoutway')) {
      alert('该用户已在其他地方登录,你已下线');     
      var url = window.location.href;
      window.location.href = url.substr(0,url.indexOf('?logoutway=edge'));
   }
  }
}
 
function GetQueryString(name)
{
   var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
   var r = window.location.search.substr(1).match(reg);
   if(r!=null)return unescape(r[2]); return null;
}
 
原文链接:http://www.jianshu.com/p/24bc2bb1444e#

java web 限制同一个用户在不同处登入的更多相关文章

  1. [转]Java web 开发 获取用户ip

    如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,那么真正的用户端的真实IP则是取X-Forwarded-For中第一个非unknown的有效IP字符串. pu ...

  2. Struts2+AJAX+JQuery 实现用户登入与注册功能。

    要求 必备知识 JAVA/Struts2,JS/JQuery,HTML/CSS基础语法. 开发环境 MyEclipse 10 演示地址 演示地址 预览截图(抬抬你的鼠标就可以看到演示地址哦): 关于U ...

  3. hibernate连接oracle12c数据库报:java.sql.SQLException: ORA-01017: 用户名/口令无效; 登录被拒绝。(用户名/口令在oracle客户端以及cmd命令都能登入)

    报错信息: 2017-09-22 15:40:07,354 WARN [org.hibernate.cfg.SettingsFactory] - Could not obtain connection ...

  4. Struts2+AJAX+JQuery 实现用户登入与注册功能

    要求:必备知识:JAVA/Struts2,JS/JQuery,HTML/CSS基础语法:开发环境:MyEclipse 10 关于UI部分请查看下列链接,有详细制作步骤: 利用:before和:afte ...

  5. Java Web 开发利用Struts2+Spring+mybatis写一个用户登录界面以及简单的数据交互

    框架的东西太复杂也难以讲通,直接上代码: 一.首先得配置环境 和导入必要的jar包 有一些重要的如下: Filter文件夹下的SafetyFilter.java   model文件夹下的 Global ...

  6. 【适合公司业务】全网最详细的IDEA里如何正确新建【普通或者Maven】的Java web项目并发布到Tomcat上运行成功【博主强烈推荐】(类似eclipse里同一个workspace下【多个子项目】并存)(图文详解)

    不多说,直接上干货! 首先,大家要明确,IDEA.Eclipse和MyEclipse等编辑器之间的新建和运行手法是不一样的. 如果是在Myeclipse里,则是File -> new -> ...

  7. java web用户登录界面

    做这次实验,主要用到了mysql  java web 的 内容 实验代码: IUserDao.java package com.jaovo.msg.dao; import java.util.List ...

  8. Java Web实现用户登录界面

    一.学习Java Web需要的技术: Java语言基础:算法基础.常用数据结构.编程规范. 掌握常见的数据结构和实用算法:培养良好的编程习惯. Java面向对象:封装.继承.多态等,面向对象程序设计, ...

  9. Java Web实现用户登录功能

    java web 学习记录一下 mvc结构实现mysql 连接 什么是mvc MVC是模型(model).视图(view).控制(controller)这三个单词上的首字母组成.它是一种应用模型,它的 ...

随机推荐

  1. httprunner3源码解读(4)parser.py

    源码结构目录 可以看到此模块定义了4个属性和12个函数,我们依次来讲解 属性源码分析 # 匹配http://或https:// absolute_http_url_regexp = re.compil ...

  2. 元素显示模式:块元素 & 行内元素 & 行内块元素

    元素显示模式 前言 了解元素的显示模式可以更好的让我们布局页面.了解显示模式需要学习以下三个方面 什么是元素的显示模式 元素显示模式的分类 元素显示模式的转换 什么是元素显示模式 元素显示模式就是元素 ...

  3. node 读取文件内容并响应

    node 读取文件内容并响应 const http = require('http'); const fs = require('fs') //创建 Server const server = htt ...

  4. spring security 之自定义表单登录源码跟踪

    ​ 上一节我们跟踪了security的默认登录页的源码,可以参考这里:https://www.cnblogs.com/process-h/p/15522267.html 这节我们来看看如何自定义单表认 ...

  5. sqlalchemy insert or ignore

    insert ignore # insert ignoreinsert_stmt = TimePoint.__table__.insert().prefix_with(" ignore&qu ...

  6. 【JAVA】笔记(1)---JVM内存图;方法重载条件;输入方法;转义字符;强制类型转换;变量分类及区别;Java命名规范;

    Java命名规范: 1.包:全部字母小写: 2.类+接口:所有单词的首字母大写: 3.变量+方法:第一个单词的首字母小写,其余单词首字母大写: 3.常量名:所有字母均大写,且用下划线" _ ...

  7. python及pygame雷霆战机游戏项目实战01 控制飞机

    入门 在这个系列中,将制作一个雷霆战机游戏. 首先,将游戏设置修改一下: WIDTH = 480 HEIGHT = 600 FPS = 60 玩家精灵 要添加的第一件事是代表玩家的精灵.最终,这将是一 ...

  8. Salesforce Consumer Goods Cloud 浅谈篇四之店内拜访的创建和执行

    本篇参考: https://v.qq.com/x/page/f0772toebhd.html https://v.qq.com/x/page/e0772tsmtek.html https://v.qq ...

  9. c语言循环位移(数字,字符串)

    C语言中没有提供循环移位的操作符,但可以通过简洁的方式实现循环移位 设一个操作数x有s位则循环左移n位的操作为: (x << n) | (x >> (s - n)); 同理右移 ...

  10. 【Microsoft Azure 的1024种玩法】四. 利用Azure Virtual machines 打造个人专属云盘,速度吊打某云盘

    [简介] 1.Azure Virtual machines是Azure 提供的多种可缩放按需分配计算资源之一,Nextcloud是一款开源免费的私有云存储网盘项目,可以让你快速便捷地搭建一套属于自己或 ...