用session监听实现唯一登录及普通类调用Service层的方法的实现思路

最近在写项目的时候遇到一个问题:如何实现用户唯一登录?一开始的想法是给t_user表添加一个字段login_status(登录状态),用户登录前去查询t_user的login_status的值,login_status为未登录状态,则可以进行登录;否则,不能登录。但是在用户非正常退出的情况下(即用户未点击“退出”按钮或浏览器非正常关闭),login_status的值一直为登录状态,用户无法进行登录。
解决方案:设置session失效时间,利用session监听,在session销毁的时候去更新login_status的值。
步骤一:在web.xml中添加如下配置:
<!-- session监听 -->
 <listener>  
    <listener-class>cn.tomato.listener.SessionListener</listener-class>  
 </listener>
 <!-- session过期时间设置 -->
 <session-config> 
	 <!-- session过期时间为30分钟 --> 
    <session-timeout>30</session-timeout>  
 </session-config> 
步骤二:创建session监听类
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import cn.tomato.util.SessionFactory;

public class SessionListener implements HttpSessionListener{

	public static SessionFactory sessionFactory=SessionFactory.getInstance();
	
	@Override
    public void sessionCreated(HttpSessionEvent httpSessionEvent) {  
		System.out.println("====================="+"SessionListener's sessionCreated");
        sessionFactory.createSession(httpSessionEvent.getSession());  
    }  
  
	@Override
    public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {  
		System.out.println("====================="+"SessionListener's sessionDestroyed");
        sessionFactory.destroySession(httpSessionEvent.getSession());   
    }  

}

步骤三:创建单例类SessionFactory,管理session的创建及销毁。
import java.util.HashMap;

import javax.servlet.http.HttpSession;


import cn.tomato.domain.User;
import cn.tomato.service.impl.UserServiceImpl;
 
public class SessionFactory{ 
	
	
    private static SessionFactory instance;  
    private HashMap<String,HttpSession> sessionMap;  
   
    private SessionFactory() {  
        sessionMap = new HashMap<String,HttpSession>();  
    }  
  
    public static SessionFactory getInstance() {  
        if (instance == null) {  
            instance = new SessionFactory();  
        }  
        return instance;  
    }  
  
    public synchronized void createSession(HttpSession session) {  
        if (session != null) {  
            sessionMap.put(session.getId(), session);  
            System.out.println("CreateSession's sessionId :"+session.getId());
        }  
    }  
  
    public synchronized void destroySession(HttpSession session) {  
        if (session != null) {
        	if(sessionMap.get(session.getId())!=null){
        		sessionMap.remove(session.getId());
        	}else{
        		User user = (User) session.getAttribute("session_user");
                //排除未登录的情况
                if(user!=null){
                	user.setLoginStatus(User.OUTLOGIN);
                	//普通类调用Service
                	UserServiceImpl userServiceImpl = (UserServiceImpl)SpringBeanFactory.getBean("userServiceImpl");
                	userServiceImpl.updateULoginStatus(user);
                    sessionMap.remove(session.getAttribute(user.getLoginName()),session);   
                }  
        	}
              
            
        }  
    }  
  
    public synchronized HttpSession getSession(String sessionId) {  
        if (sessionId == null) return null;  
        return (HttpSession) sessionMap.get(sessionId);  
    }  
  
    public synchronized HashMap<String, HttpSession> getSessionMap() {  
        return sessionMap;  
    }  
  
    public synchronized void setSessionMap(HashMap<String, HttpSession> sessionMap) {  
        this.sessionMap.putAll(sessionMap);  
    }
    
