使用过滤器和监听器防止用户重复登录

使用过滤器和监听器防止用户重复登录

老师您好这是我参照问答社区创建的项目,但是无法运行,劳烦老师能够帮忙修改完善一下,指出哪里错了,然后我再去理解。

相关代码:

package com.imooc.user;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpSession;

public class LoginMessage {
	/*LoginMessage类:
		该类是单例,有存储用户登录sessionID和用户登录session的Map集合,
		有通过用户名查询和设置sessionID的方法,
		以及通过sessionID查找和设置session的方法。*/
    private static LoginMessage instance = new LoginMessage();

    private Map<String,String> loginUserSession = new HashMap<String,String>();// key值:登录用户登录名,value值:登录用户sessionId
    private Map<String, HttpSession> loginSession = new HashMap<String,HttpSession>();//key值:登录用户sessionId,value值:登录用户session对象

    private LoginMessage(){

    }
    public static LoginMessage getInstance(){
        return instance;
    }

    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);
    }
 }

相关代码:

package com.imooc.user;

import java.io.IOException;

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;

@WebServlet("/servlet/login")
public class LoginServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;


    public LoginServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

    	/*LoginServlet类:该类中只需要获取登录用户信息,将其存入session,转发到主界面的代码*/
// 发送请求,将该请求下发到登录成功页面
        String username = request.getParameter("userName");
        String password = request.getParameter("password");
        HttpSession session = request.getSession();
        session.setAttribute("loginUser", username);//登录完成,将登录用户名存储至session对象
        response.sendRedirect("/success.jsp");
    }
}

相关代码:

package com.imooc.user;

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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class IsFilter implements Filter{
    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
    /*IsFilter类(类命名不规范,首字母应该大写)
	该类中只用来判断是否登录,如果登录,则跳转到主界面,没有登录则跳转到登录页面:*/
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest hrequest = (HttpServletRequest)request;
        HttpServletResponse hresponse = (HttpServletResponse)response;
        String loginUser = (String)hrequest.getSession().getAttribute("loginUser");
        // 判断用户是否登录
        if(loginUser==null){
            hresponse.sendRedirect(hrequest.getContextPath()+"/login.jsp");
            return;
        }else{
            chain.doFilter(request, response);
            return;
        }
}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub
		
	}
}

相关代码:

package com.imooc.user;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

public class SessionAttributeListener implements HttpSessionAttributeListener{
    private static final String LOGIN_USER="loginUser";

    public SessionAttributeListener() {
        super();
    }
	    /*该类的attributeAdded方法中获取监听到的属性名,
	     * 如果是登录操作,则获取登录的名称,判断登录名称是否之前登录过,
	     * 如果登录过,则清理前次会话信息,将本次登录信息存入LoginMessage*/
    @Override
    public void attributeAdded(HttpSessionBindingEvent event) {
        String attrName = event.getName();
        if(LOGIN_USER.equals(attrName)){//若属性名为登录属性名,判定为用户登录操作
            String attrVal = (String)event.getValue();//获取添加的属性值,即用户登录名
            HttpSession session = event.getSession();//该次操作的session对象
            String sessionId = session.getId();//该次操作的session对象ID

            String sessionId2 = LoginMessage.getInstance().getSessionIdByUsername(attrVal);//从缓存对象里面,获得该用户登录名对应的sessionID值
            if(null == sessionId2){//未获得结果,不需要清理前次登录用户会话信息

            }else{
                HttpSession session2 = LoginMessage.getInstance().getSessionBySessionId(sessionId2);//获取前次该用户登录对应的session对象
                session2.invalidate();//清理前次登录用户会话存储信息,使得前次登录失效
            }

            //完成该次登录用户登录名、sessionID,session对象的缓存对象存储
            LoginMessage.getInstance().setSessionIdByUserName(attrVal, sessionId);
            LoginMessage.getInstance().setSessionBySessionId(sessionId, session);
        }
    }

    @Override
    public void attributeRemoved(HttpSessionBindingEvent event) {
    }

    @Override
    public void attributeReplaced(HttpSessionBindingEvent event) {
    }

}

相关代码:

