使用Session实现一个用户只能登录一次

普通项目:

这样一个账号可以在多个地方进行登录。在这个基础上修改实现一个账号只能登录一次,再次登录会把上次的登录的给挤掉,类似于QQ。

难点:怎么通过sessionId销毁session。因为Servlet2.1之后不支持SessionContext里面getSession(String id)方法。我们可以自己实现一个SessionContext。然后通过sessionId获取session,再通过session.invalidate();

下面为非集群的使用情况,如果你的项目为集群设计,则不适合使用,推荐你先看这篇文章后看小弟我写的适用与集群的另一篇文章。https://blog.csdn.net/qq_33422712/article/details/86555872

1、实现SessionContext。

 

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

import javax.servlet.http.HttpSession;

public class MySessionContext {
	private static MySessionContext context;
	
	private Map<String, HttpSession> map;
	
	private MySessionContext() {
		map = new HashMap<>();
	}
	
	public static MySessionContext getSessionContext() {
		if(context == null) {
			context = new MySessionContext();
		}
		return context;
	}
	
	//添加
	public synchronized void addSession(HttpSession session) {
		if(session!= null)
			map.put(session.getId(), session);
	}
	
	//获取
	public synchronized HttpSession getSession(String sessionId) {
		if(sessionId == null)
			return null;
		return map.get(sessionId);
	}
	
	//删除
	public synchronized void delSession(HttpSession session) {
		if(session!= null)
			map.remove(session.getId());
	}
	
}

2、配置Session监听,在web.xml配置。

<!-- session监听 类实现 HttpSessionListener 接口方法 -->
	<listener>  
		<listener-class>com.it.listeners.SessionListener</listener-class>  
	</listener>

3、编写com.it.listeners.SessionListener

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.it.data.MySessionContext;
import com.it.pojo.User;
import com.it.service.UserServies;

public class SessionListener implements HttpSessionListener {
	private MySessionContext context = MySessionContext.getSessionContext();
	
	@Override
	public void sessionCreated(HttpSessionEvent e) {
		context.addSession(e.getSession());
	}

	@Override
	public void sessionDestroyed(HttpSessionEvent e) {
		User user = (User)e.getSession().getAttribute("user");
		
		//获取service
		UserServies userServies =(UserServies) getObjectFromApplication(e.getSession().getServletContext(),"userServies");
		
		//获取用户的sessionId和用户在线状态
		User tempUser = userServies.selectUserByKey(user.getId());
		
		//如果用户在线且sessionId和e.getSession().getId()相同说明下线,不是更替。
		//则修改用户的在线状态和session设置null。
		if(tempUser.getOnlinestatus() == 1 && e.getSession().getId().equals(tempUser.getSessionid())) {
			tempUser.setOnlinestatus(0);
			tempUser.setSessionid(null);
			userServies.updateByPrimaryKey(tempUser);
		}
		
		context.delSession(e.getSession());		
	}
	
	private Object getObjectFromApplication(ServletContext servletContext,String beanName){  
        //通过WebApplicationContextUtils 得到Spring容器的实例。  
        ApplicationContext application=WebApplicationContextUtils.getWebApplicationContext(servletContext);  
        //返回Bean的实例。  
        return application.getBean(beanName);  
    }
}

4、配置拦截器,在springmvc.xm配置

 

<!--拦截器 -->
 	<mvc:interceptors>
 		<mvc:interceptor>
 			<mvc:mapping path="/**"/>
 			<mvc:exclude-mapping path="/login**"/>
 			<bean class="com.it.interceptor.LoginInterceptor"></bean>
 		</mvc:interceptor>
 	</mvc:interceptors>

5、编写com.it.interceptor.LoginInterceptor,该类实现HandlerInterceptor接口。

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class LoginInterceptor implements HandlerInterceptor{

	Logger logger = LoggerFactory.getLogger(getClass());
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		logger.info("在 登录拦截器。 ");
		HttpSession session = request.getSession();		
		if(session.getAttribute("user") != null) {			
			return true;
		}		
		request.getRequestDispatcher("/WEB-INF/web/login.jsp").forward(request, response);
		return false;
	}
}

