Java web实现账号单一登录,防止同一账号重复登录(踢人效果)

 更新时间:2019年10月23日 22:45  点击:769

实现了Java web开发账号单一登录的功能,防止同一账号重复登录,后面登录的踢掉前面登录的,使用过滤器Filter实现的。可以先下载项目下来测试下效果。

有博客写的是没个一段时间(比如500ms)读取后台的session进行验证,这种方法除了会占用资源,还会出现访问session(请求1)的返回值和自己提交请求(请求2)的返回值发生冲突。比如请求1先提交,此时请求1的返回值还未返回到前端,请求2提交,实际上我们想要的是请求1的返回值先返回,然后再返回请求2的返回值,但是这不是肯定会发生的,ajax的机制所导致的,具体什么原因没查到。总之出现了请求2先返回了返回值,这时候请求1接收到了请求2的返回值,妥妥的前端出现错误,但是后台却是成功的。

下面进入主题

工程下载链接:链接: https://pan.baidu.com/s/1Rp09wv7hTJLqx9DiQ_KSeA 提取码: xyym

其中:jquery-1.11.3.js是网上的工具

在这里插入图片描述

建立两个简单的界面

登录界面:为了简单没有设置密码,直接输入账号点击登录就行


在这里插入图片描述

// index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>" rel="external nofollow" rel="external nofollow" >
 <title>My JSP 'index.jsp' starting page</title>
 <meta http-equiv="pragma" content="no-cache">
 <meta http-equiv="cache-control" content="no-cache">
 <meta http-equiv="expires" content="0"> 
 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
 <meta http-equiv="description" content="This is my page">
 <!--
 <link rel="stylesheet" type="text/css" href="styles.css" rel="external nofollow" rel="external nofollow" >
 -->
 </head>
  
 <body>
 <input id="username" name="username" type="text">
 <!-- <a href="singlecount.jsp" rel="external nofollow" target="_self"> -->
 <button id="btnlogin" name="btnlogin">登录</button><!-- </a> -->
  
 <!-- 引入jQuery -->
 <script type="text/javascript" src="js/jquery-1.11.3.js"></script>
 <script type="text/javascript" src="js/jsSubmit.js"></script>
 </body>
</html>

主页面:简单的一个提交按钮

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
 <head>
 <base href="<%=basePath%>" rel="external nofollow" rel="external nofollow" >
 <title>My JSP 'SingleCount.jsp' starting page</title>
 <meta http-equiv="pragma" content="no-cache">
 <meta http-equiv="cache-control" content="no-cache">
 <meta http-equiv="expires" content="0"> 
 <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
 <meta http-equiv="description" content="This is my page">
 <!--
 <link rel="stylesheet" type="text/css" href="styles.css" rel="external nofollow" rel="external nofollow" >
 -->
 
 </head>
  
 <body>
 已登录. <br>
 <button id="btnsubmit" name="submit">提交</button>
  
 <!-- 引入jQuery -->
 <script type="text/javascript" src="js/jquery-1.11.3.js"></script>
 <script type="text/javascript" src="js/jsSubmit.js"></script>
 </body>
</html>

写ajax,向后台提交请求

$(document).ready(function() {
 // 登录按钮
 $("#btnlogin").click(function() {
 //data,dataType,type,url
 $.ajax({
 url: 'LoginServlet?method=login',
 type: 'post',
 data: {username: $("input[name='username']").val()}, // 将用户名传给servlet
 //dataType:'json',
 success: function(msg) { // msg为从servlet接收到的返回值
 if (msg == 1) { // 接收到后台数据为1,正常登录
 window.location.href = "singlecount.jsp";
 } 
 },
 error:function(){
 window.alert("错误!");
 }
 });
 });
 // 提交按钮
 $("#btnsubmit").click(function() {
 //data,dataType,type,url
 $.ajax({
 url: 'SubmitServlet?method=submit',
 type: 'post',
 //dataType:'json',
 success: function(msg) { // msg为从servlet接收到的返回值
 if (msg >= 1) { // 正常
 window.alert("提交总数" + msg);
 } 
 },
 error:function(jqXHR){
 if(jqXHR.status == 900){ // 900状态码
 window.alert("登录状态失效,请重新登录!");
 window.location.href = "/OneLogin";
 }
 }
 });
 });
});

servlet

这部分有点长,其实主要内容直接看doPost方法就可以了。

// LoginServlet
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@SuppressWarnings("serial")
//注解表明什么样的情况下可以访问该内容
@WebServlet(urlPatterns={"/LoginServlet"})
public class LoginServlet extends HttpServlet {
 private PrintWriter out; // 输出流
 private String user;
 private String method;
 private HttpSession session;
 // 建立一个Map存储session信息,key-用户名,value-session
 public static Map<String, HttpSession> user_Session = new HashMap<String, HttpSession>();
  
