访问统计功能上线

后端实现想法记录一下:

  • 基本上是利用HttpServletRequest的get系列方法,来获取请求中包含的headers,参数,以及cookie信息,并转化为javabean,json或者写入数据库

方案一:通过Servlet filter实现

  • 结果:pass
  • 原因:无法针对每一个案例页面分别统计。
  • url-pattern的wild匹配模式只支持zhuyu.xyz/*,和*end这两种,我想匹配的真实请求都是zhuyu.xyz/xxxservlet?action=xxx,满足不了。

方案二:应用层增加一个方法M并绑定请求A

  • 请求A保证只与案例页面的访问关联,这样每次访问该页面就会调用方法M,然后M不停的累计、到了一定程度可以把count写库。
  • 结果:pass
  • 原因:既然统计了,就索性将用户访问的关键数据都记录吧,于是数据库增加一张表+javabean老老实实加起来。

方案三:增加数据库表,通过javabean关联,并创建应用层方法。

  • 结果:OK

几个注意的点:

  • 请求数量统一,将查库写库合并到一个请求了
  • 根据cid查询count是比较快的,但是并没有必要每次都写入库。这里设置了一些条件,有相同的访问(不自觉地利用了缓存特性……)就先加到一个Stack集合里,当访问累计达到2或者第二次访问时间差大于60s,就写入(这个判断条件可以根据访问频率来优化,这里也可以通过定时器来处理)
  • mybatis的一级缓存问题。当我自己用浏览器A第一次访问时,发送的请求时是1,此时后端执行的Sqlsession假设为a并进行了缓存,当我再次访问并达到了写入边界进行写库时,按理说写库的Sqlsession应该也是a,那么写库之后涉及到update操作,会自动更新掉LocalCache,第三次访问的时候,返回的count结果应该是最新的,但并不是。
  • 解决办法就是,判断写库操作,如果true,就新建一个CaseCountServiceImp对象,利用它再次查询count并将结果更新,返回前端,并将原有的CaseCountServiceImp对象引用到这个新的对象,相当于避开了查询缓存。
  • 局部代码如下:

    if(addCount(req,resp)){
              //新建一个对象并调用方法,以避开缓存num1
              CaseCountService newCount = new CaseCountServiceImp();
              visitCount = newCount.selectCount(cid);
              //更新引用,以之为新的缓存参数num2,否则还是按照缓存num1进行查询
              caseCountService = newCount;
              System.out.println("更新库后的访问统计数为:"+visitCount);
          }

依旧存在的问题:

  • 重复刷新问题,后续可以在后端增加过滤
  • cookie还有些问题
  • 其实还是没有办法避免机器人

最后贴一篇研究mybatis缓存的文章,写的很清晰:

聊聊MyBatis缓存机制/2018/01/19