用java定时器实现记录用户访问页面时间

前阵子工作中遇到同事要记录用户访问网页页面时间的问题,后来仔细思考了一下,写了一个小demo,觉得应该记录下来。
思路:
考虑到用户访问除了正常关闭或离开页面之外还有停电断网的情况,所以最好的办法是用前端定时心跳请求法记录用户访问状态。
1.在前端公共js里设置一个定时器,每隔一段时间(这个可以根据业务自调)定时向后台访问一个url
2.后台设置一个公用map,用来记录每个用户的访问状态,map里记录有每个用户的开始页面访问时间和每个用户离开页面的时间,怎么判断用户离开页面呢,在后台用java写一个定时器,项目启动时同时启用定时器,每隔一段时间(这个可以根据业务自调)扫描map里每个用户的访问时间,用系统当前时间和map里的最后一次访问时间做比对,当超过一定时间(这个可以根据业务自调)时,表明用户已经离开页面,记录下当前用户最后一次访问时间做离开页面的时间,然后map里就有了当前用户的访问时间,离开页面时间.
3.接下来可以计算停留时间保存进数据库,在数据库保存时做累计,或者直接把用户信息保存在数据库(这个根据业务实现怎么样的功能而定).
4.最后remove掉已保存进数据库的那些用户信息。

理论上map里同时存在离开页面的用户和当前访问页面的用户,通过java定时扫描的方式,记录下离开页面的用户信息并移除map里的离线用户。

代码(用SSI框架为例):
1.前端公用js里写一个定时器:

setInterval(function(){
        //要执行的代码 
        var nameText = $(".adminControl").text();
        console.log(nameText.split(",")[1]);
        var paramObj = {};
        paramObj.userName = /*nameText.split(",")[1]*/"开始健";
        //发送请求
        $.ajax({
               type: "POST",
               url: ctx+"/getUserTime.do",
               data: paramObj,
               success: function(data){
                   
               },
               error:function(){
                   
               }
            });
       console.log("定时器已生效");                   
    },5000);

2.controller里声明两个变量。

public class ConfigVersionQueryController extends BaseController{
    
    protected final Log log = LogFactory.getLog(ConfigVersionQueryController.class);
    @Autowired
    private ConfigVersionQueryService service;
    @Autowired
    private ConfigGlobalService globalService;
    @Autowired
    private IModuleLogManager logManager; 
    
    private static Map<String, Object> timeMap = new HashMap<String, Object>();
    private static int value = 0;

}

3.写一个记录用户时间的接口:

/**
     * 记录用户时间
     * @return
     * @throws Exception
     */
    @RequestMapping("/getUserTime.do")
    public void getUserTime(HttpServletRequest request,HttpServletResponse response) throws Exception
    {
        value++;
        String userName = request.getParameter("userName");
        if(null == timeMap.get(userName)){
            //用户开始访问时间
            timeMap.put(userName + "startTime", new Date());
        }
        timeMap.put(userName, new Date());
        
        //System.out.println("用户开始访问时间=" + timeMap.get(userName + "startTime"));
        //System.out.println("用户请求时间=" + timeMap.get(userName));
       // System.out.println(value);
        if(value == 1){
            System.out.println("进来===");
            Timer timer = new Timer();
             timer.schedule(new TimerTask() {
                  public void run() {
                     // server
                      System.out.println("-------设定要指定任务--------");
                      Iterator iter = timeMap.entrySet().iterator();        //获取key和value的set
                      Date time = null;
                      System.out.println("==="+ timeMap.size());
                      Set<String> keySet = new HashSet<String>();
                      while (iter.hasNext()) {
                          Map.Entry entry = (Map.Entry) iter.next();        //把hashmap转成Iterator再迭代到entry
                          String key = entry.getKey().toString();       //从entry获取key
                          if(key.indexOf("startTime") == -1 ){
                              time = (Date) entry.getValue();
                              if(((new Date()).getTime() - time.getTime())/1000 > 9){
                                  keySet.add(key);
                              } 
                          }
                      }
                      for (String key : keySet) {
                          System.out.println(key + "访问页面时间==" + (Date)timeMap.get(key + "startTime"));
                          System.out.println(key +"离开页面时间==" + (Date)timeMap.get(key));
                          //此处省略计入数据库的操作,可以计算停留时间等
                          //保存进数据库之后移除离线用户信息
                          timeMap.remove(key);
                          timeMap.remove(key + "startTime"); 
                       } 
                  }
                }, 15000, 15000);// 设定指定的时间time,此处为15000毫秒
        }
    }

总结:此为实验小demo,实现过程中用userId更好,这里只是为了直观起见用了userName,为了测试方便,前端设定固定请求时间为5秒,当前时间和最后一次记录时间差为9秒,后台定时器每15秒扫描一次,实际项目中这些时间都可以根据业务自调。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容