<%@ page language="java" contentType="text/html; UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>用户登录</title> 
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
</head>
<body>
		<div id="login_h">
				<div id="login_h_title">
						<h1>系统登录</h1>
				</div>
				<div id="login_body">
						<form id="body_form" action="http://localhost:8080/UserLogin/servlet/login" method="get" >
								<p>用户名:
								</p>
								<input type="text"  id="userName" name="userName" placeholder="请输入中文/字母/数字的用户名【4-7位】" 
								/>
								<p>密码:

								</p>
								<input type="password" id="pwd" name="password" placeholder="字母开头,数字字母6-10位组成"/ ><br>
								<input type="submit" id="sub" name="sub" value="登录">
						</form>
				</div>
		</div>

		<script type="text/javascript">
				/*$.ajax({
					"url":"http://localhost:8080/UserLogin/servlet/login" ,
					"type":"get",
					"dataType":"json",
					"success":function(json){

					}
				})*/

				/* 给表单添加提交事件 */
				/* 给相应的输入框添加正则表达式,限制输入内容 */
				document.getElementById("body_form").onsubmit=function(){
					var regexUserName=/^[\u4e00-\u9fa5A-Za-z1-9]{1}[\u4e00-\u9fa5A-Za-z0-9]{3,6}$/;
					var regexPwd=/^[A-Za-z]{1}[0-9A-Za-z]{5,9}$/;

					var userName=document.getElementById("userName").value;
					var pwd=document.getElementById("pwd").value;

					if(regexUserName.test(userName)==false){
						alert("用户名不符合当前格式!");
						return false;
					}else if(regexPwd.test(pwd)==false){
						alert("密码不不符合格式");
						return false;
					}else{
						alert("校验成功!");
					}
				}
		</script> 
</body>
</html>

相关代码:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
<head>
<meta charset="UTF-8">
<title>登录成功</title>
</head>
<body>
		<h1 style="color:red;">您好,您已登录!</h1>
</body>
</html>

相关代码:

<?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>UserLogin</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>IsFilter</filter-name>
 	<filter-class>com.imooc.user.IsFilter</filter-class>
 </filter>
 <filter-mapping>
 	<filter-name>IsFilter</filter-name>
 	<url-pattern>/*</url-pattern>
 </filter-mapping>
 <listener>
 <listener-class>com.imooc.user.SessionAttributeListener</listener-class>
 </listener>
</web-app>

正在回答 回答被采纳积分+1

登陆购买课程后可参与讨论,去登陆

1回答
好帮手慕阿满 2021-03-15 12:02:36

同学你好,在同学的web.xml代码中,对所有的路径进行了拦截,如:

http://img1.sycdn.imooc.com//climg/604ed97509c50f6906120217.jpg

这里所有的路径包括登录页面login.jsp,以及登录时要访问LoginServlet的/servlet/login。访问登录页面login.jsp时还没有登录就被拦截,在过滤器中判断没有登录,重定向到login.jsp页面,又被拦截,在过滤器中判断没有登录,重定向到login.jsp页面,如此循环往复,造成重定向次数过多,拒绝访问。

这里建议在过滤器中增加一个判断,如果路径中包含login,则表示是要登录路径,放行不拦截。这样可以正常访问登录页面login.jsp以及登录的/servlet/login,代码参考:

http://img1.sycdn.imooc.com//climg/604edc5809fb4d0908580528.jpg

祝学习愉快~

  • rock221 #1

    为什么要用单例模式阿, 单例模式的那个类是干嘛的阿。

    private static final String LOGIN_USER="loginUser";是什么意思阿 。

    2021-03-26 10:42:52
  • 同学你好,这并不是单例模式,而是一个使用static final修饰的变量。

        ​变量使用static final修饰表示静态常量。静态常量在类加载时就加载,并只加载一次,赋值之后不能改变值。

        ​这里使用static修饰,考虑的是在类加载时加载,避免使用时没有加载到对应的常量造成的报错。使用final是为了在声明的同时赋值,并且值不能改变。

    祝学习愉快!

    2021-03-26 15:59:30
  • 写这句话是为了干嘛阿。设置这个变量干嘛阿;loginUser,是什么阿?

    2021-03-26 17:48:22
问题已解决,确定采纳
还有疑问,暂不采纳

恭喜解决一个难题,获得1积分~

来为老师/同学的回答评分吧

0 星
请稍等 ...
意见反馈 帮助中心 APP下载
官方微信

在线咨询

领取优惠

免费试听

领取大纲

扫描二维码,添加
你的专属老师