2016.10.12日--利用servlet監(jiān)聽器實(shí)現(xiàn)用戶在線人數(shù)統(tǒng)計(jì)

servlet中監(jiān)聽器主要的監(jiān)聽對(duì)象有三個(gè):
ServletContext HttpSession ServletRequest.
分別可以監(jiān)聽三個(gè)對(duì)象的創(chuàng)建 銷毀躏哩,以及屬性的更改。

=========================================
實(shí)現(xiàn)監(jiān)聽在線人數(shù):

在開始實(shí)現(xiàn)功能之前首先創(chuàng)建一個(gè)用戶模型,為了區(qū)別每個(gè)用戶,我們用sessionId來作為一個(gè)用戶的id囚枪,代碼實(shí)現(xiàn):

package model;

public class User {
    private String ipStr;
    private String address;
    private String sessionId;
    
    public User() {
        super();
        // TODO Auto-generated constructor stub
    }
    
    public String getSessionId() {
        return sessionId;
    }

    public void setSessionId(String sessionId) {
        this.sessionId = sessionId;
    }

    public String getIpStr() {
        return ipStr;
    }
    public void setIpStr(String ipStr) {
        this.ipStr = ipStr;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    
    
}

第一步:創(chuàng)建出存放在線用戶的容器

當(dāng)應(yīng)用服務(wù)一旦啟動(dòng)赊级,就創(chuàng)建出一個(gè)容器來存放在線的人數(shù)。這里使用到ServletContextListener敢辩。實(shí)現(xiàn)這個(gè)接口的監(jiān)聽器將監(jiān)聽到我們的服務(wù)器程序的啟動(dòng)和銷毀。代碼實(shí)現(xiàn):

package listener;

import java.util.ArrayList;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

import model.User;

@WebListener
public class MyServletContextListener implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("===================servlet 服務(wù)銷毀===================");
    }

    @Override
    public void contextInitialized(ServletContextEvent event) {
        ServletContext context = event.getServletContext();
        ArrayList<User> userList = new ArrayList<>();
        context.setAttribute("userList", userList);
        System.out.println("===================servlet 服務(wù)啟動(dòng)===================");
    }

}

把用戶列表存放到servletContext這個(gè)對(duì)象中误褪,這個(gè)對(duì)象的生命周期是整個(gè)服務(wù)程序的生命周期责鳍。

第二步:獲得每個(gè)用戶,并存放到容器中兽间。

在一般的web程序中历葛,用戶一旦登錄,我們會(huì)把用戶的信息存放到session對(duì)象中嘀略。當(dāng)用戶退出登錄時(shí)恤溶,從session對(duì)象中移除我們的用戶信息。為了獲取到用戶的ip地址等詳細(xì)信息帜羊。要用到ServletRequestListener這個(gè)接口咒程。代碼實(shí)現(xiàn):

package listener;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.servlet.ServletContext;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import model.User;


@WebListener
public class MyHttpRequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent event) {
        System.out.println("===================一個(gè)request銷毀===================");
    }

    @Override
    public void requestInitialized(ServletRequestEvent event) {
        System.out.println("===================一個(gè)request創(chuàng)建===================");
        
        HttpServletRequest request = (HttpServletRequest) event.getServletRequest();
        HttpSession session = request.getSession();
        ServletContext app = session.getServletContext();
        ArrayList<User> userList = (ArrayList<User>) app.getAttribute("userList");
        //遍歷用戶列表,如果用戶已經(jīng)存放就不做操作
        for (User user : userList) {
        //這里用sessionID來模擬一個(gè)登陸的用戶讼育,正常應(yīng)該是從session中g(shù)etAttribute 到當(dāng)前登錄的用戶
            if(user.getSessionId().equals(session.getId())){
                return;
            }
        }
        //如果用戶沒有存放到我們的容器中帐姻,就吧這個(gè)用戶存放到容器里面稠集。這里只是模擬生成了一個(gè)用戶。正常應(yīng)該是直接把用戶存放到servletContext 的 userList 這個(gè)容器中就可以了饥瓷。
        User currentUser = new User();
        try {
            currentUser.setIpStr(InetAddress.getLocalHost().getHostAddress());
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        currentUser.setSessionId(session.getId());
        currentUser.setAddress("test");
        URL url = null;
        URLConnection connection = null;
        try {
            url = new URL("http://ip.taobao.com/service/getIpInfo.php?ip="+currentUser.getIpStr());
            connection = url.openConnection();
            connection.setConnectTimeout(2000);// 設(shè)置連接超時(shí)時(shí)間剥纷,單位毫秒  
               connection.setReadTimeout(2000);// 設(shè)置讀取數(shù)據(jù)超時(shí)時(shí)間,單位毫秒  
               connection.setDoOutput(true);// 是否打開輸出流 true|false  
               connection.setDoInput(true);// 是否打開輸入流true|false  
               connection.setUseCaches(false);// 是否緩存true|false  
               connection.connect();// 打開連接端口  
               DataOutputStream out = new DataOutputStream(connection  
                 .getOutputStream());// 打開輸出流往對(duì)端服務(wù)器寫數(shù)據(jù)  
                 
               out.flush();// 刷新  
               out.close();// 關(guān)閉輸出流  
               BufferedReader reader = new BufferedReader(new InputStreamReader(  
                 connection.getInputStream(), "gbk"));// 往對(duì)端寫完數(shù)據(jù)對(duì)端服務(wù)器返回?cái)?shù)據(jù)  
               // ,以BufferedReader流來讀取  
               StringBuffer buffer = new StringBuffer();  
               String line = "";  
               while ((line = reader.readLine()) != null) {  
                buffer.append(line);  
               }  
               reader.close();
               
               currentUser.setAddress(buffer.toString());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        userList.add(currentUser);
        app.setAttribute("userList", userList);
        
    }

}

第三步:當(dāng)用戶退出后呢铆,從容器中移除用戶

這里我們要監(jiān)聽到session的生命周期晦鞋,用到HttpSessionListener這個(gè)接口。如果實(shí)現(xiàn)用戶一段時(shí)間內(nèi)不操作棺克,銷毀session的話要在web.xml中配置session超時(shí):

<session-config> 
    <session-timeout>1</session-timeout>
   </session-config>

HttpSessionListener悠垛,代碼實(shí)現(xiàn):

package listener;

import java.util.ArrayList;

import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import model.User;

@WebListener
public class MyHttpSessionListener implements HttpSessionListener {

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        System.out.println("===================一個(gè)session創(chuàng)建===================");
        
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        
        HttpSession session = event.getSession();
        @SuppressWarnings("unchecked")
        ArrayList<User> userList =(ArrayList<User>) session.getServletContext().getAttribute("userList");
        ArrayList<User> newUserList = new ArrayList<>();
        for (User user : userList) {
            if (! user.getSessionId().equals(session.getId())) {
                newUserList.add(user);
            }
        }
        session.getServletContext().setAttribute("userList", newUserList);
        System.out.println("===================一個(gè)session銷毀===================");
    }

}