    public synchronized void removeSessionMap(String sessionId) {  
        this.sessionMap.remove(sessionId);
    }
    
    
  
		
	
}
步骤四:在用户登录及用户退出时更新sessionMap
//登录
	@RequestMapping("/login.action")
	public String login(User user,HttpServletRequest request,RedirectAttributes redirectAttributes)
	{
    	//判断是否存在此用户
		User mUser = userService.findUserByName(user.getLoginName());
    	if(mUser!=null&&user.getPassWord().equals(mUser.getPassWord())&&mUser.getLoginStatus().equals(User.OUTLOGIN))
    	{
    		
    		HttpSession session = request.getSession(false);
			mUser.setLoginStatus(User.ONLOGIN);
			userService.updateULoginStatus(mUser);
    		//创建session对象
			session.setAttribute("session_user",mUser);
			//将服务器ip传给session,后续websocket的url从session中取ip
			session.setAttribute("serverIp",contextData.getServerIp());
			//移除以sessionId为key的值,用userLoginName代替
			sessionFactory.removeSessionMap(session.getId());
			HashMap<String,HttpSession> sessionMap = new HashMap<String,HttpSession>();
			//sessionMap以userLoginName为key,session为value
			sessionMap.put(mUser.getLoginName(),session);
			sessionFactory.setSessionMap(sessionMap);
			//跳转至首页
			System.out.println("------------------------跳转至首页---------------");
			return "redirect:/toIndex"; 
    	}else{
    		if(mUser!=null&&!user.getPassWord().equals(mUser.getPassWord())){
    			redirectAttributes.addFlashAttribute("message", "密码不正确,请核实!");
    		}else if(mUser!=null&&!mUser.getLoginStatus().equals(User.OUTLOGIN)){
    			redirectAttributes.addFlashAttribute("message", "用户已经登录,请核实!");
    		}else if(mUser==null){
    			redirectAttributes.addFlashAttribute("message", "无此用户,请核实!");
    		}else{
    			redirectAttributes.addFlashAttribute("message", "用户名有误,请核实!");
    		}
    			  
			return "redirect:/toLogin";
    	}
	}

//退出
	@RequestMapping("/toQuit")
	public String quit(HttpServletRequest request)
	{
		HttpSession session = request.getSession(false);
		if(session!=null){
			User user = (User) session.getAttribute("session_user");
			if(user!=null){
				HttpSession userSession=(HttpSession)sessionFactory.getSessionMap().get(user.getLoginName());
				if(userSession!= null){
					//注销在线用户  
			        userSession.invalidate();             
			        sessionFactory.getSessionMap().remove(user.getLoginName());  
				}
			}
			
		}
		
        
		return "redirect:/toIndex"; 
    	
	}
总结下上面代码的实现思路:首先一开始创建一个新的session时,调用SessionFactory的createSession方法将以sessionId为key,session为value的map加入sessionMap中。当用户登录时,如果存在session,则将该sessionMap中移除以sessionId为key的值,替换成以userLoginName为key,session为value;退出时,先判断sessionMap中是否存在以sessionId为key的值,有说明用户未登录,在sessionMap直接移除sessionId即可;否则,先判断从session中是否可以取出用户信息,是,则更新数据库,并从sessionMap中移除userLoginName为key,session为value的记录。



通常在项目中,会遇到在普通类中调用Service层的方法,去进行数据库操作,总不能将一个普通类加上@Controller的注解吧!就像上面的代码中SessionFactory的destroySession方法中要更新登录状态。解决方法如下:
步骤一:创建一个工厂类SpringBeanFactory
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringBeanFactory implements ApplicationContextAware {
	
	 private static ApplicationContext context;

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		context = applicationContext;

	}
	
	public static ApplicationContext getApplicationContext() {
	    return context;
	}
	
	 public static Object getBean(String beanName) {
	    return context.getBean(beanName);
	 }

}
步骤二:在Spring的配置文件中配置如下内容
<bean id="springBeanFactory" class="cn.tomato.util.SpringBeanFactory"/>
步骤三:通过SpringBeanFactory的getBean()方法直接获得对应的对象即可。
//普通类调用Service
 UserServiceImpl userServiceImpl = (UserServiceImpl)SpringBeanFactory.getBean("userServiceImpl");
最近在用websocket实现单聊,后台数据写好了,前端不会写,有点尴尬。。。。。

关于我


    可以扫描关注下面的公众号(公众号:猿类进化论)
在这里插入图片描述

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值