 @Override
 public void init(ServletConfig config) throws ServletException {
 // TODO Auto-generated method stub
 super.init(config);
 }
 @Override
 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 super.doDelete(req, resp);
 }
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 doPost(req, resp);
 }
 @Override
 // 在这里实现方法
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 resp.setContentType("text/html");
 //语言编码
 req.setCharacterEncoding("utf-8");
 resp.setCharacterEncoding("utf-8");
 out = resp.getWriter();
  
 user = req.getParameter("username"); // 获取index界面username的内容
 method = req.getParameter("method"); // 获取方法名
 session = req.getSession(); // 获取session
 switch (method) {
 case "login":
 mLogin();
 break;
 default:
 break;
 }
 out.flush();
 out.close();
  
 }
 
 private void mLogin() { // 按登录按钮调用的方法
 // TODO Auto-generated method stub
 removeUser(user);
 session.setAttribute("name", user);
 user_Session.put(user, session); // 新增或覆盖session
 System.out.println(user_Session);
 out.println(1); // 返回值1,随意选个值,和前端对应就可以
 }
  
 /**
 * 判断是否有重复用户,
 * 若出现重复用户,踢掉前面登录的用户,即删除其session
 */
 private void removeUser(String user) {
 if(user_Session.containsKey(user))
 user_Session.get(user).invalidate();
 }
}
 
// SubmitServlet
package servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
//注解表明什么样的情况下可以访问该内容 会在js和web.xml中使用
@WebServlet(urlPatterns={"/SubmitServlet"})
public class SubmitServlet extends HttpServlet {
  
 private PrintWriter out; // 输出流
 private String method;
 private int number = 0; // 计数
 @Override
 public void init(ServletConfig config) throws ServletException {
 // TODO Auto-generated method stub
 super.init(config);
 }
 @Override
 protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 super.doDelete(req, resp);
 }
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 doPost(req, resp);
 }
 @Override
 // 在这里实现方法
 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 // TODO Auto-generated method stub
 resp.setContentType("text/html");
 //语言编码
 req.setCharacterEncoding("utf-8");
 resp.setCharacterEncoding("utf-8");
 out = resp.getWriter();
  
 method = req.getParameter("method"); // 获取方法名
 switch (method) {
 case "submit":
 mSubmit();
 break;
 default:
 break;
 }
 out.flush();
 out.close();
 }
  
 private void mSubmit() { // 按提交按钮调用的方法
 // TODO Auto-generated method stub
 number++;
 out.println(number);
 }
}

过滤器

过滤器的原理这里就不说了,简单来说就是请求要先经过过滤器才能到达servlet,也就是说如果请求不满足要求就无法通过过滤器,这里的要求是要有session。

package filter;
 
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebFilter("/SessionFilter")
public class SessionFilter implements Filter {
 @Override
 public void destroy() {
 // TODO Auto-generated method stub
  
 }
 @Override
 public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
 throws IOException, ServletException {
 // TODO Auto-generated method stub
 HttpServletRequest request = (HttpServletRequest) arg0;
 HttpServletResponse response = (HttpServletResponse) arg1;
 String strURL = request.getRequestURL().toString(); // 获取请求路径
 // System.out.println(strURL);
 // 只过滤来自SubmitServlet请求和singlecount.jsp的加载,可以设置成自己想过滤的
 // 需要在web.xml中添加<filter>
 if(strURL.indexOf("SubmitServlet") != -1 || strURL.indexOf("singlecount.jsp") != -1){ 
 if(request.getSession().getAttribute("name") == null){
 request.getSession().invalidate();
 response.sendError(900, "登录失效,请重新登录!"); // 自定义状态码,session失效
 // 900 到ajax的error中处理
 return;
 }
 else {
 arg2.doFilter(arg0, arg1);
 }
 }
 else {
 arg2.doFilter(arg0, arg1);
 }
 }
 @Override
 public void init(FilterConfig arg0) throws ServletException {
 // TODO Auto-generated method stub
  
 }
}

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
 <display-name>OneLogin</display-name>
 <welcome-file-list>
 <welcome-file>index.html</welcome-file>
 <welcome-file>index.htm</welcome-file>
 <welcome-file>index.jsp</welcome-file>
 <welcome-file>default.html</welcome-file>
 <welcome-file>default.htm</welcome-file>
 <welcome-file>default.jsp</welcome-file>
 </welcome-file-list>
 
 <filter>
 <filter-name>filter.SessionFilter</filter-name>
 <filter-class>filter.SessionFilter</filter-class>
 </filter>
 <filter-mapping>
 <filter-name>filter.SessionFilter</filter-name> 
 <url-pattern>/singlecount.jsp</url-pattern> <!-- 给界面添加过滤器 -->
 </filter-mapping>
 <filter-mapping>
 <filter-name>filter.SessionFilter</filter-name>
 <url-pattern>/SubmitServlet</url-pattern> <!-- 给servlet添加过滤器 -->
 </filter-mapping>