至此大概思路已經(jīng)完成。剩下的操作娜谊,按照需求完善确买。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纱皆,隨后出現(xiàn)的幾起案子拇惋,更是在濱河造成了極大的恐慌,老刑警劉巖抹剩,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蓉坎,居然都是意外死亡澳眷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門蛉艾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钳踊,“玉大人,你說我怎么就攤上這事勿侯⊥氐桑” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵助琐,是天一觀的道長(zhǎng)祭埂。 經(jīng)常有香客問我,道長(zhǎng)兵钮,這世上最難降的妖魔是什么蛆橡? 我笑而不...
    開封第一講書人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮掘譬,結(jié)果婚禮上泰演,老公的妹妹穿的比我還像新娘。我一直安慰自己葱轩,他們只是感情好睦焕,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開白布藐握。 她就那樣靜靜地躺著,像睡著了一般垃喊。 火紅的嫁衣襯著肌膚如雪猾普。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評(píng)論 1 299
  • 那天缔御,我揣著相機(jī)與錄音抬闷,去河邊找鬼。 笑死耕突,一個(gè)胖子當(dāng)著我的面吹牛笤成,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播眷茁,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼炕泳,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了上祈?” 一聲冷哼從身側(cè)響起培遵,我...
    開封第一講書人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎登刺,沒想到半個(gè)月后籽腕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纸俭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年皇耗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片揍很。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡郎楼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窒悔,到底是詐尸還是另有隱情呜袁,我是刑警寧澤简珠,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布阶界,位于F島的核電站,受9級(jí)特大地震影響聋庵,放射性物質(zhì)發(fā)生泄漏荐操。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一珍策、第九天 我趴在偏房一處隱蔽的房頂上張望托启。 院中可真熱鬧,春花似錦攘宙、人聲如沸屯耸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疗绣。三九已至线召,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間多矮,已是汗流浹背缓淹。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留塔逃,地道東北人讯壶。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像湾盗,于是被迫代替她去往敵國(guó)和親伏蚊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 監(jiān)聽器(listener) 監(jiān)聽器簡(jiǎn)介 :監(jiān)聽器就是一個(gè)實(shí)現(xiàn)特定接口的普通java程序格粪,這個(gè)程序?qū)iT用于監(jiān)聽另一個(gè)...
    奮斗的老王閱讀 2,507評(píng)論 0 53
  • 本文包括:1躏吊、Listener簡(jiǎn)介2、Servlet監(jiān)聽器3帐萎、監(jiān)聽三個(gè)域?qū)ο髣?chuàng)建和銷毀的事件監(jiān)聽器4比伏、監(jiān)聽三個(gè)域?qū)?..
    廖少少閱讀 6,065評(píng)論 6 28
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司疆导,掛了不少凳怨,但最終還是拿到小米、百度是鬼、阿里、京東紫新、新浪均蜜、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,240評(píng)論 11 349
  • 一、概述 監(jiān)聽器就是一個(gè)實(shí)現(xiàn)特定接口的普通java程序偶芍,這個(gè)程序?qū)iT用于監(jiān)聽另一個(gè)java對(duì)象的方法調(diào)用或?qū)傩愿淖?..
    yjaal閱讀 1,995評(píng)論 0 5
  • 1.棲守道德者充择,寂寞一時(shí);依阿權(quán)勢(shì)者匪蟀,凄涼萬古椎麦。達(dá)人觀物外之物,思身后之身材彪;寧受一時(shí)之寂寞观挎,毋取萬古之凄涼琴儿。 2....
    酸酸121閱讀 505評(píng)論 0 1