6、登录逻辑

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import com.it.constant.RoleConstant;
import com.it.data.MySessionContext;
import com.it.pojo.User;
import com.it.service.UserServies;

@Controller
public class LoginController {
	
	@Autowired
	private UserServies userServies ;
	
	private MySessionContext context = MySessionContext.getSessionContext();
	//处理登录请求
	@PostMapping("/login")
	public String login(HttpServletRequest request, HttpSession session,Model model,@RequestParam(required=true) String id,@RequestParam(required=true)String password) {
		User user = userServies.selectUserByKey(id);
		//密码和id匹配
		if(user != null && password.equals(user.getPassword())) {
			
			session.setAttribute("user",user);
			
			User tempuser = new User();
			tempuser.setOnlinestatus(1);
			tempuser.setSessionid(session.getId());
			tempuser.setId(id);
			userServies.updateByPrimaryKeySelective(tempuser);
			
			//删除上一个登录的session
			if(user.getOnlinestatus() == 1 && user.getSessionid() != null) {
				HttpSession oldSession = context.getSession(user.getSessionid());
				if(oldSession != null)
					oldSession.invalidate();
			}
			
			return "redirect:index";
		}else {
			model.addAttribute("msg", "用户名或密码不正确");
			return "login";
		}
		
	}
	
	//去登陆
	@GetMapping("/login")
	public String login(HttpSession session) {
		if(session.getAttribute("user") != null)
			return "redirect:index";
		return "login";
	}
}


7、user表结构

 

8、还需要解决的问题。session已经清掉了,但是第一个用户需要发送一个业务请求,这时会去登录页面。如果想第二次登录时第一个用户马上给出提示,则需要在前端做一个方法一直请求后台。但是这种做法我不知道合不合理。

 


 




 

 

  • 6
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
这里给出一个使用 Flask 框架和 session 实现的简单登陆页面的示例代码: ```python from flask import Flask, render_template, request, redirect, url_for, session app = Flask(__name__) app.secret_key = 'my-secret-key' # 设置 session 密钥 # 模拟用户数据 users = { 'user1': 'password1', 'user2': 'password2', 'user3': 'password3' } @app.route('/') def index(): if 'username' in session: # 如果用户已经登录,跳转到欢迎页面 return redirect(url_for('welcome')) else: return render_template('login.html') # 否则展示登陆页面 @app.route('/login', methods=['POST']) def login(): username = request.form['username'] password = request.form['password'] if username in users and users[username] == password: # 验证用户信息是否正确 session['username'] = username # 将用户名存入 session return redirect(url_for('welcome')) else: return render_template('login.html', error='用户名或密码错误!') @app.route('/welcome') def welcome(): if 'username' in session: # 如果用户已经登录,展示欢迎页面 return render_template('welcome.html', username=session['username']) else: return redirect(url_for('index')) # 否则跳转到登陆页面 @app.route('/logout') def logout(): session.pop('username', None) # 删除 session 中的用户名 return redirect(url_for('index')) if __name__ == '__main__': app.run(debug=True) ``` 上述代码中,我们首先通过 `app.secret_key` 设置 session 密钥。然后定义了一个 `users` 字典模拟了用户数据。在主页面 `/` 中,如果用户已经登录,就直接跳转到欢迎页面;否则展示登陆页面。在 `/login` 路由中,我们通过 `request.form` 获取用户提交的登陆信息,并验证用户名和密码是否正确。如果正确,将用户名存入 session,并跳转到欢迎页面;否则在登陆页面展示错误提示信息。在 `/welcome` 路由中,如果用户已经登录,就展示欢迎页面,否则跳转到登陆页面。最后,在 `/logout` 路由中,我们通过 `session.pop` 删除 session 中的用户名,并跳转到登陆页面。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值