1. 程式人生 > >用session監聽實現唯一登入及普通類呼叫Service層的方法的實現思路

用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實現單聊,後臺資料寫好了,前端不會寫,有點尷尬。。。。。