</web-app>

实现效果

可以使用两个不同的浏览器当两个客户端,或者电脑多就用多台电脑。

相同账号登录时,前面账号再点提交请求就会给出提示,跳转到登录界面

在这里插入图片描述未登录直接进入:http://localhost:8080/OneLogin/singlecount.jsp

在这里插入图片描述


如果也想实现跳转效果,在jsSubmit.js的$(document).ready(function() {…}); 前面加入是否有session的判断,没有就给出提示,跳转到登录界面。

[!--infotagslink--]

相关文章

  • .net实现微信公众账号接口开发实例代码

    这篇文章主要介绍了.net实现微信公众账号接口开发实例代码,有需要的朋友可以参考一下...2021-09-22
  • Oracle创建只读账号的详细步骤

    本文介绍了Oracle创建只读账号的详细步骤,有此需求的朋友可以参考下过程...2021-06-06
  • ubuntu安装mongodb创建账号和库及添加坐标索引的流程分析

    这篇文章主要介绍了ubuntu安装mongodb创建账号和库及添加坐标索引的流程分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-12-08
  • ipad 怎么注册和激活iCloud账号及备份?

    ipad 怎么注册和激活iCloud账号呢,今天进货了一个ipad air了,想看看苹果手机的icloud怎么使用,下面小给来给各位同学分享一下具体操作方法。 iCloud是什么? iCloud...2016-09-20
  • php中同一个账号同时只能一个人登录程序

    通常情况下我们用户可以多个人同时登录了,但有时客户需求我们需要的是同一个账号同时只能一个人登录了,下面我们就一起来看此问题的解决办法. 以前考虑过这个问题,今...2016-11-25
  • 微信公共账号营销工具 刮刮乐的开发

    因为公司要做一个项目活动在微信中要有这一样款游戏活动了,但自己不会写于是网上找到了一个作者写的方案下面我整理了一下可以用同时也分享给大家。 本来是不想写...2016-11-25
  • Godaddy账号怎么防盗 Godaddy账号安全防范

    Godaddy账号一般里面是域名被盗的可能性比较高了,因为许多的大域名在Godaddy给盗了,今天我们就来看一篇关于Godaddy账号安全防范方法吧。 Godaddy的安全隐患在什么...2016-10-10
  • C#实现Check Password和锁定输错密码锁定账户功能

    C#实现的Check Password,并根据输错密码的次数分情况锁定账户:如果输入错误3次,登录账户锁定5分钟并提示X点X分后重试登录,具体实现代码感兴趣的朋友跟随小编一起看看吧...2020-06-25
  • 微信公共账号第三方管理工具开发(一)

    最近在捣鼓微信公共平台提供的API,等确实一个获取用户信息的API。所以没有办法,只能自己去获取,手动填写当然可以解决问题,当然编程不就是为了让生活变的更简单么? ...2016-11-25
  • Oracle 管理员账号密码忘记的快速解决方法

    这篇文章主要介绍了 Oracle 管理员账号密码忘记的快速解决方法,本文以oracle12c为例子,给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下...2020-07-11
  • godaddy空间ftp怎么创建 godaddy ftp账号创建方法

    godaddy空间ftp怎么创建呢?初次使用godaddy空间了全是英文版了,但经常一些时间的熟习还是会做这些操作了,下面一起来看看godaddy ftp账号创建方法. 1.登录账号之后我...2016-10-10
  • 苹果id账号邮箱全忘了怎么办 苹果刷机后忘记id找回方法

    苹果设备使用中用户需要注册登录苹果id来使用商店等功能,有小伙伴注册使用过,但是把苹果id账号邮箱全忘了,这种情况怎么办呢,小编来为大家介绍...2022-09-14
  • Android实现保存QQ账号与密码功能(文件存储)

    这篇文章主要介绍了Android保存QQ账号与密码,文件存储是Android中最基本的一种数据存储方式,它与Java中的文件存储类似,都是通过I/O流形式把数据直接存储到文件中,下面我们一起来看一下如何用Android实现文件存储功能吧...2022-05-01